some refactoring + cleanup of swapchain parameter selecetion

This commit is contained in:
Matthew 2025-03-23 10:28:12 +11:00
parent e4519e3b4a
commit 0f14ffd37f
16 changed files with 658 additions and 630 deletions

View File

@ -5,7 +5,7 @@
#include "platform.c" #include "platform.c"
#include "util.c" #include "util.c"
#include "arena.c" #include "arena.c"
#include "render.c" #include "renderer.c"
#include "game.c" #include "game.c"
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@ -12,7 +12,7 @@
#include "platform.h" #include "platform.h"
#include "util.h" #include "util.h"
#include "arena.h" #include "arena.h"
#include "render.h" #include "renderer.h"
#include "game.h" #include "game.h"
int main(int argc, char **argv); int main(int argc, char **argv);

View File

@ -5,7 +5,7 @@
#include "platform.c" #include "platform.c"
#include "util.c" #include "util.c"
#include "arena.c" #include "arena.c"
#include "render.c" #include "renderer.c"
#include "game.c" #include "game.c"
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code) int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code)

View File

@ -12,7 +12,7 @@
#include "platform.h" #include "platform.h"
#include "util.h" #include "util.h"
#include "arena.h" #include "arena.h"
#include "render.h" #include "renderer.h"
#include "game.h" #include "game.h"
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code); int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int show_code);

View File

@ -87,11 +87,6 @@ b32 CreatePlatformWindow()
return _CreateWindow(); return _CreateWindow();
} }
GameWindow *GetWindowPtr()
{
return _GetWindow();
}
WindowSize GetWindowSize() WindowSize GetWindowSize()
{ {
return _GetWindowSize(); return _GetWindowSize();

View File

@ -1,6 +1,6 @@
// TODO(MA): Do stuff for general unix platforms some day // TODO(MA): Do stuff for general unix platforms some day
static GameWindow linux_window = { static PlatformWindow linux_window = {
.w = 1920, .w = 1920,
.h = 1080, .h = 1080,
}; };
@ -139,7 +139,7 @@ isize _GetPageSize()
b32 _CreateWindow() b32 _CreateWindow()
{ {
GameWindow *window = &linux_window; PlatformWindow *window = &linux_window;
window->display = XOpenDisplay(NULL); window->display = XOpenDisplay(NULL);
if (!window->display) if (!window->display)
@ -245,7 +245,7 @@ b32 _CreateWindow()
return true; return true;
} }
GameWindow *_GetWindow() { PlatformWindow *GetPlatformWindow() {
return &linux_window; return &linux_window;
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
@ -47,7 +48,7 @@ typedef struct {
xcb_atom_t close_event; xcb_atom_t close_event;
xcb_atom_t minimize_event; xcb_atom_t minimize_event;
u16 w, h; u16 w, h;
} GameWindow; } PlatformWindow;
typedef struct { typedef struct {
void *lib; void *lib;
@ -77,7 +78,6 @@ i32 _EPrintf(const char *fmt, va_list arg);
// Window Functions // Window Functions
b32 _CreateWindow(); b32 _CreateWindow();
GameWindow *_GetWindow();
void GetWindowEvents(GameInput *inputs, u32 *i_count); void GetWindowEvents(GameInput *inputs, u32 *i_count);
b32 WaitForWindowEvent(GameInput *input); b32 WaitForWindowEvent(GameInput *input);
WindowSize _GetWindowSize(); WindowSize _GetWindowSize();

View File

@ -1,5 +1,5 @@
HINSTANCE win32_instance = {0}; HINSTANCE win32_instance = {0};
GameWindow win32_window = {0}; PlatformWindow win32_window = {0};
b32 global_quit = false; b32 global_quit = false;
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
@ -176,7 +176,7 @@ b32 _CreateWindow()
return success; return success;
} }
GameWindow *_GetWindow() PlatformWindow *GetPlatformWindow()
{ {
return &win32_window; return &win32_window;
} }

View File

@ -17,7 +17,7 @@ typedef struct
HWND handle; HWND handle;
u16 h, w; u16 h, w;
b32 resize_requested; b32 resize_requested;
} GameWindow; } PlatformWindow;
typedef struct typedef struct
{ {
@ -38,7 +38,6 @@ i32 _Printfln(const char *fmt, va_list arg);
i32 _EPrintf(const char *fmt, va_list arg); i32 _EPrintf(const char *fmt, va_list arg);
b32 _CreateWindow(); b32 _CreateWindow();
GameWindow *_GetWindow();
void GetWindowEvents(); void GetWindowEvents();
void WaitForWindowEvent(); void WaitForWindowEvent();
WindowSize _GetWindowSize(); WindowSize _GetWindowSize();

View File

@ -1,5 +1,5 @@
#if STG_VULKAN_RENDERER #if STG_VULKAN_RENDERER
#include "render_vulkan.c" #include "renderer_vulkan.c"
#endif #endif
#if STG_OPENGL_RENDERER #if STG_OPENGL_RENDERER
@ -11,6 +11,6 @@
#endif #endif
#if STG_DX11_RENDERER && __linux__ #if STG_DX11_RENDERER && __linux__
#include "render_d3d11.c" #include "renderer_d3d11.c"
#endif #endif

View File

@ -77,11 +77,8 @@ static b32 FinishFrame();
static void DrawIndexed(u32 index_count, u32 instance_count); static void DrawIndexed(u32 index_count, u32 instance_count);
static void BindPipeline(PipelineHandle handle, PipelineType type); static void BindPipeline(PipelineHandle handle, PipelineType type);
// Placeholders (Remove me)
static void DrawTriangle();
#if STG_VULKAN_RENDERER #if STG_VULKAN_RENDERER
#include "render_vulkan.h" #include "renderer_vulkan.h"
#endif #endif
#if STG_OPENGL_RENDERER #if STG_OPENGL_RENDERER
@ -93,5 +90,5 @@ static void DrawTriangle();
#endif #endif
#if STG_DX11_RENDERER && __linux__ #if STG_DX11_RENDERER && __linux__
#include "render_d3d11.h" #include "renderer_d3d11.h"
#endif #endif

View File

@ -3,49 +3,40 @@
*/ */
// TODO(MA): Make separate functions for debug/non debug builds for readability // 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() static inline u32 GetFrameIndex()
{
DestroyVulkan();
}
static u32 GetFrameIndex()
{ {
return renderer.frame_state.frame_cnt % FRAME_OVERLAP; return renderer.frame_state.frame_cnt % FRAME_OVERLAP;
} }
static VkCommandBuffer GetFrameCmdBuf() static inline VkCommandBuffer GetFrameCmdBuf()
{ {
return renderer.vk.frame.buffers[GetFrameIndex()]; return renderer.vk.frame.buffers[GetFrameIndex()];
} }
static VkFence *GetFrameRenderFence() static inline VkFence *GetFrameRenderFence()
{ {
return &renderer.vk.frame.render_fences[GetFrameIndex()]; return &renderer.vk.frame.render_fences[GetFrameIndex()];
} }
static VkSemaphore GetFrameRenderSem() static inline VkSemaphore GetFrameRenderSem()
{ {
return renderer.vk.frame.render_sems[GetFrameIndex()]; return renderer.vk.frame.render_sems[GetFrameIndex()];
} }
static VkSemaphore GetFrameSwapSem() static inline VkSemaphore GetFrameSwapSem()
{ {
return renderer.vk.frame.swapchain_sems[GetFrameIndex()]; return renderer.vk.frame.swapchain_sems[GetFrameIndex()];
} }
static u32 *GetFrameBufferCount() static inline u32 *GetFrameBufferCount()
{ {
return &renderer.vk.frame.buffer_counts[GetFrameIndex()]; return &renderer.vk.frame.buffer_counts[GetFrameIndex()];
} }
static RenderBuffer *GetFrameRenderBuffers() static inline RenderBuffer *GetFrameRenderBuffers()
{ {
return renderer.vk.frame.buffer_destroy_queues[GetFrameIndex()]; 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); 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() 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) static b32 BeginImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd)
{ {
b32 success = true; b32 success = true;
@ -492,154 +192,6 @@ static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd,
return success; 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) static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx)
{ {
@ -647,13 +199,6 @@ static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx)
return success; 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 * BACK END API END
@ -760,50 +305,6 @@ static void TransitionImage(VkCommandBuffer cmd, Image *img, VkImageLayout new)
// INIT // 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() static b32 CreateVmaAllocator()
{ {
VmaVulkanFunctions vk_functions = { VmaVulkanFunctions vk_functions = {
@ -1124,7 +625,7 @@ static b32 InitVkDeviceFunctions() {
#ifdef __linux__ #ifdef __linux__
static b32 CreateSurface() static b32 CreateSurface()
{ {
GameWindow *window = GetWindowPtr(); PlatformWindow *window = GetPlatformWindow();
VkXcbSurfaceCreateInfoKHR surface_info = { VkXcbSurfaceCreateInfoKHR surface_info = {
.sType = STYPE(XCB_SURFACE_CREATE_INFO_KHR), .sType = STYPE(XCB_SURFACE_CREATE_INFO_KHR),
.connection = window->connection, .connection = window->connection,
@ -1143,7 +644,7 @@ static b32 CreateSurface()
{ {
b32 success = true; b32 success = true;
GameWindow *window = GetWindowPtr(); PlatformWindow *window = GetPlatformWindow();
VkWin32SurfaceCreateInfoKHR surface_info = { VkWin32SurfaceCreateInfoKHR surface_info = {
.sType = STYPE(WIN32_SURFACE_CREATE_INFO_KHR), .sType = STYPE(WIN32_SURFACE_CREATE_INFO_KHR),
.hinstance = window->instance, .hinstance = window->instance,
@ -1279,6 +780,9 @@ static b32 CreateSwapchain()
VkPhysicalDevice phys_device = renderer.vk.phys_device; VkPhysicalDevice phys_device = renderer.vk.phys_device;
VkDevice device = renderer.vk.device; VkDevice device = renderer.vk.device;
VkSurfaceKHR surface = renderer.vk.surface; 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; VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities);
@ -1292,19 +796,21 @@ static b32 CreateSwapchain()
extent.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); extent.width = u32Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); extent.height = u32Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
if (present_mode == INT_MAX || format == INT_MAX || color_space == INT_MAX)
{
u32 format_count; u32 format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL); vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, NULL);
VkSurfaceFormatKHR *formats = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * format_count); VkSurfaceFormatKHR *formats = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, formats); vkGetPhysicalDeviceSurfaceFormatsKHR(phys_device, surface, &format_count, formats);
renderer.vk.sc.format = formats[0].format;
renderer.vk.sc.color_space = formats[0].colorSpace; format = formats[0].format;
color_space = formats[0].colorSpace;
u32 present_count; u32 present_count;
vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, NULL); vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, NULL);
VkPresentModeKHR *present_modes = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * present_count); VkPresentModeKHR *present_modes = ArenaAlloc(renderer.arena, sizeof(VkSurfaceFormatKHR) * present_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, present_modes); vkGetPhysicalDeviceSurfacePresentModesKHR(phys_device, surface, &present_count, present_modes);
VkPresentModeKHR present_mode;
for (u32 i = 0; i < present_count; i++) for (u32 i = 0; i < present_count; i++)
{ {
if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
@ -1316,11 +822,12 @@ static b32 CreateSwapchain()
if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR) if (present_mode != VK_PRESENT_MODE_MAILBOX_KHR)
present_mode = VK_PRESENT_MODE_FIFO_KHR; present_mode = VK_PRESENT_MODE_FIFO_KHR;
}
swapchain_create_info.minImageCount = capabilities.minImageCount + 1; swapchain_create_info.minImageCount = capabilities.minImageCount + 1;
swapchain_create_info.surface = surface; swapchain_create_info.surface = surface;
swapchain_create_info.imageFormat = renderer.vk.sc.format; swapchain_create_info.imageFormat = format;
swapchain_create_info.imageColorSpace = renderer.vk.sc.color_space; swapchain_create_info.imageColorSpace = color_space;
swapchain_create_info.imageExtent = extent; swapchain_create_info.imageExtent = extent;
swapchain_create_info.preTransform = capabilities.currentTransform; swapchain_create_info.preTransform = capabilities.currentTransform;
swapchain_create_info.presentMode = present_mode; swapchain_create_info.presentMode = present_mode;
@ -1339,13 +846,16 @@ static b32 CreateSwapchain()
for (u32 i = 0; i < image_count; i++) for (u32 i = 0; i < image_count; i++)
{ {
sc_image_view_create_info.image = sc_images[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]); result = vkCreateImageView(device, &sc_image_view_create_info, NULL, &sc_views[i]);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
success = false; 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.imgs = sc_images;
renderer.vk.sc.views = sc_views; renderer.vk.sc.views = sc_views;
renderer.vk.sc.img_count = image_count; 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); 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) void VkInfo(const char *str)
{ {
Printfln("[INFO] %s", str); Printfln("[INFO] %s", str);

View File

@ -242,6 +242,7 @@ typedef struct {
typedef struct { typedef struct {
VkFormat format; VkFormat format;
VkColorSpaceKHR color_space; VkColorSpaceKHR color_space;
VkPresentModeKHR present_mode;
VkExtent3D extent; VkExtent3D extent;
VkImage *imgs; VkImage *imgs;
VkImageView *views; VkImageView *views;
@ -307,7 +308,6 @@ const char *VkResultStr(VkResult result);
// Init // Init
static b32 LoadVulkanLib(); static b32 LoadVulkanLib();
static b32 InitVulkan(Arena *arena);
static b32 InitVkInstanceFunctions(); static b32 InitVkInstanceFunctions();
static b32 InitVkGlobalFunctions(); static b32 InitVkGlobalFunctions();
static b32 CreateSurface(); static b32 CreateSurface();
@ -328,12 +328,14 @@ static b32 CreatePipelines();
static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module); static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module);
// Util // Util
static VkCommandBuffer GetFrameCmdBuf(); static inline VkCommandBuffer GetFrameCmdBuf();
static VkFence *GetFrameRenderFence(); static inline VkFence *GetFrameRenderFence();
static VkSemaphore GetFrameRenderSem(); static inline VkSemaphore GetFrameRenderSem();
static VkSemaphore GetFrameSwapSem(); static inline VkSemaphore GetFrameSwapSem();
static u32 GetFrameIndex(); static inline u32 GetFrameIndex();
static VkImage GetFrameSwapImage(); static inline VkImage GetFrameSwapImage();
static inline u32 *GetFrameBufferCount();
static inline RenderBuffer *GetFrameRenderBuffers();
static void BeginRendering(); static void BeginRendering();
// Immediate Submit // Immediate Submit
@ -344,7 +346,6 @@ static b32 FinishImmSubmit(VkDevice device, VkFence *fence, VkCommandBuffer cmd,
static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx); static b32 UploadGUIBuffer(MeshBuffer *buf, GUIContext *ctx);
// Destroy // Destroy
static void DestroyVulkan();
static void DestroySwapchain(); static void DestroySwapchain();
static void DestroyDrawImages(); static void DestroyDrawImages();
@ -372,7 +373,12 @@ static Renderer renderer = {
.queues = { .queues = {
.graphics = -1, .graphics = -1,
.transfer = -1, .transfer = -1,
} },
.sc = {
.format = INT_MAX,
.color_space = INT_MAX,
.present_mode = INT_MAX,
},
} }
}; };

View File

@ -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::
*/