started work on async code

This commit is contained in:
Matthew 2025-03-25 23:06:24 +11:00
parent 0f14ffd37f
commit 4ab1abbc27
9 changed files with 317 additions and 123 deletions

View File

@ -76,9 +76,10 @@ mkdir -p build
cd build cd build
mkdir -p ../src/file_data
if [ -v vulkan ]; then if [ -v vulkan ]; then
mkdir -p ./shaders/glsl mkdir -p ./shaders/glsl
mkdir -p ../src/file_data
for file in ../src/shaders/glsl/*.glsl; do for file in ../src/shaders/glsl/*.glsl; do
base_name=$(basename -- "$file" .glsl) base_name=$(basename -- "$file" .glsl)
@ -107,6 +108,16 @@ if [ -v vulkan ]; then
fi fi
rm -f ../src/file_data/images.c
touch ../src/file_data/images.c
for file in ../assets/*.png; do
base_name=$(basename -- "$file" .png)
xxd -n "image_${base_name}" -i $file >> ../src/file_data/images.c
done
$cpp_compiler $vma_compile_flags $vma_source_files $vma_out $vma_obj $cpp_compiler $vma_compile_flags $vma_source_files $vma_out $vma_obj
ar rcs libvma.a vma.o ar rcs libvma.a vma.o

View File

@ -8,6 +8,45 @@
#include "renderer.c" #include "renderer.c"
#include "game.c" #include "game.c"
const char *strs[10] = {
"String 1",
"String 2",
"String 3",
"String 4",
"String 5",
"String 6",
"String 7",
"String 8",
"String 9",
"String 10",
};
u32 volatile str_index = 0;
#include <unistd.h>
void *ThreadFunc(void *i)
{
for (;;)
{
u32 val = __atomic_fetch_add(&str_index, 1, __ATOMIC_RELEASE);
if (val < 10)
{
Printfln("Thread %d: %s", *(u32 *)i, strs[val]);
sleep(1);
}
else
break;
}
pthread_exit(NULL);
}
void RunThreadFunc(pthread_t *th, u32 *u, void *func)
{
pthread_create(th, NULL, func, u);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
u8 *mem = (u8 *)MemAllocZeroed(MB(64)); u8 *mem = (u8 *)MemAllocZeroed(MB(64));

View File

@ -2,6 +2,8 @@
#pragma once #pragma once
#define _GNU_SOURCE
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#define WINDOW_NAME "Video Game" #define WINDOW_NAME "Video Game"

View File

@ -558,3 +558,10 @@ b32 _ShouldQuit()
{ {
return false; return false;
} }
u32 AvailableCPUCount()
{
cpu_set_t cpu_set;
sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
return CPU_COUNT(&cpu_set);
}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <pthread.h>
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
@ -17,6 +18,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <nmmintrin.h> #include <nmmintrin.h>
#include <immintrin.h>
#include <sched.h>
// syscall defines // syscall defines
#define SYS_ERR -1 #define SYS_ERR -1
@ -89,6 +93,7 @@ void RepaintWindow();
// General Utils // General Utils
b32 CheckSyscallErr(void *ptr); b32 CheckSyscallErr(void *ptr);
u32 AvailableCPUCount();
// Write Utils // Write Utils
i32 Write(int fd, void const *str, isize count); i32 Write(int fd, void const *str, isize count);

View File

@ -34,6 +34,8 @@ typedef enum VertexAttrType_e
// Declarations // Declarations
typedef u16 DescHandle;
// @requirement RenderBuffer type; // @requirement RenderBuffer type;
// @requirement u32 size; // @requirement u32 size;
typedef struct RenderBuffer_t RenderBuffer; typedef struct RenderBuffer_t RenderBuffer;
@ -51,27 +53,29 @@ typedef struct RenderBuffers_t
// Back End API // Back End API
// Initialization // ::Initialization::Header::
b32 InitRenderer(Arena *arena); b32 InitRenderer(Arena *arena);
void DestroyRenderer(); void DestroyRenderer();
// Buffers // ::Buffers::Header::
static b32 CreateBuffer(RenderBuffer *buffer); static b32 CreateBuffer(RenderBuffer *buffer);
static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count); static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count);
static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr); static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr, u8 thr_ix);
static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr); static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr);
static void BindVertexBuffer(RenderBuffer *buffer); static void BindVertexBuffer(RenderBuffer *buffer);
static void BindIndexBuffer(RenderBuffer *buffer); static void BindIndexBuffer(RenderBuffer *buffer);
// Uniforms/PushConstants // ::Uniforms::Header:: ::PushConstants::Header::
static void GetViewportSize(Vec2 *size); static void GetViewportSize(Vec2 *size);
static void SetGlobalUniform(ShaderGlobals *globals); static void SetGlobalUniform(ShaderGlobals *globals);
static void SetPushConstants(PushConst *pc); static void SetPushConstants(PushConst *pc);
static DescHandle UploadImageUniform();
// Config // ::Config::Header::
static void SetRenderResolution(u32 x, u32 y); static void SetRenderResolution(u32 x, u32 y);
static void SetRendererAvailableThreads(u32 n);
// Rendering // ::Rendering::Header::
static b32 BeginFrame(); static b32 BeginFrame();
static b32 FinishFrame(); static b32 FinishFrame();
static void DrawIndexed(u32 index_count, u32 instance_count); static void DrawIndexed(u32 index_count, u32 instance_count);

View File

@ -702,19 +702,19 @@ static b32 VLayersSupported()
static b32 CreateFrameStructures() static b32 CreateFrameStructures()
{ {
b32 success = true; b32 success = true;
FrameStructures *data = &renderer.vk.frame; FrameStructures *data = &renderer.vk.frame;
u32 img_count = renderer.vk.sc.img_count; u32 img_count = renderer.vk.sc.img_count;
pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics; pool_create_info.queueFamilyIndex = renderer.vk.queues.graphics;
renderer.vk.frame.pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * img_count); renderer.vk.frame.pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * img_count);
renderer.vk.frame.buffers = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * img_count); renderer.vk.frame.buffers = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * img_count);
renderer.vk.frame.swapchain_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count); renderer.vk.frame.swapchain_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count); renderer.vk.frame.render_sems = ArenaAlloc(renderer.perm_arena, sizeof(VkSemaphore) * img_count);
renderer.vk.frame.render_fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * img_count); renderer.vk.frame.render_fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * img_count);
renderer.vk.frame.buffer_destroy_queues = ArenaAlloc(renderer.perm_arena, sizeof(RenderBuffer *) * FRAME_OVERLAP); renderer.vk.frame.buffer_destroy_queues = ArenaAlloc(renderer.perm_arena, sizeof(RenderBuffer *) * FRAME_OVERLAP);
renderer.vk.frame.buffer_counts = ArenaAlloc(renderer.perm_arena, sizeof(u32) * FRAME_OVERLAP); renderer.vk.frame.buffer_counts = ArenaAlloc(renderer.perm_arena, sizeof(u32) * FRAME_OVERLAP);
for (u32 i = 0; i < FRAME_OVERLAP; i++) for (u32 i = 0; i < FRAME_OVERLAP; i++)
{ {
@ -751,25 +751,40 @@ static b32 CreateFrameStructures()
static b32 CreateImmediateStructures() static b32 CreateImmediateStructures()
{ {
b32 success = true; b32 success = true;
VkResult result; VkResult result;
VkDevice device = renderer.vk.device; VkDevice device = renderer.vk.device;
ImmediateStructures *imm = &renderer.vk.imm; ImmediateStructures *imm = &renderer.vk.imm;
u8 thread_count = 1;
pool_create_info.queueFamilyIndex = renderer.vk.queues.transfer; pool_create_info.queueFamilyIndex = renderer.vk.queues.transfer;
result = vkCreateCommandPool(device, &pool_create_info, NULL, &imm->pool); if (renderer.vk_conf.avail_threads >= 10)
if (result != VK_SUCCESS) thread_count = 3;
success = false; else if (renderer.vk_conf.avail_threads >= 8)
thread_count = 2;
cmd_buf_info.commandPool = imm->pool; imm->pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * thread_count);
imm->cmds = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * thread_count);
imm->fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * thread_count);
imm->queued_buffers = ArenaAlloc(renderer.perm_arena, sizeof(RenderBuffer) * BUFFER_QUEUE_LEN);
imm->data = ArenaAlloc(renderer.perm_arena, sizeof(void *) * BUFFER_QUEUE_LEN);
result = vkAllocateCommandBuffers(device, &cmd_buf_info, &imm->cmd); for (u32 i = 0; i < thread_count && success; i++)
if (result != VK_SUCCESS) {
success = false; result = vkCreateCommandPool(device, &pool_create_info, NULL, &imm->pools[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &imm->fence); cmd_buf_info.commandPool = imm->pools[i];
if (result != VK_SUCCESS)
success = false; result = vkAllocateCommandBuffers(device, &cmd_buf_info, &imm->cmds[i]);
if (result != VK_SUCCESS)
success = false;
result = vkCreateFence(device, &fence_create_info, NULL, &imm->fences[i]);
if (result != VK_SUCCESS)
success = false;
}
return success; return success;
} }
@ -997,6 +1012,7 @@ static b32 CreateDescriptors()
{ {
bindings[i].free = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS); bindings[i].free = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS);
bindings[i].used = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS); bindings[i].used = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS);
bindings[i].handle_indices = ArenaAlloc(renderer.perm_arena, sizeof(DescHandle) * DESC_MAX_BINDINGS);
u16 free_count = 0; u16 free_count = 0;
for (i32 j = DESC_MAX_BINDINGS-1; j >= 0; j--) for (i32 j = DESC_MAX_BINDINGS-1; j >= 0; j--)
@ -1115,6 +1131,54 @@ static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module)
return success; return success;
} }
#ifdef __linux__
void *VkLoaderStart(void *i)
{
u32 index = *(u32 *)i;
pthread_t self = pthread_self();
for (;;)
{
u32 job_count = __atomic_load_n(&renderer.vk_conf.job_count, __ATOMIC_RELEASE);
if (job_count < 0)
{
pthread_exit(NULL);
}
else if (job_count == 0)
{
__atomic_add_fetch(&renderer.vk_conf.sleeping_count, __ATOMIC_RELEASE);
pthread_suspend(self);
}
else if (__atomic_compare_exchange_n(&renderer.vk_conf.job_count, &job_count, job_count-1, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED))
{
job_count -= 1;
}
}
}
static b32 StartVkLoaderThreads()
{
u32 count = renderer.vk_conf.avail_threads;
pthread_t *threads = ArenaAlloc(renderer.perm_arena, sizeof(pthread_t) * count);
for (u32 i = 0; i < count; i++)
{
vk_thread_indices[i] = i;
pthread_create(&threads[i], NULL, VkLoaderStart, &vk_thread_indices[i]);
}
}
#elif _WIN32
#error not yet implemented
#endif
static void DestroySwapchain() static void DestroySwapchain()
{ {
for (u32 i = 0; i < renderer.vk.sc.img_count; i++) for (u32 i = 0; i < renderer.vk.sc.img_count; i++)

View File

@ -16,7 +16,7 @@
#include "file_data/spv.c" #include "file_data/spv.c"
// Macros // ::Vulkan::Macros::Header::
#define VK_DECLARE(fn) static PFN_##fn fn = NULL #define VK_DECLARE(fn) static PFN_##fn fn = NULL
#define STYPE(type) VK_STRUCTURE_TYPE_ ## type #define STYPE(type) VK_STRUCTURE_TYPE_ ## type
@ -36,19 +36,14 @@
if (!name) return false; \ if (!name) return false; \
} while (0) } while (0)
#define FRAME_OVERLAP 2 // ::Vulkan::GlobalFunctions::Header::
#define DESC_MAX_BINDINGS 256
// Macros END
// Vulkan Functions
// Global
VK_DECLARE(vkGetInstanceProcAddr); VK_DECLARE(vkGetInstanceProcAddr);
VK_DECLARE(vkCreateInstance); VK_DECLARE(vkCreateInstance);
VK_DECLARE(vkEnumerateInstanceLayerProperties); VK_DECLARE(vkEnumerateInstanceLayerProperties);
// Instance // ::Vulkan::InstanceFunctions::Header::
VK_DECLARE(vkEnumeratePhysicalDevices); VK_DECLARE(vkEnumeratePhysicalDevices);
VK_DECLARE(vkCreateDevice); VK_DECLARE(vkCreateDevice);
VK_DECLARE(vkGetPhysicalDeviceQueueFamilyProperties); VK_DECLARE(vkGetPhysicalDeviceQueueFamilyProperties);
@ -61,6 +56,8 @@ VK_DECLARE(vkGetPhysicalDeviceSurfaceFormatsKHR);
VK_DECLARE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); VK_DECLARE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
VK_DECLARE(vkGetPhysicalDeviceImageFormatProperties); VK_DECLARE(vkGetPhysicalDeviceImageFormatProperties);
// ::Vulkan::PlatformFunctions::Header::
#ifdef __linux__ #ifdef __linux__
VK_DECLARE(vkCreateXcbSurfaceKHR); VK_DECLARE(vkCreateXcbSurfaceKHR);
#elif _WIN32 #elif _WIN32
@ -77,7 +74,8 @@ VK_DECLARE(vkCreateDebugUtilsMessengerEXT);
VK_DECLARE(vkDestroyDebugUtilsMessengerEXT); VK_DECLARE(vkDestroyDebugUtilsMessengerEXT);
#endif #endif
// Device // ::Vulkan::DeviceFunctions::Header::
VK_DECLARE(vkGetDeviceProcAddr); VK_DECLARE(vkGetDeviceProcAddr);
VK_DECLARE(vkCreateSwapchainKHR); VK_DECLARE(vkCreateSwapchainKHR);
VK_DECLARE(vkCreateImage); VK_DECLARE(vkCreateImage);
@ -139,14 +137,16 @@ VK_DECLARE(vkCmdDraw);
VK_DECLARE(vkDeviceWaitIdle); VK_DECLARE(vkDeviceWaitIdle);
VK_DECLARE(vkCmdClearColorImage); VK_DECLARE(vkCmdClearColorImage);
// Vulkan Functions END
#include "vma/vk_mem_alloc.h" #include "vma/vk_mem_alloc.h"
// Defines // ::Vulkan::Defines::Header::
#define FRAME_OVERLAP 2
#define DESC_MAX_BINDINGS 256
#define BUFFER_QUEUE_LEN 32
#define HOST_VISIBLE_BUFFERS (RENDER_BUFFER_TYPE_UNIFORM | RENDER_BUFFER_TYPE_STAGING) #define HOST_VISIBLE_BUFFERS (RENDER_BUFFER_TYPE_UNIFORM | RENDER_BUFFER_TYPE_STAGING)
// Types // ::Vulkan::Types::Header::
typedef enum DescType_e typedef enum DescType_e
{ {
@ -165,18 +165,18 @@ typedef struct ShaderGlobals_t
typedef struct RenderBuffer_t typedef struct RenderBuffer_t
{ {
RenderBufferType type; RenderBufferType type;
VkBuffer buffer; VkBuffer buffer;
VmaAllocation alloc; VmaAllocation alloc;
VmaAllocationInfo info; VmaAllocationInfo info;
u32 size; u32 size;
i32 mem_index; // TODO(MA): use this i32 mem_index; // TODO(MA): use this
} RenderBuffer; } RenderBuffer;
typedef struct typedef struct
{ {
RenderBuffer index_buf, vertex_buf; RenderBuffer index_buf, vertex_buf;
u32 index_count; u32 index_count;
} MeshBuffer; } MeshBuffer;
typedef struct typedef struct
@ -186,21 +186,22 @@ typedef struct
typedef struct typedef struct
{ {
u16 *free; u16 *free;
u16 free_count; u16 free_count;
u16 *used; u16 *used;
u16 used_count; u16 used_count;
DescHandle *handle_indices;
} DescBindings; } DescBindings;
typedef struct typedef struct
{ {
VkPipelineLayout pipeline_layout; VkPipelineLayout pipeline_layout;
VkDescriptorPool pool; VkDescriptorPool pool;
VkDescriptorSetLayout layouts[DESC_TYPE_MAX]; VkDescriptorSetLayout layouts[DESC_TYPE_MAX];
VkDescriptorSet sets[DESC_TYPE_MAX]; VkDescriptorSet sets[DESC_TYPE_MAX];
DescBindings *bindings; DescBindings *bindings;
u16 bindings_count; u16 bindings_count;
VkPipeline pipelines[PIPELINE_MAX]; VkPipeline pipelines[PIPELINE_MAX];
} PipelineStructures; } PipelineStructures;
typedef struct PushConst_t typedef struct PushConst_t
@ -210,70 +211,75 @@ typedef struct PushConst_t
typedef struct typedef struct
{ {
VkCommandPool *pools; VkCommandPool *pools;
VkCommandBuffer *buffers; VkCommandBuffer *buffers;
VkSemaphore *swapchain_sems; VkSemaphore *swapchain_sems;
VkSemaphore *render_sems; VkSemaphore *render_sems;
VkFence *render_fences; VkFence *render_fences;
RenderBuffer **buffer_destroy_queues; RenderBuffer **buffer_destroy_queues;
u32 *buffer_counts; u32 *buffer_counts;
} FrameStructures; } FrameStructures;
typedef struct typedef struct
{ {
VkCommandPool pool; VkCommandPool *pools;
VkCommandBuffer cmd; VkCommandBuffer *cmds;
VkFence fence; VkFence *fences;
RenderBuffer **queued_buffers;
void *data;
i32 volatile job_count;
i32 volatile completed_count;
i32 volatile sleeping_count;
} ImmediateStructures; } ImmediateStructures;
typedef struct { typedef struct {
i32 graphics, transfer; i32 graphics, transfer;
VkQueue graphics_queue, transfer_queue; VkQueue graphics_queue, transfer_queue;
} DeviceQueues; } DeviceQueues;
typedef struct { typedef struct {
VkImage img; VkImage img;
VkImageView view; VkImageView view;
VmaAllocation alloc; VmaAllocation alloc;
VkFormat fmt; VkFormat fmt;
VkImageLayout curr_layout; VkImageLayout curr_layout;
} Image; } Image;
typedef struct { typedef struct {
VkFormat format; VkFormat format;
VkColorSpaceKHR color_space; VkColorSpaceKHR color_space;
VkPresentModeKHR present_mode; VkPresentModeKHR present_mode;
VkExtent3D extent; VkExtent3D extent;
VkImage *imgs; VkImage *imgs;
VkImageView *views; VkImageView *views;
u32 img_count; u32 img_count;
Image draw_img; Image draw_img;
Image depth_img; Image depth_img;
} SwapchainStructures; } SwapchainStructures;
typedef struct { typedef struct {
u32 img_ix; u32 img_ix;
u64 frame_cnt; u64 frame_cnt;
u64 prev_frame; u64 prev_frame;
b8 begin_rendering; b8 begin_rendering;
PipelineHandle last_pipeline; PipelineHandle last_pipeline;
RenderBuffer *prev_buffers; RenderBuffer *prev_buffers;
u32 prev_buffer_count; u32 prev_buffer_count;
} FrameState; } FrameState;
typedef struct { typedef struct {
Library lib; Library lib;
VkInstance inst; VkInstance inst;
VkSurfaceKHR surface; VkSurfaceKHR surface;
VkDevice device; VkDevice device;
VkSwapchainKHR swapchain; VkSwapchainKHR swapchain;
VkPhysicalDevice phys_device; VkPhysicalDevice phys_device;
DeviceQueues queues; DeviceQueues queues;
VmaAllocator alloc; VmaAllocator alloc;
FrameStructures frame; FrameStructures frame;
ImmediateStructures imm; ImmediateStructures imm;
SwapchainStructures sc; SwapchainStructures sc;
PipelineStructures pipe; PipelineStructures pipe;
#ifdef BUILD_DEBUG #ifdef BUILD_DEBUG
VkDebugUtilsMessengerEXT debug; VkDebugUtilsMessengerEXT debug;
#endif #endif
@ -282,21 +288,33 @@ typedef struct {
typedef struct { typedef struct {
u16 render_width; u16 render_width;
u16 render_height; u16 render_height;
b8 resized; b8 resized;
} PendingUpdates; } PendingUpdates;
typedef struct VulkanConfig_t
{
u8 avail_threads;
#ifdef __linux__
pthread_t *threads;
#elif _WIN32
#error not yet implemented
#endif
} VulkanConfig;
typedef struct Renderer_t typedef struct Renderer_t
{ {
Vulkan_t vk; Vulkan_t vk;
FrameState frame_state; VulkanConfig vk_conf;
FrameState frame_state;
PendingUpdates pending; PendingUpdates pending;
Arena *arena; Arena *arena;
Arena *perm_arena; Arena *perm_arena;
} Renderer; } Renderer;
// Renderer Function Declarations // ::Vulkan::Functions::Header::
// ::Vulkan::Debug::Header::
// Debug
static b32 VLayersSupported(); static b32 VLayersSupported();
static VKAPI_ATTR VkBool32 DebugCallback( static VKAPI_ATTR VkBool32 DebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
@ -306,7 +324,8 @@ static VKAPI_ATTR VkBool32 DebugCallback(
); );
const char *VkResultStr(VkResult result); const char *VkResultStr(VkResult result);
// Init // ::Vulkan::Init::Header::
static b32 LoadVulkanLib(); static b32 LoadVulkanLib();
static b32 InitVkInstanceFunctions(); static b32 InitVkInstanceFunctions();
static b32 InitVkGlobalFunctions(); static b32 InitVkGlobalFunctions();
@ -326,8 +345,10 @@ static VkFormat GetImageFormat();
static b32 CreateDescriptors(); static b32 CreateDescriptors();
static b32 CreatePipelines(); static b32 CreatePipelines();
static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module); static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module);
static b32 StartVkLoaderThreads();
// ::Vulkan::Util::Header::
// Util
static inline VkCommandBuffer GetFrameCmdBuf(); static inline VkCommandBuffer GetFrameCmdBuf();
static inline VkFence *GetFrameRenderFence(); static inline VkFence *GetFrameRenderFence();
static inline VkSemaphore GetFrameRenderSem(); static inline VkSemaphore GetFrameRenderSem();
@ -338,36 +359,49 @@ static inline u32 *GetFrameBufferCount();
static inline RenderBuffer *GetFrameRenderBuffers(); static inline RenderBuffer *GetFrameRenderBuffers();
static void BeginRendering(); static void BeginRendering();
// Immediate Submit // ::Vulkan::Async::Header::
#ifdef __linux__
void *VkLoaderStart(void *thread_data);
#elif _WIN32
#error not yet implemented
#endif
// ::Vulkan::ImmediateSubmit::Header::
static b32 BeginImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd); static b32 BeginImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd);
static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd, VkQueue queue); static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd, VkQueue queue);
// Buffers // ::Vulkan::Buffers::Header::
static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx); static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx);
// Destroy // ::Vulkan::Destroy::Header::
static void DestroySwapchain(); static void DestroySwapchain();
static void DestroyDrawImages(); static void DestroyDrawImages();
// Util // ::Vulkan::Util::Header::
static void TransitionImage(VkCommandBuffer cmd, Image *img, VkImageLayout new); static void TransitionImage(VkCommandBuffer cmd, Image *img, VkImageLayout new);
static void TransitionImageLayout(VkCommandBuffer cmd, VkImage img, VkImageLayout curr, VkImageLayout new); static void TransitionImageLayout(VkCommandBuffer cmd, VkImage img, VkImageLayout curr, VkImageLayout new);
static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext); static void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext);
// Swapchain // ::Vulkan::Swapchain::Header::
static VkExtent2D SelectSwapchainExtent(VkSurfaceCapabilitiesKHR *capabilities); static VkExtent2D SelectSwapchainExtent(VkSurfaceCapabilitiesKHR *capabilities);
static VkSurfaceFormatKHR SelectSwapchainFormat(VkSurfaceFormatKHR *formats); static VkSurfaceFormatKHR SelectSwapchainFormat(VkSurfaceFormatKHR *formats);
static void ResizeSwapchain(); static void ResizeSwapchain();
// Logging // ::Vulkan::Logging::Header::
static void VkInfo(const char *str); static void VkInfo(const char *str);
static void VkWarn(const char *str); static void VkWarn(const char *str);
static void VkError(const char *str); static void VkError(const char *str);
// Renderer Functions Declarations END
#include "vulkan_config.c" #include "vulkan_config.c"
// ::Vulkan::Globals::Header::
static Renderer renderer = { static Renderer renderer = {
.vk = { .vk = {
.queues = { .queues = {
@ -382,6 +416,10 @@ static Renderer renderer = {
} }
}; };
static u32 vk_thread_indices[10] = {};
// ::Vulkan::Constants::Header::
static const char *_VK_VALIDATION = "VK_LAYER_KHRONOS_validation"; static const char *_VK_VALIDATION = "VK_LAYER_KHRONOS_validation";
#if __linux__ #if __linux__

View File

@ -3,6 +3,8 @@
*/ */
b32 InitRenderer(Arena *arena) b32 InitRenderer(Arena *arena)
{ {
SetRendererAvailableThreads(AvailableCPUCount());
CustomizePipelines(); CustomizePipelines();
Assert(arena != NULL, "Vulkan memory is null"); Assert(arena != NULL, "Vulkan memory is null");
@ -39,6 +41,7 @@ b32 InitRenderer(Arena *arena)
Assert(CreateImmediateStructures(), "Unable to create immediate structures"); Assert(CreateImmediateStructures(), "Unable to create immediate structures");
Assert(CreateDescriptors(), "Unable to initialize descriptors."); Assert(CreateDescriptors(), "Unable to initialize descriptors.");
Assert(CreatePipelines(), "Unable to initialize pipelines."); Assert(CreatePipelines(), "Unable to initialize pipelines.");
Assert(StartVkLoaderThreads(), "Unable to initialize vulkan loader threads");
ArenaFree(renderer.arena); ArenaFree(renderer.arena);
@ -74,9 +77,12 @@ void DestroyRenderer()
DestroySwapchain(); DestroySwapchain();
vkDestroyFence(device, imm.fence, NULL); for (u32 i = 0; i < renderer.vk_conf.avail_threads; i++)
vkFreeCommandBuffers(device, imm.pool, 1, &imm.cmd); {
vkDestroyCommandPool(device, imm.pool, NULL); vkDestroyFence(device, imm.fences[i], NULL);
vkFreeCommandBuffers(device, imm.pools[i], 1, &imm.cmds[i]);
vkDestroyCommandPool(device, imm.pools[i], NULL);
}
for (u32 i = 0; i < FRAME_OVERLAP; i++) for (u32 i = 0; i < FRAME_OVERLAP; i++)
{ {
@ -196,14 +202,15 @@ static b32 CreateBuffer(RenderBuffer *buffer)
return success; return success;
} }
static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr) static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr, u8 thr_ix)
{ {
Assert(buffer, "UploadToBuffer: buffer must not be null"); Assert(buffer, "UploadToBuffer: buffer must not be null");
Assert(ptr, "UploadToBuffer: ptr must not be null"); Assert(ptr, "UploadToBuffer: ptr must not be null");
b32 success = true; b32 success = true;
ImmediateStructures *imm = &renderer.vk.imm; VkCommandBuffer cmd = renderer.vk.imm.cmds[thr_ix];
VkFence fence = renderer.vk.imm.fences[thr_ix];
VkDevice device = renderer.vk.device; VkDevice device = renderer.vk.device;
VkQueue queue = renderer.vk.queues.transfer_queue; VkQueue queue = renderer.vk.queues.transfer_queue;
VmaAllocator alloc = renderer.vk.alloc; VmaAllocator alloc = renderer.vk.alloc;
@ -231,18 +238,18 @@ static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr)
} }
if (success) if (success)
success = BeginImmSubmit(device, &imm->fence, imm->cmd); success = BeginImmSubmit(device, &fence, cmd);
b32 imm_started = success; b32 imm_started = success;
if (success) if (success)
{ {
VkBufferCopy buffer_copy = { .size = (VkDeviceSize)buffer->size }; VkBufferCopy buffer_copy = { .size = (VkDeviceSize)buffer->size };
vkCmdCopyBuffer(imm->cmd, staging_buffer.buffer, buffer->buffer, 1, &buffer_copy); vkCmdCopyBuffer(cmd, staging_buffer.buffer, buffer->buffer, 1, &buffer_copy);
} }
if (imm_started) if (imm_started)
FinishImmSubmit(device, &imm->fence, imm->cmd, queue); FinishImmSubmit(device, &fence, cmd, queue);
if (buffer_created) if (buffer_created)
{ {
@ -254,6 +261,17 @@ static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr)
return success; return success;
} }
static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr)
{
// TODO: revisit this to see if it could be done better
u32 i = __atomic_fetch_add(&renderer.vk.imm.job_count, 1, __ATOMIC_RELEASE);
renderer.vk.imm.queued_buffers[i] = buffer;
renderer.vk.imm.data[i] = ptr;
}
/* TODO: DELETE
static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr) static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr)
{ {
b32 success = true; b32 success = true;
@ -261,10 +279,11 @@ static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr)
success = CreateBuffer(buffer); success = CreateBuffer(buffer);
if (success) if (success)
success = UploadToBuffer(buffer, ptr); success = UploadToBuffer(buffer, ptr, 0); // TODO: DELETE this
return success; return success;
} }
*/
static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count) static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count)
{ {
@ -348,6 +367,11 @@ static void SetRenderResolution(u32 x, u32 y)
renderer.pending.resized = true; renderer.pending.resized = true;
} }
static void SetRendererAvailableThreads(u32 n)
{
renderer.vk_conf.avail_threads = n;
}
/* /*
* ::Config::End:: * ::Config::End::
*/ */