From 0f14ffd37f69bd67ec3cbd63baf120cdcfb5e3c7 Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 23 Mar 2025 10:28:12 +1100 Subject: [PATCH] some refactoring + cleanup of swapchain parameter selecetion --- src/entry_linux.c | 2 +- src/entry_linux.h | 2 +- src/entry_windows.c | 2 +- src/entry_windows.h | 2 +- src/platform.c | 5 - src/platform_linux.c | 6 +- src/platform_linux.h | 4 +- src/platform_windows.c | 4 +- src/platform_windows.h | 3 +- src/{render.c => renderer.c} | 4 +- src/{render.h => renderer.h} | 7 +- src/{render_d3d11.c => renderer_d3d11.c} | 0 src/{render_d3d11.h => renderer_d3d11.h} | 0 src/{render_vulkan.c => renderer_vulkan.c} | 640 ++------------------- src/{render_vulkan.h => renderer_vulkan.h} | 24 +- src/renderer_vulkan_public.c | 583 +++++++++++++++++++ 16 files changed, 658 insertions(+), 630 deletions(-) rename src/{render.c => renderer.c} (77%) rename src/{render.h => renderer.h} (94%) rename src/{render_d3d11.c => renderer_d3d11.c} (100%) rename src/{render_d3d11.h => renderer_d3d11.h} (100%) rename src/{render_vulkan.c => renderer_vulkan.c} (68%) rename src/{render_vulkan.h => renderer_vulkan.h} (95%) create mode 100644 src/renderer_vulkan_public.c diff --git a/src/entry_linux.c b/src/entry_linux.c index 0380b01..ecbbc08 100644 --- a/src/entry_linux.c +++ b/src/entry_linux.c @@ -5,7 +5,7 @@ #include "platform.c" #include "util.c" #include "arena.c" -#include "render.c" +#include "renderer.c" #include "game.c" int main(int argc, char **argv) diff --git a/src/entry_linux.h b/src/entry_linux.h index 83d47c1..3c4cdbc 100644 --- a/src/entry_linux.h +++ b/src/entry_linux.h @@ -12,7 +12,7 @@ #include "platform.h" #include "util.h" #include "arena.h" -#include "render.h" +#include "renderer.h" #include "game.h" int main(int argc, char **argv); diff --git a/src/entry_windows.c b/src/entry_windows.c index 11413dc..9b849e4 100644 --- a/src/entry_windows.c +++ b/src/entry_windows.c @@ -5,7 +5,7 @@ #include "platform.c" #include "util.c" #include "arena.c" -#include "render.c" +#include "renderer.c" #include "game.c" int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code) diff --git a/src/entry_windows.h b/src/entry_windows.h index 5e02805..a91f6ea 100644 --- a/src/entry_windows.h +++ b/src/entry_windows.h @@ -12,7 +12,7 @@ #include "platform.h" #include "util.h" #include "arena.h" -#include "render.h" +#include "renderer.h" #include "game.h" int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code); diff --git a/src/platform.c b/src/platform.c index c225d73..a00908f 100644 --- a/src/platform.c +++ b/src/platform.c @@ -87,11 +87,6 @@ b32 CreatePlatformWindow() return _CreateWindow(); } -GameWindow *GetWindowPtr() -{ - return _GetWindow(); -} - WindowSize GetWindowSize() { return _GetWindowSize(); diff --git a/src/platform_linux.c b/src/platform_linux.c index fc94ddc..408bac3 100644 --- a/src/platform_linux.c +++ b/src/platform_linux.c @@ -1,6 +1,6 @@ // TODO(MA): Do stuff for general unix platforms some day -static GameWindow linux_window = { +static PlatformWindow linux_window = { .w = 1920, .h = 1080, }; @@ -139,7 +139,7 @@ isize _GetPageSize() b32 _CreateWindow() { - GameWindow *window = &linux_window; + PlatformWindow *window = &linux_window; window->display = XOpenDisplay(NULL); if (!window->display) @@ -245,7 +245,7 @@ b32 _CreateWindow() return true; } -GameWindow *_GetWindow() { +PlatformWindow *GetPlatformWindow() { return &linux_window; } diff --git a/src/platform_linux.h b/src/platform_linux.h index b2b2aca..76368af 100644 --- a/src/platform_linux.h +++ b/src/platform_linux.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -47,7 +48,7 @@ typedef struct { xcb_atom_t close_event; xcb_atom_t minimize_event; u16 w, h; -} GameWindow; +} PlatformWindow; typedef struct { void *lib; @@ -77,7 +78,6 @@ i32 _EPrintf(const char *fmt, va_list arg); // Window Functions b32 _CreateWindow(); -GameWindow *_GetWindow(); void GetWindowEvents(GameInput *inputs, u32 *i_count); b32 WaitForWindowEvent(GameInput *input); WindowSize _GetWindowSize(); diff --git a/src/platform_windows.c b/src/platform_windows.c index 3bb9f09..834e05f 100644 --- a/src/platform_windows.c +++ b/src/platform_windows.c @@ -1,5 +1,5 @@ HINSTANCE win32_instance = {0}; -GameWindow win32_window = {0}; +PlatformWindow win32_window = {0}; b32 global_quit = false; LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) @@ -176,7 +176,7 @@ b32 _CreateWindow() return success; } -GameWindow *_GetWindow() +PlatformWindow *GetPlatformWindow() { return &win32_window; } diff --git a/src/platform_windows.h b/src/platform_windows.h index 43efd10..5c3aa36 100644 --- a/src/platform_windows.h +++ b/src/platform_windows.h @@ -17,7 +17,7 @@ typedef struct HWND handle; u16 h, w; b32 resize_requested; -} GameWindow; +} PlatformWindow; typedef struct { @@ -38,7 +38,6 @@ i32 _Printfln(const char *fmt, va_list arg); i32 _EPrintf(const char *fmt, va_list arg); b32 _CreateWindow(); -GameWindow *_GetWindow(); void GetWindowEvents(); void WaitForWindowEvent(); WindowSize _GetWindowSize(); diff --git a/src/render.c b/src/renderer.c similarity index 77% rename from src/render.c rename to src/renderer.c index e3b1753..081b2d3 100644 --- a/src/render.c +++ b/src/renderer.c @@ -1,5 +1,5 @@ #if STG_VULKAN_RENDERER -#include "render_vulkan.c" +#include "renderer_vulkan.c" #endif #if STG_OPENGL_RENDERER @@ -11,6 +11,6 @@ #endif #if STG_DX11_RENDERER && __linux__ -#include "render_d3d11.c" +#include "renderer_d3d11.c" #endif diff --git a/src/render.h b/src/renderer.h similarity index 94% rename from src/render.h rename to src/renderer.h index 0d46d08..53b3164 100644 --- a/src/render.h +++ b/src/renderer.h @@ -77,11 +77,8 @@ static b32 FinishFrame(); static void DrawIndexed(u32 index_count, u32 instance_count); static void BindPipeline(PipelineHandle handle, PipelineType type); -// Placeholders (Remove me) -static void DrawTriangle(); - #if STG_VULKAN_RENDERER -#include "render_vulkan.h" +#include "renderer_vulkan.h" #endif #if STG_OPENGL_RENDERER @@ -93,5 +90,5 @@ static void DrawTriangle(); #endif #if STG_DX11_RENDERER && __linux__ -#include "render_d3d11.h" +#include "renderer_d3d11.h" #endif diff --git a/src/render_d3d11.c b/src/renderer_d3d11.c similarity index 100% rename from src/render_d3d11.c rename to src/renderer_d3d11.c diff --git a/src/render_d3d11.h b/src/renderer_d3d11.h similarity index 100% rename from src/render_d3d11.h rename to src/renderer_d3d11.h diff --git a/src/render_vulkan.c b/src/renderer_vulkan.c similarity index 68% rename from src/render_vulkan.c rename to src/renderer_vulkan.c index eda2d52..a77e32b 100644 --- a/src/render_vulkan.c +++ b/src/renderer_vulkan.c @@ -3,49 +3,40 @@ */ // TODO(MA): Make separate functions for debug/non debug builds for readability -b32 InitRenderer(Arena *arena) -{ - Assert(InitVulkan(arena), "InitVkLib failure"); - return true; -} +#include "renderer_vulkan_public.c" -void DestroyRenderer() -{ - DestroyVulkan(); -} - -static u32 GetFrameIndex() +static inline u32 GetFrameIndex() { return renderer.frame_state.frame_cnt % FRAME_OVERLAP; } -static VkCommandBuffer GetFrameCmdBuf() +static inline VkCommandBuffer GetFrameCmdBuf() { return renderer.vk.frame.buffers[GetFrameIndex()]; } -static VkFence *GetFrameRenderFence() +static inline VkFence *GetFrameRenderFence() { return &renderer.vk.frame.render_fences[GetFrameIndex()]; } -static VkSemaphore GetFrameRenderSem() +static inline VkSemaphore GetFrameRenderSem() { return renderer.vk.frame.render_sems[GetFrameIndex()]; } -static VkSemaphore GetFrameSwapSem() +static inline VkSemaphore GetFrameSwapSem() { return renderer.vk.frame.swapchain_sems[GetFrameIndex()]; } -static u32 *GetFrameBufferCount() +static inline u32 *GetFrameBufferCount() { return &renderer.vk.frame.buffer_counts[GetFrameIndex()]; } -static RenderBuffer *GetFrameRenderBuffers() +static inline RenderBuffer *GetFrameRenderBuffers() { return renderer.vk.frame.buffer_destroy_queues[GetFrameIndex()]; } @@ -96,89 +87,6 @@ static void BeginRendering() vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.vk.pipe.pipeline_layout, 0, DESC_TYPE_MAX, renderer.vk.pipe.sets, 0, NULL); } -b32 BeginFrame() -{ - b32 success = true; - VkResult result; - - if (renderer.pending.resized) - ResizeSwapchain(); - - VkDevice device = renderer.vk.device; - VkSwapchainKHR swapchain = renderer.vk.swapchain; - VkCommandBuffer cmd = GetFrameCmdBuf(); - VkFence *fence = GetFrameRenderFence(); - VkSemaphore sc_sem = GetFrameSwapSem(); - VkSemaphore rndr_sem = GetFrameRenderSem(); - - // TODO(MA): make this work with VK_PRESENT_MODE_MAILBOX_KHR and remove assignment of present mode to FIFO - result = vkWaitForFences(device, 1, fence, VK_TRUE, 1000000000); - if (result != VK_SUCCESS) - { - Printf("vkWaitForFences failure: %s", VkResultStr(result)); - success = false; - } - - if (success) - { - u32 *buf_count = GetFrameBufferCount(); - if (*buf_count > 0) - { - RenderBuffer *buffers = GetFrameRenderBuffers(); - for (u32 i = 0; i < *buf_count; i++) - vmaDestroyBuffer(renderer.vk.alloc, buffers[i].buffer, buffers[i].alloc); - *buf_count = 0; - } - - result = vkResetFences(device, 1, fence); - if (result != VK_SUCCESS) - { - Printf("vkResetFences failure: %s", VkResultStr(result)); - success = false; - } - } - - if (success) - { - result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix); - if (result == VK_ERROR_OUT_OF_DATE_KHR) - ResizeSwapchain(); - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) - { - Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result)); - success = false; - } - } - - if (success) - { - result = vkResetCommandBuffer(cmd, 0); - if (result != VK_SUCCESS) - { - Printf("vkResetCommandBuffer failure: %s", VkResultStr(result)); - success = false; - } - } - - - if (success) - { - VkCommandBufferBeginInfo cmd_info = { - .sType = STYPE(COMMAND_BUFFER_BEGIN_INFO), - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, - }; - - result = vkBeginCommandBuffer(cmd, &cmd_info); - if (result != VK_SUCCESS) - { - Printf("vkBeginCommandBuffer failure: %s", VkResultStr(result)); - success = false; - } - } - - return success; -} - void ClearScreen() { @@ -200,214 +108,6 @@ static void DrawGUI(GUIContext *ctx) } -static void BindPipeline(PipelineHandle handle, PipelineType type) -{ - if (!renderer.frame_state.begin_rendering) - { - BeginRendering(); - renderer.frame_state.begin_rendering = true; - } - - VkCommandBuffer cmd = GetFrameCmdBuf(); - - vkCmdBindPipeline(cmd, (VkPipelineBindPoint)type, renderer.vk.pipe.pipelines[handle]); - - VkViewport viewport = { - .width = (f32)renderer.vk.sc.extent.width, - .height = (f32)renderer.vk.sc.extent.height, - .maxDepth = 1.0, - }; - - vkCmdSetViewport(cmd, 0, 1, &viewport); - - VkRect2D scissor = { - .extent = { - .width = renderer.vk.sc.extent.width, - .height = renderer.vk.sc.extent.height, - }, - }; - - vkCmdSetScissor(cmd, 0, 1, &scissor); -} - -static void DrawIndexed(u32 index_count, u32 instance_count) -{ - VkCommandBuffer cmd = GetFrameCmdBuf(); - - vkCmdDrawIndexed(cmd, index_count, instance_count, 0, 0, 0); -} - -void DrawTriangle() -{ - VkCommandBuffer cmd = GetFrameCmdBuf(); - - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.vk.pipe.pipelines[PIPELINE_CUBE]); - - - vkCmdDraw(cmd, 3, 1, 0, 0); -} - -b32 FinishFrame() -{ - if (!renderer.frame_state.begin_rendering) - Assert(false, "FinishFrame called without beginning rendering"); - - renderer.frame_state.begin_rendering = false; - - b32 success = true; - VkResult result; - - VkCommandBuffer cmd = GetFrameCmdBuf(); - VkSemaphore sc_sem = GetFrameSwapSem(); - VkSemaphore rndr_sem = GetFrameRenderSem(); - VkFence *fence = GetFrameRenderFence(); - VkImage curr_img = renderer.vk.sc.imgs[renderer.frame_state.img_ix]; - - vkCmdEndRendering(cmd); - - TransitionImage(cmd, &renderer.vk.sc.draw_img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - VkExtent2D extent = { - .width = renderer.vk.sc.extent.width, - .height = renderer.vk.sc.extent.height, - }; - - CopyImageToImage(cmd, renderer.vk.sc.draw_img.img, curr_img, extent, extent); - - TransitionImageLayout(cmd, curr_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - result = vkEndCommandBuffer(cmd); - if (result != VK_SUCCESS) - { - Printf("vkEndCommandBuffer failure: %s", VkResultStr(result)); - success = false; - } - - if (success) - { - VkCommandBufferSubmitInfo cmd_info = { - .sType = STYPE(COMMAND_BUFFER_SUBMIT_INFO), - .commandBuffer = cmd, - }; - - VkSemaphoreSubmitInfo wait_info = { - .sType = STYPE(SEMAPHORE_SUBMIT_INFO), - .semaphore = sc_sem, - .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, - .value = 1, - }; - - VkSemaphoreSubmitInfo signal_info = { - .sType = STYPE(SEMAPHORE_SUBMIT_INFO), - .semaphore = rndr_sem, - .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, - .value = 1, - }; - - VkSubmitInfo2 submit_info = { - .sType = STYPE(SUBMIT_INFO_2), - .waitSemaphoreInfoCount = 1, - .pWaitSemaphoreInfos = &wait_info, - .signalSemaphoreInfoCount = 1, - .pSignalSemaphoreInfos = &signal_info, - .commandBufferInfoCount = 1, - .pCommandBufferInfos = &cmd_info, - }; - - result = vkQueueSubmit2(renderer.vk.queues.graphics_queue, 1, &submit_info, *fence); - if (result != VK_SUCCESS) - { - Printf("vkQueueSubmit2 failure: %s", VkResultStr(result)); - success = false; - } - } - - if (success) - { - VkPresentInfoKHR present_info = { - .sType = STYPE(PRESENT_INFO_KHR), - .pSwapchains = &renderer.vk.swapchain, - .swapchainCount = 1, - .pWaitSemaphores = &rndr_sem, - .waitSemaphoreCount = 1, - .pImageIndices = &renderer.frame_state.img_ix, - }; - - result = vkQueuePresentKHR(renderer.vk.queues.graphics_queue, &present_info); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || renderer.pending.resized) - ResizeSwapchain(); - else if (result != VK_SUCCESS) - { - Printf("vkQueuePresentKHR failure: %s", VkResultStr(result)); - success = false; - } - } - - renderer.frame_state.prev_frame = renderer.frame_state.frame_cnt; - renderer.frame_state.frame_cnt++; - - return success; -} - -static void GetViewportSize(Vec2 *size) -{ - size->x = (f32)renderer.vk.sc.extent.width; - size->y = (f32)renderer.vk.sc.extent.height; -} - -static void SetGlobalUniform(ShaderGlobals *globals) -{ - -} - -static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count) -{ - VkDevice device = renderer.vk.device; - VmaAllocator alloc = renderer.vk.alloc; - u32 frame_index = renderer.frame_state.begin_rendering ? renderer.frame_state.frame_cnt : renderer.frame_state.prev_frame; - frame_index = frame_index % FRAME_OVERLAP; - - u32 *buf_count = &renderer.vk.frame.buffer_counts[frame_index]; - - // TODO: make this better at some point - for (u32 i = 0; i < buffer_count; i++) - { - renderer.vk.frame.buffer_destroy_queues[frame_index][*buf_count] = buffers[i]; - *buf_count += 1; - } -} - -static void SetPushConstants(PushConst *pc) -{ - VkCommandBuffer cmd = GetFrameCmdBuf(); - - vkCmdPushConstants(cmd, - renderer.vk.pipe.pipeline_layout, - VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT|VK_SHADER_STAGE_COMPUTE_BIT, - 0, - sizeof(PushConst), - pc); -} - -static void BindVertexBuffer(RenderBuffer *buffer) -{ - Assert(buffer && buffer->type == RENDER_BUFFER_TYPE_VERTEX, "BindVertexBuffer: invalid buffer provided"); - - VkCommandBuffer cmd = GetFrameCmdBuf(); - VkDeviceSize offsets = 0; - - vkCmdBindVertexBuffers(cmd, 0, 1, &buffer->buffer, &offsets); -} - -static void BindIndexBuffer(RenderBuffer *buffer) -{ - Assert(buffer && buffer->type == RENDER_BUFFER_TYPE_INDEX, "BindIndexBuffer: invalid buffer provided"); - - VkCommandBuffer cmd = GetFrameCmdBuf(); - - vkCmdBindIndexBuffer(cmd, buffer->buffer, 0, VK_INDEX_TYPE_UINT32); -} - static b32 BeginImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd) { b32 success = true; @@ -492,154 +192,6 @@ static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd, return success; } -static b32 CreateBuffer(RenderBuffer *buffer) -{ - Assert(buffer, "CreateBuffer: RenderBuffer must not be null"); - Assert(buffer->type != RENDER_BUFFER_TYPE_NONE, "CreateBuffer: RenderBuffer type must not be RENDER_BUFFER_TYPE_NONE"); - - b32 success = true; - VkResult result; - - DeviceQueues *queues = &renderer.vk.queues; - ImmediateStructures *imm = &renderer.vk.imm; - VmaAllocator alloc = renderer.vk.alloc; - - VkBufferCreateInfo buffer_info = { - .sType = STYPE(BUFFER_CREATE_INFO), - .size = (VkDeviceSize)buffer->size, - }; - - VmaAllocationCreateInfo alloc_info = { - .usage = VMA_MEMORY_USAGE_UNKNOWN, - .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, - }; - - switch (buffer->type) - { - case RENDER_BUFFER_TYPE_VERTEX: - { - buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } break; - case RENDER_BUFFER_TYPE_INDEX: - { - buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } break; - case RENDER_BUFFER_TYPE_UNIFORM: - { - buffer_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT; - alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - } break; - case RENDER_BUFFER_TYPE_STAGING: - { - buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - } break; - case RENDER_BUFFER_TYPE_STORAGE: - { - buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT; - alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } break; - case RENDER_BUFFER_TYPE_NONE: - default: - Assert(false, "CreateBuffer: Unknown buffer type provided"); - } - - if (queues->graphics != queues->transfer) - { - buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; - buffer_info.queueFamilyIndexCount = 2; - buffer_info.pQueueFamilyIndices = (u32[]){queues->graphics, queues->transfer}; - } - - result = vmaCreateBuffer(alloc, &buffer_info, &alloc_info, &buffer->buffer, &buffer->alloc, &buffer->info); - if (result != VK_SUCCESS) - { - Printfln("vmaCreateBuffer failure: %s", VkResultStr(result)); - success = false; - } - - return success; -} - -static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr) -{ - Assert(buffer, "UploadToBuffer: buffer must not be null"); - Assert(ptr, "UploadToBuffer: ptr must not be null"); - - b32 success = true; - - ImmediateStructures *imm = &renderer.vk.imm; - VkDevice device = renderer.vk.device; - VkQueue queue = renderer.vk.queues.transfer_queue; - VmaAllocator alloc = renderer.vk.alloc; - rawptr mapped_buffer = NULL; - - b32 host_visible = buffer->type & HOST_VISIBLE_BUFFERS; - - if (host_visible) - { - vmaMapMemory(alloc, buffer->alloc, &mapped_buffer); - MemCpy(mapped_buffer, ptr, buffer->size); - } - else - { - RenderBuffer staging_buffer = { .type = RENDER_BUFFER_TYPE_STAGING, .size = buffer->size }; - - success = CreateBuffer(&staging_buffer); - - b32 buffer_created = success; - - if (success) - { - vmaMapMemory(alloc, staging_buffer.alloc, &mapped_buffer); - MemCpy(mapped_buffer, ptr, staging_buffer.size); - } - - if (success) - success = BeginImmSubmit(device, &imm->fence, imm->cmd); - - b32 imm_started = success; - - if (success) - { - VkBufferCopy buffer_copy = { .size = (VkDeviceSize)buffer->size }; - vkCmdCopyBuffer(imm->cmd, staging_buffer.buffer, buffer->buffer, 1, &buffer_copy); - } - - if (imm_started) - FinishImmSubmit(device, &imm->fence, imm->cmd, queue); - - if (buffer_created) - { - vmaUnmapMemory(alloc, staging_buffer.alloc); - vmaDestroyBuffer(alloc, staging_buffer.buffer, staging_buffer.alloc); - } - } - - return success; -} - -static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr) -{ - b32 success = true; - - success = CreateBuffer(buffer); - - if (success) - success = UploadToBuffer(buffer, ptr); - - return success; -} static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx) { @@ -647,13 +199,6 @@ static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx) return success; } -static void SetRenderResolution(u32 x, u32 y) -{ - renderer.pending.render_width = x; - renderer.pending.render_height = y; - renderer.pending.resized = true; -} - /** * BACK END API END @@ -760,50 +305,6 @@ static void TransitionImage(VkCommandBuffer cmd, Image *img, VkImageLayout new) // INIT -static b32 InitVulkan(Arena *arena) -{ - CustomizePipelines(); - - Assert(arena != NULL, "Vulkan memory is null"); - renderer.perm_arena = arena; - void *mem = ArenaAlloc(arena, MB(8)); - renderer.arena = CreateArena(mem, MB(8)); - - Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions"); - { - VkResult result = vkCreateInstance(&inst_info, NULL, &renderer.vk.inst); - if (result != VK_SUCCESS) - { - Printfln("vkCreateInstance failure: %s", VkResultStr(result)); - assert(false && "Failed to initialize 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(CreateSwapchain(), "Unable to initialize swapchain and draw images"); - Assert(CreateDrawImages(), "Unable to create draw images"); - Assert(CreateFrameStructures(), "Unable to create frame structures"); - Assert(CreateImmediateStructures(), "Unable to create immediate structures"); - Assert(CreateDescriptors(), "Unable to initialize descriptors."); - Assert(CreatePipelines(), "Unable to initialize pipelines."); - - ArenaFree(renderer.arena); - - return true; -} - static b32 CreateVmaAllocator() { VmaVulkanFunctions vk_functions = { @@ -1124,7 +625,7 @@ static b32 InitVkDeviceFunctions() { #ifdef __linux__ static b32 CreateSurface() { - GameWindow *window = GetWindowPtr(); + PlatformWindow *window = GetPlatformWindow(); VkXcbSurfaceCreateInfoKHR surface_info = { .sType = STYPE(XCB_SURFACE_CREATE_INFO_KHR), .connection = window->connection, @@ -1143,7 +644,7 @@ static b32 CreateSurface() { b32 success = true; - GameWindow *window = GetWindowPtr(); + PlatformWindow *window = GetPlatformWindow(); VkWin32SurfaceCreateInfoKHR surface_info = { .sType = STYPE(WIN32_SURFACE_CREATE_INFO_KHR), .hinstance = window->instance, @@ -1279,6 +780,9 @@ static b32 CreateSwapchain() VkPhysicalDevice phys_device = renderer.vk.phys_device; VkDevice device = renderer.vk.device; VkSurfaceKHR surface = renderer.vk.surface; + VkPresentModeKHR present_mode = renderer.vk.sc.present_mode; + VkFormat format = renderer.vk.sc.format; + VkColorSpaceKHR color_space = renderer.vk.sc.color_space; VkSurfaceCapabilitiesKHR capabilities; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities); @@ -1292,35 +796,38 @@ static b32 CreateSwapchain() extent.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); - u32 format_count; - vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL); - VkSurfaceFormatKHR *formats = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * format_count); - vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, formats); - renderer.vk.sc.format = formats[0].format; - renderer.vk.sc.color_space = formats[0].colorSpace; - - u32 present_count; - vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, NULL); - VkPresentModeKHR *present_modes = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * present_count); - vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, present_modes); - - VkPresentModeKHR present_mode; - for (u32 i = 0; i < present_count; i++) + if (present_mode == INT_MAX || format == INT_MAX || color_space == INT_MAX) { - if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) - { - present_mode = VK_PRESENT_MODE_MAILBOX_KHR; - break; - } - } + u32 format_count; + vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL); + VkSurfaceFormatKHR *formats = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * format_count); + vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, formats); - if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR) - present_mode = VK_PRESENT_MODE_FIFO_KHR; + format = formats[0].format; + color_space = formats[0].colorSpace; + + u32 present_count; + vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, NULL); + VkPresentModeKHR *present_modes = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * present_count); + vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, present_modes); + + for (u32 i = 0; i < present_count; i++) + { + if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) + { + present_mode = VK_PRESENT_MODE_MAILBOX_KHR; + break; + } + } + + if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR) + present_mode = VK_PRESENT_MODE_FIFO_KHR; + } swapchain_create_info.minImageCount = capabilities.minImageCount + 1; swapchain_create_info.surface = surface; - swapchain_create_info.imageFormat = renderer.vk.sc.format; - swapchain_create_info.imageColorSpace = renderer.vk.sc.color_space; + swapchain_create_info.imageFormat = format; + swapchain_create_info.imageColorSpace = color_space; swapchain_create_info.imageExtent = extent; swapchain_create_info.preTransform = capabilities.currentTransform; swapchain_create_info.presentMode = present_mode; @@ -1339,13 +846,16 @@ static b32 CreateSwapchain() for (u32 i = 0; i < image_count; i++) { sc_image_view_create_info.image = sc_images[i]; - sc_image_view_create_info.format = renderer.vk.sc.format; + sc_image_view_create_info.format = format; result = vkCreateImageView(device, &sc_image_view_create_info, NULL, &sc_views[i]); if (result != VK_SUCCESS) success = false; } + renderer.vk.sc.format = format; + renderer.vk.sc.color_space = color_space; + renderer.vk.sc.present_mode = present_mode; renderer.vk.sc.imgs = sc_images; renderer.vk.sc.views = sc_views; renderer.vk.sc.img_count = image_count; @@ -1628,68 +1138,6 @@ static void DestroyDrawImages() vmaDestroyImage(vma_alloc, sc->depth_img.img, sc->depth_img.alloc); } -static void DestroyVulkan() -{ - VkDevice device = renderer.vk.device; - VkInstance instance = renderer.vk.inst; - FrameStructures data = renderer.vk.frame; - ImmediateStructures imm = renderer.vk.imm; - SwapchainStructures sc = renderer.vk.sc; - VmaAllocator vma_alloc = renderer.vk.alloc; - VkSwapchainKHR swapchain = renderer.vk.swapchain; - PipelineStructures pipe = renderer.vk.pipe; - - vkDeviceWaitIdle(device); - - for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++) - vkDestroyPipeline(device, pipe.pipelines[i], NULL); - - vkDestroyPipelineLayout(device, pipe.pipeline_layout, NULL); - - for (u32 i = DESC_TYPE_SHARED; i < DESC_TYPE_MAX; i++) - vkDestroyDescriptorSetLayout(device, pipe.layouts[i], NULL); - - vkDestroyDescriptorPool(device, pipe.pool, NULL); - - DestroyDrawImages(); - - DestroySwapchain(); - - vkDestroyFence(device, imm.fence, NULL); - vkFreeCommandBuffers(device, imm.pool, 1, &imm.cmd); - 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); - - if (data.buffer_counts[i] > 0) - { - for (u32 j = 0; j < data.buffer_counts[i]; j++) - vmaDestroyBuffer(renderer.vk.alloc, data.buffer_destroy_queues[i][j].buffer, data.buffer_destroy_queues[i][j].alloc); - } - } - - 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); - - ArenaFree(renderer.arena); - ArenaFree(renderer.perm_arena); -} - void VkInfo(const char *str) { Printfln("[INFO] %s", str); diff --git a/src/render_vulkan.h b/src/renderer_vulkan.h similarity index 95% rename from src/render_vulkan.h rename to src/renderer_vulkan.h index 5012b2c..b2c92dd 100644 --- a/src/render_vulkan.h +++ b/src/renderer_vulkan.h @@ -242,6 +242,7 @@ typedef struct { typedef struct { VkFormat format; VkColorSpaceKHR color_space; + VkPresentModeKHR present_mode; VkExtent3D extent; VkImage *imgs; VkImageView *views; @@ -307,7 +308,6 @@ const char *VkResultStr(VkResult result); // Init static b32 LoadVulkanLib(); -static b32 InitVulkan(Arena *arena); static b32 InitVkInstanceFunctions(); static b32 InitVkGlobalFunctions(); static b32 CreateSurface(); @@ -328,12 +328,14 @@ static b32 CreatePipelines(); static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module); // Util -static VkCommandBuffer GetFrameCmdBuf(); -static VkFence *GetFrameRenderFence(); -static VkSemaphore GetFrameRenderSem(); -static VkSemaphore GetFrameSwapSem(); -static u32 GetFrameIndex(); -static VkImage GetFrameSwapImage(); +static inline VkCommandBuffer GetFrameCmdBuf(); +static inline VkFence *GetFrameRenderFence(); +static inline VkSemaphore GetFrameRenderSem(); +static inline VkSemaphore GetFrameSwapSem(); +static inline u32 GetFrameIndex(); +static inline VkImage GetFrameSwapImage(); +static inline u32 *GetFrameBufferCount(); +static inline RenderBuffer *GetFrameRenderBuffers(); static void BeginRendering(); // Immediate Submit @@ -344,7 +346,6 @@ static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd, static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx); // Destroy -static void DestroyVulkan(); static void DestroySwapchain(); static void DestroyDrawImages(); @@ -372,7 +373,12 @@ static Renderer renderer = { .queues = { .graphics = -1, .transfer = -1, - } + }, + .sc = { + .format = INT_MAX, + .color_space = INT_MAX, + .present_mode = INT_MAX, + }, } }; diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c new file mode 100644 index 0000000..c88d06b --- /dev/null +++ b/src/renderer_vulkan_public.c @@ -0,0 +1,583 @@ +/* + * ::Initialization::Start:: + */ +b32 InitRenderer(Arena *arena) +{ + CustomizePipelines(); + + Assert(arena != NULL, "Vulkan memory is null"); + renderer.perm_arena = arena; + void *mem = ArenaAlloc(arena, MB(8)); + renderer.arena = CreateArena(mem, MB(8)); + + Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions"); + { + VkResult result = vkCreateInstance(&inst_info, NULL, &renderer.vk.inst); + if (result != VK_SUCCESS) + { + Printfln("vkCreateInstance failure: %s", VkResultStr(result)); + assert(false && "Failed to initialize 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(CreateSwapchain(), "Unable to initialize swapchain and draw images"); + Assert(CreateDrawImages(), "Unable to create draw images"); + Assert(CreateFrameStructures(), "Unable to create frame structures"); + Assert(CreateImmediateStructures(), "Unable to create immediate structures"); + Assert(CreateDescriptors(), "Unable to initialize descriptors."); + Assert(CreatePipelines(), "Unable to initialize pipelines."); + + ArenaFree(renderer.arena); + + return true; + + return true; +} + +void DestroyRenderer() +{ + VkDevice device = renderer.vk.device; + VkInstance instance = renderer.vk.inst; + FrameStructures data = renderer.vk.frame; + ImmediateStructures imm = renderer.vk.imm; + SwapchainStructures sc = renderer.vk.sc; + VmaAllocator vma_alloc = renderer.vk.alloc; + VkSwapchainKHR swapchain = renderer.vk.swapchain; + PipelineStructures pipe = renderer.vk.pipe; + + vkDeviceWaitIdle(device); + + for (u32 i = PIPELINE_CUBE; i < PIPELINE_MAX; i++) + vkDestroyPipeline(device, pipe.pipelines[i], NULL); + + vkDestroyPipelineLayout(device, pipe.pipeline_layout, NULL); + + for (u32 i = DESC_TYPE_SHARED; i < DESC_TYPE_MAX; i++) + vkDestroyDescriptorSetLayout(device, pipe.layouts[i], NULL); + + vkDestroyDescriptorPool(device, pipe.pool, NULL); + + DestroyDrawImages(); + + DestroySwapchain(); + + vkDestroyFence(device, imm.fence, NULL); + vkFreeCommandBuffers(device, imm.pool, 1, &imm.cmd); + 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); + + if (data.buffer_counts[i] > 0) + { + for (u32 j = 0; j < data.buffer_counts[i]; j++) + vmaDestroyBuffer(renderer.vk.alloc, data.buffer_destroy_queues[i][j].buffer, data.buffer_destroy_queues[i][j].alloc); + } + } + + 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); + + ArenaFree(renderer.arena); + ArenaFree(renderer.perm_arena); +} + +/* + * ::Initialization::End:: + */ + +/* + * ::Buffers::Start:: + */ + +static b32 CreateBuffer(RenderBuffer *buffer) +{ + Assert(buffer, "CreateBuffer: RenderBuffer must not be null"); + Assert(buffer->type != RENDER_BUFFER_TYPE_NONE, "CreateBuffer: RenderBuffer type must not be RENDER_BUFFER_TYPE_NONE"); + + b32 success = true; + VkResult result; + + DeviceQueues *queues = &renderer.vk.queues; + ImmediateStructures *imm = &renderer.vk.imm; + VmaAllocator alloc = renderer.vk.alloc; + + VkBufferCreateInfo buffer_info = { + .sType = STYPE(BUFFER_CREATE_INFO), + .size = (VkDeviceSize)buffer->size, + }; + + VmaAllocationCreateInfo alloc_info = { + .usage = VMA_MEMORY_USAGE_UNKNOWN, + .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, + }; + + switch (buffer->type) + { + case RENDER_BUFFER_TYPE_VERTEX: + { + buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } break; + case RENDER_BUFFER_TYPE_INDEX: + { + buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } break; + case RENDER_BUFFER_TYPE_UNIFORM: + { + buffer_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } break; + case RENDER_BUFFER_TYPE_STAGING: + { + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } break; + case RENDER_BUFFER_TYPE_STORAGE: + { + buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } break; + case RENDER_BUFFER_TYPE_NONE: + default: + Assert(false, "CreateBuffer: Unknown buffer type provided"); + } + + if (queues->graphics != queues->transfer) + { + buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_info.queueFamilyIndexCount = 2; + buffer_info.pQueueFamilyIndices = (u32[]){queues->graphics, queues->transfer}; + } + + result = vmaCreateBuffer(alloc, &buffer_info, &alloc_info, &buffer->buffer, &buffer->alloc, &buffer->info); + if (result != VK_SUCCESS) + { + Printfln("vmaCreateBuffer failure: %s", VkResultStr(result)); + success = false; + } + + return success; +} + +static b32 UploadToBuffer(RenderBuffer *buffer, rawptr ptr) +{ + Assert(buffer, "UploadToBuffer: buffer must not be null"); + Assert(ptr, "UploadToBuffer: ptr must not be null"); + + b32 success = true; + + ImmediateStructures *imm = &renderer.vk.imm; + VkDevice device = renderer.vk.device; + VkQueue queue = renderer.vk.queues.transfer_queue; + VmaAllocator alloc = renderer.vk.alloc; + rawptr mapped_buffer = NULL; + + b32 host_visible = buffer->type & HOST_VISIBLE_BUFFERS; + + if (host_visible) + { + vmaMapMemory(alloc, buffer->alloc, &mapped_buffer); + MemCpy(mapped_buffer, ptr, buffer->size); + } + else + { + RenderBuffer staging_buffer = { .type = RENDER_BUFFER_TYPE_STAGING, .size = buffer->size }; + + success = CreateBuffer(&staging_buffer); + + b32 buffer_created = success; + + if (success) + { + vmaMapMemory(alloc, staging_buffer.alloc, &mapped_buffer); + MemCpy(mapped_buffer, ptr, staging_buffer.size); + } + + if (success) + success = BeginImmSubmit(device, &imm->fence, imm->cmd); + + b32 imm_started = success; + + if (success) + { + VkBufferCopy buffer_copy = { .size = (VkDeviceSize)buffer->size }; + vkCmdCopyBuffer(imm->cmd, staging_buffer.buffer, buffer->buffer, 1, &buffer_copy); + } + + if (imm_started) + FinishImmSubmit(device, &imm->fence, imm->cmd, queue); + + if (buffer_created) + { + vmaUnmapMemory(alloc, staging_buffer.alloc); + vmaDestroyBuffer(alloc, staging_buffer.buffer, staging_buffer.alloc); + } + } + + return success; +} + +static b32 CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr) +{ + b32 success = true; + + success = CreateBuffer(buffer); + + if (success) + success = UploadToBuffer(buffer, ptr); + + return success; +} + +static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count) +{ + VkDevice device = renderer.vk.device; + VmaAllocator alloc = renderer.vk.alloc; + u32 frame_index = renderer.frame_state.begin_rendering ? renderer.frame_state.frame_cnt : renderer.frame_state.prev_frame; + frame_index = frame_index % FRAME_OVERLAP; + + u32 *buf_count = &renderer.vk.frame.buffer_counts[frame_index]; + + // TODO: make this better at some point + for (u32 i = 0; i < buffer_count; i++) + { + renderer.vk.frame.buffer_destroy_queues[frame_index][*buf_count] = buffers[i]; + *buf_count += 1; + } +} + +static void BindVertexBuffer(RenderBuffer *buffer) +{ + Assert(buffer && buffer->type == RENDER_BUFFER_TYPE_VERTEX, "BindVertexBuffer: invalid buffer provided"); + + VkCommandBuffer cmd = GetFrameCmdBuf(); + VkDeviceSize offsets = 0; + + vkCmdBindVertexBuffers(cmd, 0, 1, &buffer->buffer, &offsets); +} + +static void BindIndexBuffer(RenderBuffer *buffer) +{ + Assert(buffer && buffer->type == RENDER_BUFFER_TYPE_INDEX, "BindIndexBuffer: invalid buffer provided"); + + VkCommandBuffer cmd = GetFrameCmdBuf(); + + vkCmdBindIndexBuffer(cmd, buffer->buffer, 0, VK_INDEX_TYPE_UINT32); +} + +/* + * ::Buffers::End:: + */ + +/* + * ::Uniforms::Start:: ::PushConstants::Start:: + */ + +static void GetViewportSize(Vec2 *size) +{ + size->x = (f32)renderer.vk.sc.extent.width; + size->y = (f32)renderer.vk.sc.extent.height; +} + +static void SetGlobalUniform(ShaderGlobals *globals) +{ + +} + +static void SetPushConstants(PushConst *pc) +{ + VkCommandBuffer cmd = GetFrameCmdBuf(); + + vkCmdPushConstants(cmd, + renderer.vk.pipe.pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT|VK_SHADER_STAGE_COMPUTE_BIT, + 0, + sizeof(PushConst), + pc); +} + +/* + * ::Uniforms::End:: ::PushConstants::End:: + */ + +/* + * ::Config::Start:: + */ + +static void SetRenderResolution(u32 x, u32 y) +{ + renderer.pending.render_width = x; + renderer.pending.render_height = y; + renderer.pending.resized = true; +} + +/* + * ::Config::End:: + */ + +/* + * ::Rendering::Start:: + */ + +b32 BeginFrame() +{ + b32 success = true; + VkResult result; + + if (renderer.pending.resized) + ResizeSwapchain(); + + VkDevice device = renderer.vk.device; + VkSwapchainKHR swapchain = renderer.vk.swapchain; + VkCommandBuffer cmd = GetFrameCmdBuf(); + VkFence *fence = GetFrameRenderFence(); + VkSemaphore sc_sem = GetFrameSwapSem(); + VkSemaphore rndr_sem = GetFrameRenderSem(); + + // TODO(MA): make this work with VK_PRESENT_MODE_MAILBOX_KHR and remove assignment of present mode to FIFO + result = vkWaitForFences(device, 1, fence, VK_TRUE, 1000000000); + if (result != VK_SUCCESS) + { + Printf("vkWaitForFences failure: %s", VkResultStr(result)); + success = false; + } + + if (success) + { + u32 *buf_count = GetFrameBufferCount(); + if (*buf_count > 0) + { + RenderBuffer *buffers = GetFrameRenderBuffers(); + for (u32 i = 0; i < *buf_count; i++) + vmaDestroyBuffer(renderer.vk.alloc, buffers[i].buffer, buffers[i].alloc); + *buf_count = 0; + } + + result = vkResetFences(device, 1, fence); + if (result != VK_SUCCESS) + { + Printf("vkResetFences failure: %s", VkResultStr(result)); + success = false; + } + } + + if (success) + { + result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &renderer.frame_state.img_ix); + if (result == VK_ERROR_OUT_OF_DATE_KHR) + ResizeSwapchain(); + else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) + { + Printf("vkAcquireNextImageKHR failure: %s", VkResultStr(result)); + success = false; + } + } + + if (success) + { + result = vkResetCommandBuffer(cmd, 0); + if (result != VK_SUCCESS) + { + Printf("vkResetCommandBuffer failure: %s", VkResultStr(result)); + success = false; + } + } + + + if (success) + { + VkCommandBufferBeginInfo cmd_info = { + .sType = STYPE(COMMAND_BUFFER_BEGIN_INFO), + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + + result = vkBeginCommandBuffer(cmd, &cmd_info); + if (result != VK_SUCCESS) + { + Printf("vkBeginCommandBuffer failure: %s", VkResultStr(result)); + success = false; + } + } + + return success; +} + +b32 FinishFrame() +{ + if (!renderer.frame_state.begin_rendering) + Assert(false, "FinishFrame called without beginning rendering"); + + renderer.frame_state.begin_rendering = false; + + b32 success = true; + VkResult result; + + VkCommandBuffer cmd = GetFrameCmdBuf(); + VkSemaphore sc_sem = GetFrameSwapSem(); + VkSemaphore rndr_sem = GetFrameRenderSem(); + VkFence *fence = GetFrameRenderFence(); + VkImage curr_img = renderer.vk.sc.imgs[renderer.frame_state.img_ix]; + + vkCmdEndRendering(cmd); + + TransitionImage(cmd, &renderer.vk.sc.draw_img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + VkExtent2D extent = { + .width = renderer.vk.sc.extent.width, + .height = renderer.vk.sc.extent.height, + }; + + CopyImageToImage(cmd, renderer.vk.sc.draw_img.img, curr_img, extent, extent); + + TransitionImageLayout(cmd, curr_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + result = vkEndCommandBuffer(cmd); + if (result != VK_SUCCESS) + { + Printf("vkEndCommandBuffer failure: %s", VkResultStr(result)); + success = false; + } + + if (success) + { + VkCommandBufferSubmitInfo cmd_info = { + .sType = STYPE(COMMAND_BUFFER_SUBMIT_INFO), + .commandBuffer = cmd, + }; + + VkSemaphoreSubmitInfo wait_info = { + .sType = STYPE(SEMAPHORE_SUBMIT_INFO), + .semaphore = sc_sem, + .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + .value = 1, + }; + + VkSemaphoreSubmitInfo signal_info = { + .sType = STYPE(SEMAPHORE_SUBMIT_INFO), + .semaphore = rndr_sem, + .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, + .value = 1, + }; + + VkSubmitInfo2 submit_info = { + .sType = STYPE(SUBMIT_INFO_2), + .waitSemaphoreInfoCount = 1, + .pWaitSemaphoreInfos = &wait_info, + .signalSemaphoreInfoCount = 1, + .pSignalSemaphoreInfos = &signal_info, + .commandBufferInfoCount = 1, + .pCommandBufferInfos = &cmd_info, + }; + + result = vkQueueSubmit2(renderer.vk.queues.graphics_queue, 1, &submit_info, *fence); + if (result != VK_SUCCESS) + { + Printf("vkQueueSubmit2 failure: %s", VkResultStr(result)); + success = false; + } + } + + if (success) + { + VkPresentInfoKHR present_info = { + .sType = STYPE(PRESENT_INFO_KHR), + .pSwapchains = &renderer.vk.swapchain, + .swapchainCount = 1, + .pWaitSemaphores = &rndr_sem, + .waitSemaphoreCount = 1, + .pImageIndices = &renderer.frame_state.img_ix, + }; + + result = vkQueuePresentKHR(renderer.vk.queues.graphics_queue, &present_info); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || renderer.pending.resized) + ResizeSwapchain(); + else if (result != VK_SUCCESS) + { + Printf("vkQueuePresentKHR failure: %s", VkResultStr(result)); + success = false; + } + } + + renderer.frame_state.prev_frame = renderer.frame_state.frame_cnt; + renderer.frame_state.frame_cnt++; + + return success; +} + +static void DrawIndexed(u32 index_count, u32 instance_count) +{ + VkCommandBuffer cmd = GetFrameCmdBuf(); + + vkCmdDrawIndexed(cmd, index_count, instance_count, 0, 0, 0); +} + +static void BindPipeline(PipelineHandle handle, PipelineType type) +{ + if (!renderer.frame_state.begin_rendering) + { + BeginRendering(); + renderer.frame_state.begin_rendering = true; + } + + VkCommandBuffer cmd = GetFrameCmdBuf(); + + vkCmdBindPipeline(cmd, (VkPipelineBindPoint)type, renderer.vk.pipe.pipelines[handle]); + + VkViewport viewport = { + .width = (f32)renderer.vk.sc.extent.width, + .height = (f32)renderer.vk.sc.extent.height, + .maxDepth = 1.0, + }; + + vkCmdSetViewport(cmd, 0, 1, &viewport); + + VkRect2D scissor = { + .extent = { + .width = renderer.vk.sc.extent.width, + .height = renderer.vk.sc.extent.height, + }, + }; + + vkCmdSetScissor(cmd, 0, 1, &scissor); +} + +/* + * ::Rendering::End:: + */