// ::Vulkan::Renderer::Initialization::Functions::Start:: b32 rInit() { rThreadCountSet(pCPUCountGet()); vInitArenas(); vCustomizePipelines(); Assert(vInitInstance(), "Unable to initialize instance"); Assert(vInstanceFunctionsInit(), "Unable to initialize instance functions"); #ifdef BUILD_DEBUG { vEnableDebug(); } #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(vInitBuffers(), "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; vBufferAllocPtrArray buffers = v_Renderer.buffers.perm; vImmHandlesArray imm = v_Renderer.imm_handles; 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; vkDeviceWaitIdle(device); 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(); for (u32 i = 0; i < async.count; i++) { vImmHandles ih = imm.data[i]; vkDestroyFence(device, ih.fence, NULL); vkFreeCommandBuffers(device, ih.pool, 1, &ih.buffer); vkDestroyCommandPool(device, ih.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 rBuffer rBufferCreate(rRenderBufferType type, u64 size) { rBuffer buffer = NULL; return buffer; } static b32 rBufferCreateOLD(rRenderBufferType type, u64 size) { Assert(type != rRBT_NONE, "rBufferCreate: rRenderBuffer type must not be rRBT_NONE"); b32 success = true; VkResult result; u32 gfx_queue = v_Renderer.state.vk.gfx_queue_idx; u32 tfer_queue = v_Renderer.state.vk.tfer_queue_idx; VmaAllocator alloc = v_Renderer.handles.vma_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 (type) { case rRBT_VERTEX: { buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } break; case rRBT_INDEX: { buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } break; case rRBT_UNIFORM: { buffer_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; } break; case rRBT_STAGING: { buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } break; case rRBT_STORAGE: { buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } break; default: break; } if ((type & rRBT_HOST) == rRBT_HOST || type == rRBT_STAGING) { alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; alloc_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; } else { buffer_info.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } if (tfer_queue != gfx_queue) { buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; buffer_info.queueFamilyIndexCount = 2; buffer_info.pQueueFamilyIndices = (u32[]){gfx_queue, tfer_queue}; } //result = vmaCreateBuffer(alloc, &buffer_info, &alloc_info, &buffer->buffer, &buffer->alloc, &buffer->info); //if (result != VK_SUCCESS) //{ //Printfln("vmaCreateBuffer failure: %s", vVkResultStr(result)); //} return success; } static b32 rBufferUpload(rRenderBuffer **buffers, rawptr *ptrs, u32 count, u32 thr_ix) { // TODO: replace /* Assert(buffers, "rBufferUpload: buffer must not be null"); Assert(ptrs, "rBufferUpload: ptr must not be null"); b32 success = true; VkCommandBuffer cmd = renderer.vk.imm.cmds[thr_ix]; VkFence fence = renderer.vk.imm.fences[thr_ix]; VkDevice device = v_Renderer.handles.device; VkQueue queue = renderer.vk.queues.transfer_queue; VmaAllocator alloc = v_Renderer.handles.vma_alloc; rawptr mapped_buffers[16] = {0}; rRenderBuffer staging_buffers[16] = {0}; u32 copy_count = 0; b32 imm_started = success = vImmSubmitBegin(device, fence, cmd); for (u32 i = 0; i < count && success; i++) { b32 host_visible = buffers[i]->type & HOST_VISIBLE_BUFFERS; if (host_visible) { vmaMapMemory(alloc, buffers[i]->alloc, &mapped_buffers[i]); MemCpy(mapped_buffers[i], ptrs[i], buffers[i]->size); } else { staging_buffers[copy_count].type = rRBT_STAGING; staging_buffers[copy_count].size = buffers[i]->size; //success = rBufferCreate(&staging_buffers[i]); if (success) { vmaMapMemory(alloc, staging_buffers[i].alloc, &mapped_buffers[i]); MemCpy(mapped_buffers[i], ptrs[i], staging_buffers[i].size); VkBufferCopy buffer_copy = { .size = (VkDeviceSize)buffers[i]->size }; vkCmdCopyBuffer(cmd, staging_buffers[i].buffer, buffers[i]->buffer, 1, &buffer_copy); copy_count += 1; } } } vImmSubmitFinish(device, fence, cmd, queue); vkWaitForFences(device, 1, &fence, VK_TRUE, 999999999); for (u32 i = 0; i < copy_count; i++) { vmaUnmapMemory(alloc, staging_buffers[i].alloc); vmaDestroyBuffer(alloc, staging_buffers[i].buffer, staging_buffers[i].alloc); } */ return false; } static void rBufferCreateAndUpload(rRenderBuffer *buffer, rawptr ptr) { // TODO: replace /* TicketMutLock(&renderer.upload_queues[vDT_MATERIAL].ticket_mut); u32 job_idx = JobQueueAdd(&renderer.upload_queues[vDT_MATERIAL].job_queue, 1); renderer.upload_queues[vDT_MATERIAL].queued_buffers[job_idx] = buffer; renderer.upload_queues[vDT_MATERIAL].data[job_idx] = ptr; TicketMutUnlock(&renderer.upload_queues[vDT_MATERIAL].ticket_mut); */ vLoaderWake(); } static rDescHandle rTextureCreateAndUpload(TextureAsset asset_id) { rDescHandle handle = 0; // TODO: replace it /* vAssetInfo *info = vDescHandleSearch(vDT_SAMPLED_IMAGE, asset_id); if (info == NULL) { Asset asset = apLoadTexture(asset_id); rTextureBuffer *buffer = FLMemAlloc(sizeof(rTextureBuffer)); buffer->type = rTBT_SAMPLER; buffer->width = asset.texture_meta.w; buffer->height = asset.texture_meta.h; buffer->channels = asset.texture_meta.ch; TicketMutLock(&renderer.upload_queues[vDT_SAMPLED_IMAGE].ticket_mut); u32 job_idx = JobQueueAdd(&renderer.upload_queues[vDT_SAMPLED_IMAGE].job_queue, 1); renderer.upload_queues[vDT_SAMPLED_IMAGE].queued_textures[job_idx] = buffer; renderer.upload_queues[vDT_SAMPLED_IMAGE].data[job_idx] = asset.bytes; handle = vDescHandlePop(vDT_SAMPLED_IMAGE); TicketMutUnlock(&renderer.upload_queues[vDT_SAMPLED_IMAGE].ticket_mut); vLoaderWake(); } else { handle = info->handle; } */ return handle; } static void rBufferFree(rRenderBuffer *buffers, u32 buffer_count) { VkDevice device = v_Renderer.handles.device; VmaAllocator alloc = v_Renderer.handles.vma_alloc; u32 frame_index = vFrameIndex(); // TODO: replace it //for (u32 i = 0; i < buffer_count; i++) //{ // *buf_count += 1; //} } 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 rAssetHandle rTextureLoad(TextureAsset asset_id) { rAssetHandle handle = 0; return handle; } static void WaitForBufferQueue() { for (u32 i = 0; i < vDT_MAX; i++) { // TODO: replace /* while (!JobQueueCompleted(&renderer.upload_queues[vDT_MATERIAL].job_queue)) { if (v_Renderer.state.renderer.height > 0) vLoaderWake(); } */ } } static void rBufferQueueReset() { for (u32 i = 0; i < vDT_MAX; i++) { // TODO: replace //JobQueueReset(&renderer.upload_queues[i].job_queue); } } 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; } static void rThreadCountSet(u32 n) { v_Renderer.async.count = n; } // ::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(); // 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) { // TODO: replace /* u32 *buf_count = vFrameBufferCount(); if (*buf_count > 0) { rRenderBuffer *buffers = vFrameRenderBuffers(); for (u32 i = 0; i < *buf_count; i++) vmaDestroyBuffer(v_Renderer.handles.vma_alloc, buffers[i].buffer, buffers[i].alloc); *buf_count = 0; } */ 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; 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::