some refactoring + cleanup of swapchain parameter selecetion
This commit is contained in:
parent
e4519e3b4a
commit
0f14ffd37f
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -87,11 +87,6 @@ b32 CreatePlatformWindow()
|
||||
return _CreateWindow();
|
||||
}
|
||||
|
||||
GameWindow *GetWindowPtr()
|
||||
{
|
||||
return _GetWindow();
|
||||
}
|
||||
|
||||
WindowSize GetWindowSize()
|
||||
{
|
||||
return _GetWindowSize();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <xcb/xcb.h>
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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,19 +796,21 @@ 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);
|
||||
|
||||
if (present_mode == INT_MAX || format == INT_MAX || color_space == INT_MAX)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
VkPresentModeKHR present_mode;
|
||||
for (u32 i = 0; i < present_count; i++)
|
||||
{
|
||||
if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
@ -1316,11 +822,12 @@ static b32 CreateSwapchain()
|
||||
|
||||
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);
|
||||
@ -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,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
583
src/renderer_vulkan_public.c
Normal file
583
src/renderer_vulkan_public.c
Normal 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::
|
||||
*/
|
||||
Loading…
x
Reference in New Issue
Block a user