some refactoring + cleanup of swapchain parameter selecetion
This commit is contained in:
parent
e4519e3b4a
commit
0f14ffd37f
@ -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)
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -87,11 +87,6 @@ b32 CreatePlatformWindow()
|
|||||||
return _CreateWindow();
|
return _CreateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
GameWindow *GetWindowPtr()
|
|
||||||
{
|
|
||||||
return _GetWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowSize GetWindowSize()
|
WindowSize GetWindowSize()
|
||||||
{
|
{
|
||||||
return _GetWindowSize();
|
return _GetWindowSize();
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
@ -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
|
||||||
@ -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);
|
||||||
@ -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,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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