first commit

This commit is contained in:
Matthew 2025-02-22 19:29:11 +11:00
commit 7bf35d0031
20 changed files with 22802 additions and 0 deletions

77
build.sh Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash
set -eu
for arg in "$@"; do declare $arg="1"; done
if [ ! -v clang ]; then gcc=1; fi
if [ ! -v release ]; then debug=1; fi
if [ -v debug ]; then echo "[debug mode]"; fi
if [ -v release ]; then echo "[release mode]"; fi
if [ -v gcc ]; then compiler="${CC:-gcc}"; cpp_compiler="g++"; echo "[gcc compiler]"; fi
if [ -v clang ]; then compiler="${CC:-clang}"; cpp_compiler="clang++"; echo "[clang compiler]"; fi
if [ -v vulkan ]; then render_flag="-DSTG_VULKAN_RENDERER"; echo "[vulkan renderer]"; fi
if [ -v opengl ] && [ ! -v render_flag ]; then render_flag="-DSTG_OPENGL_RENDERER"; echo "[opengl renderer]"; fi
if [ -v webgl ] && [ ! -v render_flag ]; then render_flag="-DSTG_WEBGL_RENDERER"; echo "[webgl renderer]"; fi
if [ -v dx11 ] && [ ! -v render_flag ]; then render_flag="-DSTG_DX11_RENDERER"; echo "[dx11 renderer]"; fi
if [ ! -v render_flag ]; then render_flag="-DSTG_VULKAN_RENDERER"; echo "[default renderer - vulkan]"; fi
# for command line build args
auto_compile_flags="${render_flag}"
# source files
source_files="../src/main.c"
# includes
include_flags="-I../src/ -I../external/ -L."
# executable name
out_name="here"
# vma flags
vma_ld="ld -static vma.o `g++ -print-file-name=libstdc++.a` -o vmastdc++.o"
vma_source_files="../external/vma/vma.cpp"
vma_compile_flags="-std=c++20 -I../external/vma"
vma_out="-c -o"
vma_obj="vma.o"
clang_common="${include_flags} -g -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl -l:libvma.a"
clang_out="-o"
gcc_common="${include_flags} -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
gcc_link="-lpthread -lm -lrt -ldl -l:libvma.a"
gcc_out="-o"
link_dll="-fPIC"
link_os_gfx="-lxcb -lvulkan"
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
if [ -v gcc ]; then compile_release="$gcc_release"; fi
if [ -v gcc ]; then compile_link="$gcc_link"; fi
if [ -v gcc ]; then out="$gcc_out"; fi
if [ -v clang ]; then compile_debug="$clang_debug"; fi
if [ -v clang ]; then compile_release="$clang_release"; fi
if [ -v clang ]; then compile_link="$clang_link"; fi
if [ -v clang ]; then out="$clang_out"; fi
if [ -v debug ]; then compile="$compile_debug"; fi
if [ -v release ]; then compile="$compile_release"; fi
mkdir -p build
cd build
if [ ! -f $vma_obj ]; then
$vma_ld
fi
$cpp_compiler $vma_compile_flags $vma_source_files $vma_out $vma_obj
ar rcs libvma.a vmastdc++.o
$compile $source_files $compile_link $link_os_gfx $out $out_name

1906
external/stb/stb_sprintf.h vendored Normal file

File diff suppressed because it is too large Load Diff

19111
external/vma/vk_mem_alloc.h vendored Normal file

File diff suppressed because it is too large Load Diff

5
external/vma/vma.cpp vendored Normal file
View File

@ -0,0 +1,5 @@
#define VMA_IMPLEMENTATION
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#define VMA_VULKAN_VERSION 1003000
#include "vk_mem_alloc.h"

56
src/arena.c Normal file
View File

@ -0,0 +1,56 @@
static Arena *CreateArena(rawptr buffer, isize length)
{
Arena *arena = (Arena *)buffer;
buffer += ARENA_HEADER_SIZE;
arena->buffer = buffer;
arena->length = length;
arena->pos = 0;
return arena;
}
static rawptr ArenaAllocAlign(Arena *arena, isize size, isize align)
{
rawptr ptr;
uintptr curr_ptr = (uintptr)arena->buffer + (uintptr)arena->pos;
uintptr offset = AlignPow2(curr_ptr, align);
offset -= (uintptr)arena->buffer;
if (offset+size <= arena->length)
{
ptr = &arena->buffer[offset];
arena->pos = offset+size;
}
else
{
Printfln("Out of memory: %d", arena->init_line_no);
Assert(0, "Memory Failure");
}
return ptr;
}
static rawptr ArenaAlloc(Arena *arena, isize size)
{
return ArenaAllocAlign(arena, size, DEFAULT_ALIGNMENT);
}
static void ArenaFree(Arena *arena)
{
arena->pos = 0;
}
static void ArenaFreeZeroed(Arena *arena)
{
MemZero(arena->buffer, arena->pos);
ArenaFree(arena);
}
static Arena * CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no)
{
Arena *arena = CreateArena(buffer, length);
arena->init_line_no = init_line_no;
return arena;
}

25
src/arena.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#define ARENA_HEADER_SIZE 64
typedef struct
{
u8 *buffer;
isize length;
isize pos;
u32 init_line_no;
} Arena;
typedef struct
{
Arena *arena;
u64 pos;
} TempArena;
static Arena *CreateArena(rawptr buffer, isize length);
static rawptr ArenaAllocAlign(Arena *arena, isize size, isize align);
static rawptr ArenaAlloc(Arena *arena, isize size);
static void ArenaFree(Arena *arena);
static void ArenaFreeZeroed(Arena *arena);
static Arena *CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no);

26
src/main.c Normal file
View File

@ -0,0 +1,26 @@
#include "main.h"
#include "platform.c"
#include "util.c"
#include "arena.c"
#include "render.c"
int main(int argc, char **argv)
{
InitPlatform();
u8 *mem = (u8 *)MemAllocZeroed(MB(512));
Arena *arena = CreateArenaDebug(mem, MB(512), __LINE__);
isize renderer_mem_size = MB(8);
rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size);
Arena *renderer_arena = CreateArenaDebug(renderer_mem, MB(8), __LINE__);
Assert(CreateWindow(), "Failed to initialize the window");
Assert(InitRenderer(renderer_arena), "Failed to initialize the renderer");
DestroyRenderer();
return 0;
}

16
src/main.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#define STB_SPRINTF_IMPLEMENTATION
#define WINDOW_NAME "Video Game"
#include <stdio.h>
#include "stb/stb_sprintf.h"
#include "platform.h"
#include "util.h"
#include "arena.h"
#include "render.h"
int main(int argc, char **argv);

93
src/platform.c Normal file
View File

@ -0,0 +1,93 @@
#if __linux__
#include "platform_linux.c"
#endif
#if _WIN32
#error Not yet implemented
#endif
#if __APPLE__ || __MACH__
#error Not yet implemented
#endif
#if __unix__ && !__linux__
#error Not yet implemented
#endif
b32 LoadLib(const char *name, Library *out_lib)
{
return _LoadLib(name, out_lib);
}
b32 LoadFn(const char *name, Library *lib, Function *out_fn)
{
return _LoadFn(name, lib, out_fn);
}
b32 InitPlatform()
{
return _InitPlatform();
}
rawptr MemAlloc(isize size)
{
return _MemAlloc(size);
}
rawptr MemAllocZeroed(isize size)
{
return _MemAllocZeroed(size);
}
isize GetPageSize()
{
return _GetPageSize();
}
i32 EPrint(void const *str)
{
return _EPrint(str);
}
i32 Printf(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
i32 result = _Printf(fmt, arg);
va_end(arg);
return result;
}
i32 Printfln(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
i32 result = _Printfln(fmt, arg);
va_end(arg);
return result;
}
i32 EPrintf(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
i32 result = _EPrintf(fmt, arg);
va_end(arg);
return result;
}
b32 CreateWindow()
{
return _CreateWindow();
}
Window *GetWindow()
{
return _GetWindow();
}

37
src/platform.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#if __linux__
#include "platform_linux.h"
#endif
#if _WIN32
#error Not yet implemented
#endif
#if __APPLE__ || __MACH__
#error Not yet implemented
#endif
#if __unix__ && !__linux__
#error Not yet implemented
#endif
// Init
b32 LoadLib(const char *name, Library *out_lib);
b32 LoadFn(const char *name, Library *lib, Function *out_fn);
b32 InitPlatform();
// Memory Functions
rawptr MemAlloc(isize size);
rawptr MemAllocZeroed(isize size);
isize GetPageSize();
// Print Functions
i32 EPrint(void const *str);
i32 Printf(const char *fmt, ...);
i32 Printfln(const char *fmt, ...);
i32 EPrintf(const char *fmt, ...);
// Window Functions
b32 CreateWindow();
Window *GetWindow();

230
src/platform_linux.c Normal file
View File

@ -0,0 +1,230 @@
// TODO(MA): Do stuff for general unix platforms some day
static Window linux_window = {
.w = 1920,
.h = 1080,
};
// Init
b32 _LoadLib(const char *name, Library *out_lib)
{
if (!name) {
return false;
}
out_lib->lib = dlopen(name, RTLD_NOW);
if (!out_lib->lib) {
return false;
}
return true;
}
b32 _LoadFn(const char *name, Library *lib, Function *out_fn)
{
if (!name) {
return false;
}
out_fn->fn = dlsym(lib->lib, name);
if (!out_fn->fn) {
Printf("unable to find function\n");
return false;
}
return true;
}
b32 _InitPlatform()
{
return true;
}
// Init End
// General Utils
b32 CheckSyscallErr(void *ptr)
{
return (isize)ptr == SYS_ERR ? true : false;
}
// General Utils End
i32 Write(int fd, void const *str, isize count)
{
i32 result = (i32)write(fd, str, count);
return result;
}
i32 _EPrint(void const *str)
{
return Write(_STDERR, str, (isize)StrLen(str));
}
i32 _EPrintf(const char *fmt, va_list arg)
{
char buffer[1024];
int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);
if (sprf_res < 0) return sprf_res;
i32 pr_res = EPrint(&buffer);
return pr_res;
}
i32 _Printf(const char *fmt, va_list arg)
{
char buffer[1024];
int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);
i32 pr_res;
if (sprf_res < 0)
pr_res = sprf_res;
else
pr_res = Write(_STDOUT, &buffer, sprf_res);
return pr_res;
}
i32 _Printfln(const char *fmt, va_list arg)
{
char buffer[1024];
int sprf_res = stbsp_vsnprintf(&buffer[0], 1023, fmt, arg);
i32 pr_res;
if (sprf_res < 0)
{
pr_res = sprf_res;
}
else
{
buffer[sprf_res] = '\n';
buffer[sprf_res+1] = '\0';
pr_res = Write(_STDOUT, &buffer, sprf_res+1);
}
return pr_res;
}
rawptr _MemAlloc(isize size)
{
void *addr = mmap(
NULL,
size,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE,
-1,
0
);
if (CheckSyscallErr(addr)) addr = NULL;
return addr;
}
rawptr _MemAllocZeroed(isize size)
{
rawptr ptr = MemAlloc(size);
MemZero(ptr, size);
return ptr;
}
isize _GetPageSize()
{
return (isize)sysconf(_SC_PAGESIZE);
}
b32 _CreateWindow()
{
Window *window = &linux_window;
window->connection = xcb_connect(NULL, NULL);
if (!window->connection) {
return false;
}
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
const xcb_setup_t *setup = xcb_get_setup(window->connection);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
xcb_screen_t *screen = iter.data;
const int event_mask = XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_KEY_PRESS |
XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_MOTION |
XCB_EVENT_MASK_STRUCTURE_NOTIFY|
XCB_EVENT_MASK_RESIZE_REDIRECT;
const int val_win[] = {event_mask, 0};
const int val_mask = XCB_CW_EVENT_MASK;
window->window = xcb_generate_id(window->connection);
cookie = xcb_create_window_checked(
window->connection,
XCB_COPY_FROM_PARENT,
window->window,
screen->root,
0, 0, // x/y pos
window->w, window->h,
10,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
val_mask,
val_win
);
XCB_CHECK_ERROR(window, cookie, error, "Failed to create window.");
cookie = xcb_map_window_checked(window->connection, window->window);
XCB_CHECK_ERROR(window, cookie, error, "Failed to map window.");
cookie = xcb_change_property_checked(
window->connection,
XCB_PROP_MODE_REPLACE,
window->window,
XCB_ATOM_WM_NAME,
XCB_ATOM_STRING,
8,
StrLen(WINDOW_NAME),
WINDOW_NAME
);
XCB_CHECK_ERROR(window, cookie, error, "Failed to rename window.");
xcb_intern_atom_cookie_t c_proto = xcb_intern_atom(window->connection, 1, 12, "WM_PROTOCOLS");
xcb_intern_atom_reply_t *r_proto = xcb_intern_atom_reply(window->connection, c_proto, &error);
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_PROTOCOLS.");
xcb_intern_atom_cookie_t c_close = xcb_intern_atom(window->connection, 0, 16, "WM_DELETE_WINDOW");
xcb_intern_atom_reply_t *r_close = xcb_intern_atom_reply(window->connection, c_close, &error);
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_DELETE_WINDOW.");
cookie = xcb_change_property_checked(
window->connection,
XCB_PROP_MODE_REPLACE,
window->window,
r_proto->atom,
XCB_ATOM_ATOM,
32,
1,
&r_close->atom
);
XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event.");
window->close_event = r_close->atom;
return true;
}
Window *_GetWindow() {
return &linux_window;
}

115
src/platform_linux.h Normal file
View File

@ -0,0 +1,115 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <xcb/xcb.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <dlfcn.h>
#define Assert(condition, message) do { assert(condition && message); } while(0)
// generic defines
#define KB(n) n * 1024LL
#define MB(n) KB(n) * 1024LL
#define GB(n) MB(n) * 1024LL
#define TB(n) GB(n) * 1024LL
// syscall defines
#define SYS_ERR -1
// syscall write defines
#define _STDIN 0
#define _STDOUT 1
#define _STDERR 2
// xcb defines
#define XCB_CHECK_CURRENT_ERROR(window, error, message) do { \
error = xcb_request_check(window->connection, cookie); \
if (error != NULL) { \
EPrintf("%s ERROR CODE: %d\n", message, error->error_code); \
free(error); \
return false; \
} \
} while (0)
#define XCB_CHECK_ERROR(window, cookie, error, message) do { \
error = xcb_request_check(window->connection, cookie); \
XCB_CHECK_CURRENT_ERROR(window, error, message); \
} while (0)
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef intptr_t intptr;
typedef uintptr_t uintptr;
typedef ssize_t isize;
typedef size_t usize;
typedef float f32;
typedef double f64;
typedef uint32_t b32;
typedef void * rawptr;
typedef struct {
xcb_connection_t *connection;
xcb_window_t window;
xcb_atom_t close_event;
u16 w, h;
} Window;
typedef struct {
void *lib;
} Library;
typedef struct {
void *fn;
} Function;
// Platform API
// Init Functions
b32 _LoadLib(const char *name, Library *out_lib);
b32 _LoadFn(const char *name, Library *lib, Function *out_fn);
b32 _InitPlatform();
// Memory Functions
rawptr _MemAlloc(isize size);
rawptr _MemAllocZeroed(isize size);
isize _GetPageSize();
// Print Functions
i32 _EPrint(void const *str);
i32 _Printf(const char *fmt, va_list arg);
i32 _Printfln(const char *fmt, va_list arg);
i32 _EPrintf(const char *fmt, va_list arg);
// Window Functions
b32 _CreateWindow();
Window *_GetWindow();
// Platform API END
// General Utils
b32 CheckSyscallErr(void *ptr);
// Write Utils
i32 Write(int fd, void const *str, isize count);

24
src/render.c Normal file
View File

@ -0,0 +1,24 @@
#if STG_VULKAN_RENDERER
#include "render_vulkan.c"
#endif
#if STG_OPENGL_RENDERER
#error Not yet implemented
#endif
#if STG_WEBGL_RENDERER
#error Not yet implemented
#endif
#if STG_DX11_RENDERER
#error Not yet implemented
#endif
b32 InitRenderer(Arena *arena) {
return _InitRenderer(arena);
}
void DestroyRenderer() {
_DestroyRenderer();
}

21
src/render.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#if STG_VULKAN_RENDERER
#include "render_vulkan.h"
#endif
#if STG_OPENGL_RENDERER
#error Not yet implemented
#endif
#if STG_WEBGL_RENDERER
#error Not yet implemented
#endif
#if STG_DX11_RENDERER
#error Not yet implemented
#endif
b32 InitRenderer(Arena *arena);
void DestroyRenderer();

571
src/render_vulkan.c Normal file
View File

@ -0,0 +1,571 @@
/**
* BACK END API
*/
// TODO(MA): Make separate functions for debug/non debug builds for readability
b32 _InitRenderer(Arena *arena)
{
Assert(InitVulkan(arena), "InitVkLib failure");
ArenaFree(arena);
return true;
}
void _DestroyRenderer()
{
DestroyVulkan();
}
/**
* BACK END API END
*/
/**
* INTERNAL API
*/
static b32 InitVulkan(Arena *arena)
{
Assert(arena != NULL, "Vulkan memory is null");
renderer.arena = arena;
Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions");
Assert(vkCreateInstance(&inst_info, NULL, &renderer.vk.inst) == VK_SUCCESS, "Error initializing instance");
Assert(InitVkInstanceFunctions(), "Unable to initialize instance functions");
#ifdef BUILD_DEBUG
{
Assert(VLayersSupported(), "DEBUG_BUILD ERROR: Validation layers are not supported");
Assert(vkCreateDebugUtilsMessengerEXT(renderer.vk.inst, &debug_msg_info, NULL, &renderer.vk.debug) == VK_SUCCESS,
"Unable to initialize debug messenger");
}
#endif
Assert(CreateSurface(), "Unable to create surface");
Assert(CreateDevice(), "Unable to create device");
Assert(CreateVmaAllocator(), "Unable to create VMA allocator");
Assert(CreateFrameStructures(), "Unable to create frame structures");
Assert(CreateImmediateStructures(), "Unable to create immediate structures");
return true;
}
static b32 CreateVmaAllocator()
{
VmaVulkanFunctions vk_functions = {
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
};
vma_create_info.pVulkanFunctions = &vk_functions;
vma_create_info.physicalDevice = renderer.vk.phys_device;
vma_create_info.device = renderer.vk.device;
vma_create_info.instance = renderer.vk.inst;
VkResult result = vmaCreateAllocator(&vma_create_info, &renderer.vk.alloc);
if (result != VK_SUCCESS)
{
Printf("vmaCreateAllocator failure: %d", result);
}
return result == VK_SUCCESS;
}
static b32 CheckQueueSurfaceSupport(i32 index, VkPhysicalDevice device, VkSurfaceKHR surface)
{
b32 surface_supported;
vkGetPhysicalDeviceSurfaceSupportKHR(device, (u32)index, surface, &surface_supported);
return surface_supported;
}
static DeviceQueues CheckDeviceQueueSupport(VkPhysicalDevice device, VkSurfaceKHR surface)
{
DeviceQueues queues = { .graphics = -1, .transfer = -1 };
u32 queue_count;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, NULL);
VkQueueFamilyProperties *families = ArenaAlloc(renderer.arena, sizeof(VkQueueFamilyProperties) * queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, &families[0]);
for (i32 i = 0; i < queue_count; i++)
{
if (i == 0 && CheckQueueSurfaceSupport(i, device, surface))
{
queues.graphics = i;
continue;
}
if (BitEq(families[i].queueFlags, VK_QUEUE_TRANSFER_BIT))
queues.transfer = i;
}
if (queues.transfer < 0)
queues.transfer = queues.graphics;
return queues;
}
static b32 CheckDevicePropertiesSupport(VkPhysicalDevice device, VkSurfaceKHR surface, b32 *discrete)
{
b32 success = false;
VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(device, &properties);
if (VK_API_VERSION_MINOR(properties.apiVersion) >= 3)
{
u32 ext_count;
vkEnumerateDeviceExtensionProperties(device, NULL, &ext_count, NULL);
VkExtensionProperties *ext_properties = ArenaAlloc(renderer.arena, sizeof(VkExtensionProperties) * ext_count);
vkEnumerateDeviceExtensionProperties(device, NULL, &ext_count, &ext_properties[0]);
i32 matched = 0;
for (u32 i = 0; i < ext_count; i++) {
for (i32 j = 0; j < Len(device_extensions); j++) {
if (StrEq(ext_properties[i].extensionName, device_extensions[j])) {
matched++;
break;
}
}
}
if (matched == Len(device_extensions))
{
u32 fmt_count, present_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &fmt_count, NULL);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count, NULL);
*discrete = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
success = fmt_count && present_count;
}
}
return success;
}
static b32 CheckDeviceFeatureSupport(VkPhysicalDevice device)
{
VkPhysicalDeviceFeatures2 features2 = { .sType = STYPE(PHYSICAL_DEVICE_FEATURES_2) };
VkPhysicalDeviceVulkan12Features features_12 = { .sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) };
VkPhysicalDeviceVulkan13Features features_13 = { .sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_3_FEATURES) };
features2.pNext = &features_12;
vkGetPhysicalDeviceFeatures2(device, &features2);
features2.pNext = &features_13;
vkGetPhysicalDeviceFeatures2(device, &features2);
VkPhysicalDeviceFeatures features = features2.features;
b32 result = true;
result &= (b32)features.shaderUniformBufferArrayDynamicIndexing;
result &= (b32)features.shaderSampledImageArrayDynamicIndexing;
result &= (b32)features.shaderStorageBufferArrayDynamicIndexing;
result &= (b32)features.shaderStorageImageArrayDynamicIndexing;
result &= (b32)features_12.descriptorIndexing;
result &= (b32)features_12.bufferDeviceAddress;
result &= (b32)features_13.synchronization2;
result &= (b32)features_13.dynamicRendering;
return result;
}
static b32 CreateDevice()
{
VkInstance inst = renderer.vk.inst;
VkSurfaceKHR surface = renderer.vk.surface;
u32 device_count;
vkEnumeratePhysicalDevices(inst, &device_count, NULL);
VkPhysicalDevice *devices = ArenaAlloc(renderer.arena, sizeof(VkPhysicalDevice) * device_count);
vkEnumeratePhysicalDevices(inst, &device_count, &devices[0]);
b32 discrete_device = false;
DeviceQueues *queues = &renderer.vk.queues;
VkPhysicalDevice *phys_device = &renderer.vk.phys_device;
for (u32 i = 0; i < device_count; i++) {
DeviceQueues current_queues = CheckDeviceQueueSupport(devices[i], surface);
b32 discrete = false;
if (current_queues.graphics < 0)
continue;
if (!CheckDevicePropertiesSupport(devices[i], surface, &discrete))
continue;
if (discrete_device && !discrete)
continue;
if (!CheckDeviceFeatureSupport(devices[i]))
continue;
discrete_device = discrete;
*queues = current_queues;
*phys_device = devices[i];
if (discrete_device && queues->graphics != queues->transfer)
break;
}
b32 success = false;
if (phys_device != NULL)
{
VkDeviceQueueCreateInfo queue_info[2] = {};
f32 priority = 1.0f;
u32 count = 1;
queue_info[0].sType = STYPE(DEVICE_QUEUE_CREATE_INFO);
queue_info[0].queueFamilyIndex = queues->graphics;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = &priority;
queue_info[0].flags = 0;
if (queues->graphics != queues->transfer) {
queue_info[1].sType = STYPE(DEVICE_QUEUE_CREATE_INFO);
queue_info[1].queueFamilyIndex = queues->transfer;
queue_info[1].queueCount = 1;
queue_info[1].pQueuePriorities = &priority;
queue_info[1].flags = 0;
count++;
}
device_info.queueCreateInfoCount = count;
device_info.pQueueCreateInfos = &queue_info[0];
VkResult result = vkCreateDevice(renderer.vk.phys_device, &device_info, NULL, &renderer.vk.device);
if (result != VK_SUCCESS) {
Printf("vkCreateDevice failure: %d", result);
}
else
{
Assert(InitVkDeviceFunctions(), "Failed to initialize device functions");
vkGetDeviceQueue(renderer.vk.device, queues->graphics, 0, &queues->graphics_queue);
vkGetDeviceQueue(renderer.vk.device, queues->transfer, 0, &queues->transfer_queue);
success = true;
}
}
return success;
}
static b32 InitVkGlobalFunctions()
{
b32 result = LoadVulkanLib();
if (result)
{
INIT_FN(vkGetInstanceProcAddr);
INIT_FN(vkEnumerateInstanceLayerProperties);
INIT_FN(vkCreateInstance);
}
return result;
}
static b32 InitVkInstanceFunctions()
{
VkInstance instance = renderer.vk.inst;
#ifdef __linux__
{
INIT_INST_FN(vkCreateXcbSurfaceKHR);
}
#endif
#ifdef BUILD_DEBUG
{
INIT_INST_FN(vkCreateDebugUtilsMessengerEXT);
INIT_INST_FN(vkDestroyDebugUtilsMessengerEXT);
}
#endif
INIT_INST_FN(vkEnumeratePhysicalDevices);
INIT_INST_FN(vkGetPhysicalDeviceQueueFamilyProperties);
INIT_INST_FN(vkGetPhysicalDeviceSurfaceSupportKHR);
INIT_INST_FN(vkCreateDevice);
INIT_INST_FN(vkGetPhysicalDeviceProperties);
INIT_INST_FN(vkGetPhysicalDeviceFeatures2);
INIT_INST_FN(vkGetPhysicalDeviceSurfaceFormatsKHR);
INIT_INST_FN(vkGetPhysicalDeviceSurfacePresentModesKHR);
INIT_INST_FN(vkEnumerateDeviceExtensionProperties);
INIT_INST_FN(vkGetDeviceProcAddr);
INIT_INST_FN(vkDestroyInstance);
INIT_INST_FN(vkDestroySurfaceKHR);
return true;
}
static b32 InitVkDeviceFunctions() {
VkDevice device = renderer.vk.device;
INIT_DEV_FN(vkCreateSwapchainKHR);
INIT_DEV_FN(vkCreateImage);
INIT_DEV_FN(vkCreateImageView);
INIT_DEV_FN(vkGetSwapchainImagesKHR);
INIT_DEV_FN(vkGetDeviceQueue);
INIT_DEV_FN(vkCreateSemaphore);
INIT_DEV_FN(vkAllocateCommandBuffers);
INIT_DEV_FN(vkCreateCommandPool);
INIT_DEV_FN(vkCreateFence);
INIT_DEV_FN(vkCreateDescriptorPool);
INIT_DEV_FN(vkCreateDescriptorSetLayout);
INIT_DEV_FN(vkAllocateDescriptorSets);
INIT_DEV_FN(vkCreatePipelineLayout);
INIT_DEV_FN(vkResetDescriptorPool);
INIT_DEV_FN(vkCreateShaderModule);
INIT_DEV_FN(vkCreateGraphicsPipelines);
INIT_DEV_FN(vkCreateComputePipelines);
INIT_DEV_FN(vkUpdateDescriptorSets);
INIT_DEV_FN(vkDestroyDevice);
INIT_DEV_FN(vkDestroyDescriptorPool);
INIT_DEV_FN(vkDestroySwapchainKHR);
INIT_DEV_FN(vkDestroyImage);
INIT_DEV_FN(vkDestroyImageView);
INIT_DEV_FN(vkDestroyCommandPool);
INIT_DEV_FN(vkDestroySemaphore);
INIT_DEV_FN(vkDestroyFence);
INIT_DEV_FN(vkDestroyPipelineLayout);
INIT_DEV_FN(vkDestroyPipeline);
INIT_DEV_FN(vkWaitForFences);
INIT_DEV_FN(vkBeginCommandBuffer);
INIT_DEV_FN(vkEndCommandBuffer);
INIT_DEV_FN(vkAcquireNextImageKHR);
INIT_DEV_FN(vkCmdBindPipeline);
INIT_DEV_FN(vkCmdBindDescriptorSets);
INIT_DEV_FN(vkCmdDispatch);
INIT_DEV_FN(vkCmdBeginRendering);
INIT_DEV_FN(vkCmdEndRendering);
INIT_DEV_FN(vkCmdSetViewport);
INIT_DEV_FN(vkCmdSetScissor);
INIT_DEV_FN(vkCmdPushConstants);
INIT_DEV_FN(vkCmdBindIndexBuffer);
INIT_DEV_FN(vkCmdDrawIndexed);
INIT_DEV_FN(vkCmdBlitImage2);
INIT_DEV_FN(vkCmdPipelineBarrier2);
INIT_DEV_FN(vkCmdCopyBufferToImage);
INIT_DEV_FN(vkCmdCopyBuffer);
INIT_DEV_FN(vkQueueSubmit2);
INIT_DEV_FN(vkResetFences);
INIT_DEV_FN(vkResetCommandBuffer);
INIT_DEV_FN(vkFreeCommandBuffers);
return true;
}
// TODO(MA): implement other platforms
#ifdef __linux__
static b32 CreateSurface()
{
Window *window = GetWindow();
VkXcbSurfaceCreateInfoKHR surface_info = {
.sType = STYPE(XCB_SURFACE_CREATE_INFO_KHR),
.connection = window->connection,
.window = window->window
};
VkResult result = vkCreateXcbSurfaceKHR(renderer.vk.inst, &surface_info, NULL, &renderer.vk.surface);
if (result != VK_SUCCESS) {
Printf("Unable to create surface: %d", result);
}
return result == VK_SUCCESS;
}
#endif
static b32 LoadVulkanLib()
{
Library *lib = &renderer.vk.lib;
b32 lib_found; Function fn;
for (i32 i = 0; i < Len(vulkan_libs); i++) {
lib_found = LoadLib(vulkan_libs[i], lib);
if (lib_found) {
lib_found = LoadFn("vkGetInstanceProcAddr", lib, &fn);
vkGetInstanceProcAddr = fn.fn;
break;
}
}
return lib_found;
}
static b32 VLayersSupported()
{
b32 success;
u32 count;
vkEnumerateInstanceLayerProperties(&count, NULL);
Assert(count, "VLayersSupported(): vkEnumerateInstanceLayerProperties returned a count of 0");
VkLayerProperties *layers = ArenaAlloc(renderer.arena, sizeof(VkLayerProperties) * count);
vkEnumerateInstanceLayerProperties(&count, layers);
for (u32 i = 0; i < count; i++) {
if (StrEq(layers[i].layerName, _VK_VALIDATION)) {
success = true;
break;
}
}
return success;
}
static b32 CreateFrameStructures()
{
b32 success = true;
FrameStructures *data = &renderer.vk.frame;
pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics;
for (u32 i = 0; i < FRAME_OVERLAP; i++)
{
VkResult result;
VkDevice device = renderer.vk.device;
result = vkCreateCommandPool(device, &pool_create_info, NULL, &data->pools[i]);
if (result != VK_SUCCESS)
success = false;
cmd_buf_info.commandPool = data->pools[i];
result = vkAllocateCommandBuffers(device, &cmd_buf_info, &data->buffers[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &data->render_fences[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateSemaphore(device, &semaphore_create_info, NULL, &data->render_sems[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateSemaphore(device, &semaphore_create_info, NULL, &data->swapchain_sems[i]);
if (result != VK_SUCCESS)
success = false;
}
return success;
}
static b32 CreateImmediateStructures()
{
b32 success = true;
VkResult result;
VkDevice device = renderer.vk.device;
ImmediateStructures *imm = &renderer.vk.imm;
pool_create_info.queueFamilyIndex = renderer.vk.queues.transfer;
result = vkCreateCommandPool(device, &pool_create_info, NULL, &imm->pool);
if (result != VK_SUCCESS)
success = false;
cmd_buf_info.commandPool = imm->pool;
result = vkAllocateCommandBuffers(device, &cmd_buf_info, &imm->buffer);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &imm->fence);
if (result != VK_SUCCESS)
success = false;
return success;
}
static b32 CreateSwapchain()
{
b32 success = true;
VkSurfaceCapabilitiesKHR capabilities;
return success;
}
static void DestroyVulkan()
{
VkDevice device = renderer.vk.device;
VkInstance instance = renderer.vk.inst;
FrameStructures data = renderer.vk.frame;
ImmediateStructures imm = renderer.vk.imm;
vkDestroyFence(device, imm.fence, NULL);
vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer);
vkDestroyCommandPool(device, imm.pool, NULL);
for (u32 i = 0; i < FRAME_OVERLAP; i++)
{
vkDestroySemaphore(device, data.render_sems[i], NULL);
vkDestroySemaphore(device, data.swapchain_sems[i], NULL);
vkDestroyFence(device, data.render_fences[i], NULL);
vkFreeCommandBuffers(device, data.pools[i], 1, &data.buffers[i]);
vkDestroyCommandPool(device, data.pools[i], NULL);
}
vmaDestroyAllocator(renderer.vk.alloc);
vkDestroyDevice(renderer.vk.device, NULL);
vkDestroySurfaceKHR(renderer.vk.inst, renderer.vk.surface, NULL);
#ifdef BUILD_DEBUG
{
vkDestroyDebugUtilsMessengerEXT(renderer.vk.inst, renderer.vk.debug, NULL);
}
#endif
vkDestroyInstance(renderer.vk.inst, NULL);
}
static VkBool32 DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
VkDebugUtilsMessageTypeFlagsEXT message_type,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData
) {
char *ms, *mt;
switch (message_severity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
ms = (char *)"VERBOSE";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
ms = (char *)"INFO";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
ms = (char *)"WARNING";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
ms = (char *)"ERROR";
break;
default:
ms = (char *)"UNKNOWN";
break;
}
switch (message_type) {
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"General";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
mt = (char *)"Validation";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"Validation | General";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"General | Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
mt = (char *)"Validation | Performance";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
mt = (char *)"General | Validation | Performance";
break;
default:
mt = (char *)"Unknown";
break;
}
Printf("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
return VK_FALSE;
}

227
src/render_vulkan.h Normal file
View File

@ -0,0 +1,227 @@
#pragma once
#define VK_USE_PLATFORM_XCB_KHR
#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>
// Macros
#define VK_DECLARE(fn) static PFN_##fn fn = NULL
#define STYPE(type) VK_STRUCTURE_TYPE_ ## type
#define INIT_FN(name) do { \
name = (PFN_##name)vkGetInstanceProcAddr(NULL, MakeString(name)); \
if (!name) return false; \
} while (0)
#define INIT_INST_FN(name) do { \
name = (PFN_##name)vkGetInstanceProcAddr(instance, MakeString(name)); \
if (!name) return false; \
} while (0)
#define INIT_DEV_FN(name) do { \
name = (PFN_##name)vkGetDeviceProcAddr(device, MakeString(name)); \
if (!name) return false; \
} while (0)
#define FRAME_OVERLAP 2
// Macros END
// Vulkan Functions
// Global
VK_DECLARE(vkGetInstanceProcAddr);
VK_DECLARE(vkCreateInstance);
VK_DECLARE(vkEnumerateInstanceLayerProperties);
// Instance
VK_DECLARE(vkEnumeratePhysicalDevices);
VK_DECLARE(vkCreateDevice);
VK_DECLARE(vkGetPhysicalDeviceQueueFamilyProperties);
VK_DECLARE(vkGetPhysicalDeviceSurfaceSupportKHR);
VK_DECLARE(vkGetPhysicalDeviceProperties);
VK_DECLARE(vkGetPhysicalDeviceFeatures2);
VK_DECLARE(vkEnumerateDeviceExtensionProperties);
VK_DECLARE(vkGetPhysicalDeviceSurfacePresentModesKHR);
VK_DECLARE(vkGetPhysicalDeviceSurfaceFormatsKHR);
VK_DECLARE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
#ifdef __linux__
VK_DECLARE(vkCreateXcbSurfaceKHR);
#endif
#ifdef BUILD_DEBUG
VK_DECLARE(vkCreateDebugUtilsMessengerEXT);
VK_DECLARE(vkDestroyDebugUtilsMessengerEXT);
#endif
// Device
VK_DECLARE(vkGetDeviceProcAddr);
VK_DECLARE(vkCreateSwapchainKHR);
VK_DECLARE(vkCreateImage);
VK_DECLARE(vkCreateImageView);
VK_DECLARE(vkGetSwapchainImagesKHR);
VK_DECLARE(vkGetDeviceQueue);
VK_DECLARE(vkCreateSemaphore);
VK_DECLARE(vkAllocateCommandBuffers);
VK_DECLARE(vkCreateCommandPool);
VK_DECLARE(vkCreateFence);
VK_DECLARE(vkCreateDescriptorPool);
VK_DECLARE(vkCreateDescriptorSetLayout);
VK_DECLARE(vkAllocateDescriptorSets);
VK_DECLARE(vkCreatePipelineLayout);
VK_DECLARE(vkResetDescriptorPool);
VK_DECLARE(vkCreateShaderModule);
VK_DECLARE(vkCreateGraphicsPipelines);
VK_DECLARE(vkCreateComputePipelines);
VK_DECLARE(vkUpdateDescriptorSets);
VK_DECLARE(vkDestroyDevice);
VK_DECLARE(vkDestroyInstance);
VK_DECLARE(vkDestroySurfaceKHR);
VK_DECLARE(vkDestroyDescriptorPool);
VK_DECLARE(vkDestroySwapchainKHR);
VK_DECLARE(vkDestroyImage);
VK_DECLARE(vkDestroyImageView);
VK_DECLARE(vkDestroyCommandPool);
VK_DECLARE(vkDestroySemaphore);
VK_DECLARE(vkDestroyFence);
VK_DECLARE(vkDestroyPipelineLayout);
VK_DECLARE(vkDestroyPipeline);
VK_DECLARE(vkWaitForFences);
VK_DECLARE(vkBeginCommandBuffer);
VK_DECLARE(vkEndCommandBuffer);
VK_DECLARE(vkAcquireNextImageKHR);
VK_DECLARE(vkCmdBindPipeline);
VK_DECLARE(vkCmdBindDescriptorSets);
VK_DECLARE(vkCmdDispatch);
VK_DECLARE(vkCmdBeginRendering);
VK_DECLARE(vkCmdEndRendering);
VK_DECLARE(vkCmdSetViewport);
VK_DECLARE(vkCmdSetScissor);
VK_DECLARE(vkCmdPushConstants);
VK_DECLARE(vkCmdBindIndexBuffer);
VK_DECLARE(vkCmdDrawIndexed);
VK_DECLARE(vkCmdBlitImage2);
VK_DECLARE(vkCmdPipelineBarrier2);
VK_DECLARE(vkCmdCopyBufferToImage);
VK_DECLARE(vkCmdCopyBuffer);
VK_DECLARE(vkQueueSubmit2);
VK_DECLARE(vkResetFences);
VK_DECLARE(vkResetCommandBuffer);
VK_DECLARE(vkFreeCommandBuffers);
// Vulkan Functions END
#include "vma/vk_mem_alloc.h"
// Types
typedef struct {
VkCommandPool pools[FRAME_OVERLAP];
VkCommandBuffer buffers[FRAME_OVERLAP];
VkSemaphore swapchain_sems[FRAME_OVERLAP];
VkSemaphore render_sems[FRAME_OVERLAP];
VkFence render_fences[FRAME_OVERLAP];
} FrameStructures;
typedef struct {
VkCommandPool pool;
VkCommandBuffer buffer;
VkFence fence;
} ImmediateStructures;
typedef struct {
i32 graphics, transfer;
VkQueue graphics_queue, transfer_queue;
} DeviceQueues;
typedef struct {
Library lib;
VkInstance inst;
VkSurfaceKHR surface;
VkDevice device;
VkPhysicalDevice phys_device;
DeviceQueues queues;
VmaAllocator alloc;
FrameStructures frame;
ImmediateStructures imm;
#ifdef BUILD_DEBUG
VkDebugUtilsMessengerEXT debug;
#endif
} Vulkan_t;
typedef struct {
Vulkan_t vk;
Arena *arena;
} Renderer_t;
// Renderer Function Declarations
// Debug
static b32 VLayersSupported();
static VkBool32 DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
VkDebugUtilsMessageTypeFlagsEXT message_types,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData
);
// Init
static b32 LoadVulkanLib();
static b32 InitVulkan(Arena *arena);
static b32 InitVkInstanceFunctions();
static b32 InitVkGlobalFunctions();
static b32 CreateSurface();
static b32 CreateDevice();
static b32 CheckQueueSurfaceSupport();
static DeviceQueues CheckDeviceQueueSupport();
static b32 CheckDevicePropertiesSupport();
static b32 CheckDeviceFeatureSupport();
static b32 InitVkDeviceFunctions();
static b32 CreateVmaAllocator();
static b32 CreateFrameStructures();
static b32 CreateImmediateStructures();
static b32 CreateSwapchain();
// Destroy
static void DestroyVulkan();
// Renderer Functions Declarations END
#include "vulkan_config.c"
static Renderer_t renderer = {
.vk = {
.queues = {
.graphics = -1,
.transfer = -1,
}
}
};
static const char *_VK_VALIDATION = "VK_LAYER_KHRONOS_validation";
#if __linux__
static char *vulkan_libs[] = {
"libvulkan.so.1",
"libvulkan.so"
};
#endif
#if _WIN32
#error Not yet implemented
#endif
#if __APPLE__ || __MACH__
#error Not yet implemented
#endif
#if __unix__ && !__linux__
#error Not yet implemented
#endif
b32 _InitRenderer(Arena *arena);
void _DestroyRenderer();

51
src/syscall_linux.s Normal file
View File

@ -0,0 +1,51 @@
.intel_syntax noprefix
.data
.bss
.text
.globl _syscall, _mmap
# rax - return value 64bit
# eax - return value 32bit
# params
# 1 - RDI
# 2 - RSI
# 3 - RDX
# 4 - RCX
# 5 - R8
# 6 - R9
# 7 - [rsp+8]
# 8 - [rsp+16]
# etc
_start:
xor rbp, rbp
pop rdi
mov rsi, rsp
and rsp, -16
call main
mov rdi, rax
mov rax, 60 # SYS_exit
syscall
ret
_syscall:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
mov rdx, rcx
mov r10, r8
mov r8, r9
syscall
ret
_mmap:
mov rax, 9
syscall
ret

80
src/util.c Normal file
View File

@ -0,0 +1,80 @@
b32 StrEq(const char *l, const char *r) {
for (; *l == *r && *l; l++, r++);
return *l == '\0' && *r == '\0';
}
u32 StrLen(const char *str)
{
const char *start;
for (start = str; *str != '\0'; ++str)
/* Iterate only */;
return (u32)(str - start);
}
i32 SPrintf(char *buf, rawptr fmt, ...)
{
va_list arg;
va_start(arg, fmt);
int sprf_res = stbsp_vsnprintf(buf, sizeof(buf), fmt, arg);
va_end(arg);
return sprf_res;
}
void MemZero(void *ptr, isize size)
{
isize iter_size = size > sizeof(u64) ? 8 : 1;
iter_size *= 4;
isize iter_len = size / iter_size;
if (iter_size > sizeof(u64))
{
u64 *mem = (u64 *)ptr;
while (iter_len > 0)
{
mem[0] = 0;
mem[1] = 0;
mem[2] = 0;
mem[3] = 0;
mem += 4;
iter_len--;
}
isize rem_len = size % iter_size;
while (rem_len > 0)
{
mem[0] = 0;
mem++;
rem_len--;
}
}
else
{
u8 *mem = (u8 *)ptr;
while (iter_len > 0)
{
mem[0] = 0;
mem[1] = 0;
mem[2] = 0;
mem[3] = 0;
mem += 4;
iter_len--;
}
isize rem_len = size % iter_size;
while (rem_len > 0)
{
mem[0] = 0;
mem++;
rem_len--;
}
}
u8 *test_ptr = (u8 *)ptr;
for (isize i = 0; i < size; i++)
{
assert(test_ptr[i] == 0);
}
}

19
src/util.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <assert.h>
#define DEFAULT_ALIGNMENT (2*sizeof(rawptr))
#define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define MakeString(x) #x
#define BitEq(var, bits) (((var) & (bits)) == bits)
#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1)))
#define IsPow2(x) ((x) != 0 && ((x) &((x) - 1)) == 0)
// String Functions
u32 StrLen(const char *str);
b32 StrEq(const char *l, const char *r);
i32 SPrintf(char *buf, rawptr fmt, ...);
// Memory Functions
void MemZero(void *ptr, isize size);

112
src/vulkan_config.c Normal file
View File

@ -0,0 +1,112 @@
// VULKAN CONFIG
static VkApplicationInfo app_info = {
.sType = STYPE(APPLICATION_INFO),
.pApplicationName = "Video Game",
.applicationVersion = VK_MAKE_API_VERSION(0, 0, 0, 1),
.pEngineName = "None (yet)",
.engineVersion = VK_MAKE_API_VERSION(0, 0, 0, 1),
.apiVersion = VK_API_VERSION_1_3,
};
static const char *instance_layers[] = {
"VK_LAYER_KHRONOS_validation"
};
static const char *instance_extensions[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XCB_SURFACE_EXTENSION_NAME,
#ifdef BUILD_DEBUG
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
#endif
};
static VkInstanceCreateInfo inst_info = {
.sType = STYPE(INSTANCE_CREATE_INFO),
.pApplicationInfo = &app_info,
.enabledLayerCount = sizeof(instance_layers) / sizeof(char *),
.ppEnabledLayerNames = instance_layers,
.enabledExtensionCount = sizeof(instance_extensions) / sizeof(char *),
.ppEnabledExtensionNames = instance_extensions,
};
const char *device_extensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME,
};
#ifdef BUILD_DEBUG
static VkDebugUtilsMessengerCreateInfoEXT debug_msg_info = {
.sType = STYPE(DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT),
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = DebugCallback,
};
#endif
static VkPhysicalDeviceVulkan13Features vk_13_features = {
.sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_3_FEATURES),
.synchronization2 = VK_TRUE,
.dynamicRendering = VK_TRUE
};
static VkPhysicalDeviceVulkan12Features vk_12_features = {
.sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_2_FEATURES),
.pNext = &vk_13_features,
.descriptorIndexing = VK_TRUE,
.bufferDeviceAddress = VK_TRUE
};
static VkPhysicalDeviceVulkan11Features vk_11_features = {
.sType = STYPE(PHYSICAL_DEVICE_VULKAN_1_1_FEATURES),
.pNext = &vk_12_features
};
static const VkPhysicalDeviceFeatures vk_features = {
.shaderUniformBufferArrayDynamicIndexing = VK_TRUE,
.shaderSampledImageArrayDynamicIndexing = VK_TRUE,
.shaderStorageBufferArrayDynamicIndexing = VK_TRUE,
.shaderStorageImageArrayDynamicIndexing = VK_TRUE
};
static VkPhysicalDeviceFeatures2 vk_features_2 = {
.sType = STYPE(PHYSICAL_DEVICE_FEATURES_2),
.pNext = &vk_11_features,
.features = vk_features
};
static VkDeviceCreateInfo device_info = {
.sType = STYPE(DEVICE_CREATE_INFO),
.pNext = &vk_features_2,
.ppEnabledExtensionNames = device_extensions,
.enabledExtensionCount = Len(device_extensions),
.pEnabledFeatures = NULL,
};
static VmaAllocatorCreateInfo vma_create_info = {
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
.vulkanApiVersion = VK_API_VERSION_1_3,
};
static VkCommandPoolCreateInfo pool_create_info = {
.sType = STYPE(COMMAND_POOL_CREATE_INFO),
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
};
static VkFenceCreateInfo fence_create_info = {
.sType = STYPE(FENCE_CREATE_INFO),
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
};
static VkSemaphoreCreateInfo semaphore_create_info = {
.sType = STYPE(SEMAPHORE_CREATE_INFO),
};
static VkCommandBufferAllocateInfo cmd_buf_info = {
.sType = STYPE(COMMAND_BUFFER_ALLOCATE_INFO),
.commandBufferCount = 1,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
};