first commit
This commit is contained in:
commit
7bf35d0031
77
build.sh
Executable file
77
build.sh
Executable 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
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
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
5
external/vma/vma.cpp
vendored
Normal 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
56
src/arena.c
Normal 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
25
src/arena.h
Normal 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
26
src/main.c
Normal 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
16
src/main.h
Normal 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
93
src/platform.c
Normal 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
37
src/platform.h
Normal 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
230
src/platform_linux.c
Normal 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
115
src/platform_linux.h
Normal 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
24
src/render.c
Normal 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
21
src/render.h
Normal 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
571
src/render_vulkan.c
Normal 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
227
src/render_vulkan.h
Normal 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
51
src/syscall_linux.s
Normal 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
80
src/util.c
Normal 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
19
src/util.h
Normal 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
112
src/vulkan_config.c
Normal 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,
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user