Gears-C/src/renderer_vulkan_public.c
2025-05-19 15:58:49 +10:00

485 lines
13 KiB
C

// ::Vulkan::Renderer::Initialization::Functions::Start::
b32 rInit()
{
vArenasInit();
vCustomizePipelines();
Assert(vInitInstance(), "Unable to initialize instance");
Assert(vInstanceFunctionsInit(), "Unable to initialize instance functions");
#ifdef BUILD_DEBUG
{
vEnableDebug();
//vRenderDocInit();
}
#endif
Assert(vSurfaceInit(), "Unable to create surface");
Assert(vDeviceInit(), "Unable to create device");
Assert(vVmaAllocatorInit(), "Unable to create VMA allocator");
Assert(vSwapchainInit(), "Unable to initialize swapchain and draw images");
Assert(vDrawImagesInit(), "Unable to create draw images");
Assert(vFrameStructuresInit(), "Unable to create frame structures");
Assert(vImmediateStructuresInit(), "Unable to create immediate structures");
Assert(vDescriptorsInit(), "Unable to initialize descriptors.");
Assert(vPipelinesInit(), "Unable to initialize pipelines.");
Assert(vBuffersInit(), "Unable to initialize buffers.");
vUploadQueuesInit();
vLoaderStartThreads();
ArenaFree(vFrameArena());
return true;
}
void rDestroy()
{
VkDevice device = v_Renderer.handles.device;
VkInstance instance = v_Renderer.handles.inst;
vBufferAllocPtrArray *frame_buffers = v_Renderer.buffers.frame_buffers;
vImmHandles imm = v_Renderer.imm;
VmaAllocator vma_alloc = v_Renderer.handles.vma_alloc;
VkSwapchainKHR swapchain = v_Renderer.handles.swapchain;
VkPipeline *pipelines = v_Renderer.handles.pipelines;
VkPipelineLayout pipeline_layout = v_Renderer.handles.pipeline_layout;
VkDescriptorSetLayout *desc_layouts = v_Renderer.handles.desc_layouts;
VkDescriptorPool desc_pool = v_Renderer.handles.desc_pool;
vAsync async = v_Renderer.async;
VkSampler nearest_sampler = v_Renderer.handles.nearest_sampler;
vkDeviceWaitIdle(device);
vkDestroySampler(device, nearest_sampler, NULL);
for (u32 i = R_PIPELINE_CUBE; i < R_PIPELINE_MAX; i++)
vkDestroyPipeline(device, pipelines[i], NULL);
vkDestroyPipelineLayout(device, pipeline_layout, NULL);
for (u32 i = vDT_SHARED; i < vDT_MAX; i++)
vkDestroyDescriptorSetLayout(device, desc_layouts[i], NULL);
vkDestroyDescriptorPool(device, desc_pool, NULL);
vDrawImagesDestroy();
vSwapchainDestroy();
vkDestroyFence(device, imm.fence, NULL);
vkFreeCommandBuffers(device, imm.pool, 1, &imm.buffer);
vkDestroyCommandPool(device, imm.pool, NULL);
for (u32 i = 0; i < FRAME_OVERLAP; i++)
{
vFrameHandles fh = v_Renderer.frame_handles[i];
vkDestroySemaphore(device, fh.r_sem, NULL);
vkDestroySemaphore(device, fh.sc_sem, NULL);
vkDestroyFence(device, fh.r_fence, NULL);
vkFreeCommandBuffers(device, fh.pool, 1, &fh.buffer);
vkDestroyCommandPool(device, fh.pool, NULL);
for (u32 j = 0; j < frame_buffers[i].length; j++)
vmaDestroyBuffer(vma_alloc, frame_buffers[i].data[j]->buffer, frame_buffers[i].data[j]->alloc);
}
vmaUnmapMemory(vma_alloc, v_Renderer.buffers.transfer.alloc.alloc);
vmaUnmapMemory(vma_alloc, v_Renderer.buffers.gui_vert.alloc.alloc);
vmaUnmapMemory(vma_alloc, v_Renderer.buffers.gui_idx.alloc.alloc);
vmaDestroyBuffer(vma_alloc, v_Renderer.buffers.transfer.alloc.buffer, v_Renderer.buffers.transfer.alloc.alloc);
vmaDestroyBuffer(vma_alloc, v_Renderer.buffers.gui_vert.alloc.buffer, v_Renderer.buffers.gui_vert.alloc.alloc);
vmaDestroyBuffer(vma_alloc, v_Renderer.buffers.gui_idx.alloc.buffer, v_Renderer.buffers.gui_idx.alloc.alloc);
vmaDestroyAllocator(v_Renderer.handles.vma_alloc);
vkDestroyDevice(v_Renderer.handles.device, NULL);
vkDestroySurfaceKHR(v_Renderer.handles.inst, v_Renderer.handles.surface, NULL);
#ifdef BUILD_DEBUG
{
vkDestroyDebugUtilsMessengerEXT(v_Renderer.handles.inst, v_Renderer.handles.debug, NULL);
}
#endif
vkDestroyInstance(v_Renderer.handles.inst, NULL);
for (u32 i = 0; i < FRAME_OVERLAP; i++)
{
ArenaFree(v_Renderer.mem.frame_arenas[i]);
}
ArenaFree(v_Renderer.mem.perm_arena);
}
// ::Vulkan::Renderer::Initialization::Functions::End::
// ::Vulkan::Renderer::Buffers::Functions::Start::
static rDescHandle rTextureLoad(TextureAsset asset_id)
{
rDescHandle handle = vDescHandleSearch(vDT_SAMPLED_IMAGE, asset_id);
if (handle.asset_id == UINT32_MAX)
{
vImageView *view = FLMemAlloc(sizeof(vImageView));
Asset asset = apLoadTexture(asset_id);
TextureAssetMeta meta = apGetTextureMeta(asset_id);
// TODO: handle errors instead of failing
Assert(vImageViewInit(view, meta.w, meta.h, meta.ch), "rTextureLoad failure: vImageViewInit failed");
handle.asset_id = asset_id;
handle.desc_index = vDescPushImage(view);
TicketMutLock(&v_Renderer.upload.mut);
vTransfer *transfer = vTextureTransferInit(vFrameArena(), asset_id, view->image.image, asset.bytes, &meta);
u32 job_idx = JobQueueAdd(&v_Renderer.upload.job_queue, 1);
v_Renderer.upload.transfers[job_idx] = transfer;
vDescPushImageAndHandle(handle, view);
TicketMutUnlock(&v_Renderer.upload.mut);
vLoaderWake();
}
return handle;
}
static void rTextureUnload(rDescHandle current_handle)
{
rDescHandle handle = vDescHandleSearch(vDT_SAMPLED_IMAGE, current_handle.asset_id);
if (handle.asset_id != UINT32_MAX)
{
b8 *queue = vFrameTexDestroyQueue();
queue[current_handle.asset_id] = true;
}
}
static void rBufferBindVertex(rRenderBuffer *buffer)
{
Assert(buffer && buffer->type == rRBT_VERTEX, "rBufferBindVertex: invalid buffer provided");
VkCommandBuffer cmd = vFrameCmdBuf();
VkDeviceSize offsets = 0;
vkCmdBindVertexBuffers(cmd, 0, 1, &buffer->buffer, &offsets);
}
static void rBufferBindIndex(rRenderBuffer *buffer)
{
Assert(buffer && buffer->type == rRBT_INDEX, "rBufferBindIndex: invalid buffer provided");
VkCommandBuffer cmd = vFrameCmdBuf();
vkCmdBindIndexBuffer(cmd, buffer->buffer, 0, VK_INDEX_TYPE_UINT32);
}
static void vBufferQueueWait()
{
while (!JobQueueCompleted(&v_Renderer.upload.job_queue))
{
if (v_Renderer.async.sleeping)
vLoaderWake();
}
}
static rawptr rBufferGUIVertMapping()
{
return v_Renderer.buffers.gui_vert.ptr;
}
static rawptr rBufferGUIIdxMapping()
{
return v_Renderer.buffers.gui_idx.ptr;
}
static void rBufferBindGUIVertex()
{
VkCommandBuffer cmd = vFrameCmdBuf();
VkDeviceSize offsets = 0;
VkBuffer buffer = v_Renderer.buffers.gui_vert.alloc.buffer;
vkCmdBindVertexBuffers(cmd, 0, 1, &buffer, &offsets);
}
static void rBufferBindGUIIndex()
{
VkCommandBuffer cmd = vFrameCmdBuf();
VkBuffer buffer = v_Renderer.buffers.gui_idx.alloc.buffer;
vkCmdBindIndexBuffer(cmd, buffer, 0, VK_INDEX_TYPE_UINT32);
}
// ::Vulkan::Renderer::Buffers::Functions::End::
// ::Vulkan::Renderer::Uniforms::Functions::Start::
// ::Vulkan::Renderer::PushConstants::Functions::Start::
static void rViewportSize(Vec2 *size)
{
size->x = (f32)v_Renderer.state.swapchain.extent.width;
size->y = (f32)v_Renderer.state.swapchain.extent.height;
}
static void rGlobalUniformSet(rShaderGlobals *globals)
{
}
static void rPushConstantsSet(rPushConst *pc)
{
VkCommandBuffer cmd = vFrameCmdBuf();
vkCmdPushConstants(cmd,
v_Renderer.handles.pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT|VK_SHADER_STAGE_COMPUTE_BIT,
0,
sizeof(rPushConst),
pc);
}
// ::Vulkan::Renderer::Uniforms::Functions::End::
// ::Vulkan::Renderer::PushConstants::Functions::End::
// ::Vulkan::Renderer::Config::Functions::Start::
static void rResolutionSet(u32 x, u32 y)
{
v_Renderer.state.renderer.width = x;
v_Renderer.state.renderer.height = y;
}
// ::Vulkan::Renderer::Config::Functions::End::
// ::Vulkan::Renderer::Rendering::Functions::Start::
b32 rFrameBegin()
{
b32 success = true;
VkResult result;
VkDevice device = v_Renderer.handles.device;
VkSwapchainKHR swapchain = v_Renderer.handles.swapchain;
VkCommandBuffer cmd = vFrameCmdBuf();
VkFence fence = vFrameRenderFence();
VkSemaphore sc_sem = vFrameSwapSem();
VkSemaphore rndr_sem = vFrameRenderSem();
#ifdef RDOC_ENABLED
if (!v_rdoc_captured)
v_rdoc_api->StartFrameCapture(device, pWindowGet());
#endif
// 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", vVkResultStr(result));
success = false;
}
if (success)
{
result = vkResetFences(device, 1, &fence);
if (result != VK_SUCCESS)
{
Printf("vkResetFences failure: %s", vVkResultStr(result));
success = false;
}
}
if (success)
{
result = vkAcquireNextImageKHR(device, swapchain, 1000000000, sc_sem, 0, &v_Renderer.state.vk.image_idx);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
vSwapchainResize();
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
Printf("vkAcquireNextImageKHR failure: %s", vVkResultStr(result));
success = false;
}
}
if (success)
{
result = vkResetCommandBuffer(cmd, 0);
if (result != VK_SUCCESS)
{
Printf("vkResetCommandBuffer failure: %s", vVkResultStr(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", vVkResultStr(result));
success = false;
}
if (success)
vRenderingBegin();
}
return success;
}
b32 rFrameFinish()
{
b32 success = true;
VkResult result;
VkCommandBuffer cmd = vFrameCmdBuf();
VkSemaphore sc_sem = vFrameSwapSem();
VkSemaphore rndr_sem = vFrameRenderSem();
VkFence fence = vFrameRenderFence();
VkImage curr_img = vFrameImage();
vkCmdEndRendering(cmd);
vImageTransition(cmd, &v_Renderer.images.draw.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkExtent2D extent = {
.width = v_Renderer.state.swapchain.extent.width,
.height = v_Renderer.state.swapchain.extent.height,
};
vImageCopyToImage(cmd, v_Renderer.images.draw.image.image, curr_img, extent, extent);
vImageTransitionLayout(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", vVkResultStr(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(v_Renderer.handles.gfx_queue, 1, &submit_info, fence);
if (result != VK_SUCCESS)
{
Printf("vkQueueSubmit2 failure: %s", vVkResultStr(result));
success = false;
}
}
if (success)
{
VkPresentInfoKHR present_info = {
.sType = STYPE(PRESENT_INFO_KHR),
.pSwapchains = &v_Renderer.handles.swapchain,
.swapchainCount = 1,
.pWaitSemaphores = &rndr_sem,
.waitSemaphoreCount = 1,
.pImageIndices = &v_Renderer.state.vk.image_idx,
};
result = vkQueuePresentKHR(v_Renderer.handles.gfx_queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
vSwapchainResize();
else if (result != VK_SUCCESS)
{
Printf("vkQueuePresentKHR failure: %s", vVkResultStr(result));
success = false;
}
}
v_Renderer.state.renderer.frame_count += 1;
#ifdef RDOC_ENABLED
if (!v_rdoc_captured)
{
v_rdoc_api->EndFrameCapture(v_Renderer.handles.device, pWindowGet());
}
#endif
return success;
}
static void rDrawIndexed(u32 index_count, u32 instance_count)
{
VkCommandBuffer cmd = vFrameCmdBuf();
vkCmdDrawIndexed(cmd, index_count, instance_count, 0, 0, 0);
}
static void rPipelineBind(rPipelineHandle handle, rPipelineType type)
{
VkCommandBuffer cmd = vFrameCmdBuf();
vkCmdBindPipeline(cmd, (VkPipelineBindPoint)type, v_Renderer.handles.pipelines[handle]);
VkViewport viewport = {
.width = (f32)v_Renderer.state.swapchain.extent.width,
.height = (f32)v_Renderer.state.swapchain.extent.height,
.maxDepth = 1.0,
};
vkCmdSetViewport(cmd, 0, 1, &viewport);
VkRect2D scissor = {
.extent = {
.width = v_Renderer.state.swapchain.extent.width,
.height = v_Renderer.state.swapchain.extent.height,
},
};
vkCmdSetScissor(cmd, 0, 1, &scissor);
}
// ::Vulkan::Renderer::Rendering::Functions::End::