From 1114210039e3ef74eb397ab152f2abf7b5eff0e1 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Thu, 12 Aug 2021 22:40:40 -0700 Subject: [PATCH] Create Vulkan semaphores for swapchain synchronization --- kraken/KRContext.cpp | 76 +++++++++++++++++++++++++++++++++++++++++-- kraken/KRContext.h | 7 ++-- kraken/KRPipeline.cpp | 7 +++- kraken/KRPipeline.h | 3 +- 4 files changed, 86 insertions(+), 7 deletions(-) diff --git a/kraken/KRContext.cpp b/kraken/KRContext.cpp index c4c782d..2a2bd61 100755 --- a/kraken/KRContext.cpp +++ b/kraken/KRContext.cpp @@ -47,6 +47,8 @@ int KRContext::KRENGINE_SYS_PAGE_SIZE; #endif +std::mutex KRContext::g_SurfaceInfoMutex; +std::mutex KRContext::g_DeviceInfoMutex; const char *KRContext::extension_names[KRENGINE_NUM_EXTENSIONS] = { "GL_EXT_texture_storage" @@ -783,6 +785,7 @@ KRContext::createDeviceContexts() void KRContext::destroyDeviceContexts() { + const std::lock_guard lock(KRContext::g_DeviceInfoMutex); for (auto itr = m_devices.begin(); itr != m_devices.end(); itr++) { DeviceInfo* deviceInfo = &(*itr).second; vkDestroyCommandPool(deviceInfo->logicalDevice, deviceInfo->graphicsCommandPool, nullptr); @@ -803,6 +806,7 @@ KRContext::destroySurfaces() if (m_vulkanInstance == VK_NULL_HANDLE) { return; } + const std::lock_guard surfaceLock(KRContext::g_SurfaceInfoMutex); for (auto itr = m_surfaces.begin(); itr != m_surfaces.end(); itr++) { SurfaceInfo& surfaceInfo = (*itr).second; DeviceInfo& deviceInfo = GetDeviceInfo(surfaceInfo.deviceHandle); @@ -810,8 +814,9 @@ KRContext::destroySurfaces() vkDestroyFramebuffer(deviceInfo.logicalDevice, framebuffer, nullptr); } vkDestroySwapchainKHR(deviceInfo.logicalDevice, surfaceInfo.swapChain, nullptr); + vkDestroySemaphore(deviceInfo.logicalDevice, surfaceInfo.renderFinishedSemaphore, nullptr); + vkDestroySemaphore(deviceInfo.logicalDevice, surfaceInfo.imageAvailableSemaphore, nullptr); vkDestroySurfaceKHR(m_vulkanInstance, surfaceInfo.surface, nullptr); - } m_surfaces.clear(); m_surfaceHandleMap.clear(); @@ -918,13 +923,15 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW return KR_ERROR_NO_DEVICE; } + const std::lock_guard surfaceLock(KRContext::g_SurfaceInfoMutex); + const std::lock_guard deviceLock(KRContext::g_DeviceInfoMutex); + DeviceInfo* deviceInfo = nullptr; #ifdef WIN32 HWND hWnd = static_cast(createWindowSurfaceInfo->hWnd); SurfaceInfo info{}; - info.surfaceHandle = createWindowSurfaceInfo->surfaceHandle; info.hWnd = hWnd; VkWin32SurfaceCreateInfoKHR createInfo{}; @@ -951,6 +958,18 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW return KR_ERROR_NO_DEVICE; } + VkSemaphoreCreateInfo semaphoreInfo{}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + if (vkCreateSemaphore(deviceInfo->logicalDevice, &semaphoreInfo, nullptr, &info.imageAvailableSemaphore) != VK_SUCCESS) { + vkDestroySurfaceKHR(m_vulkanInstance, info.surface, nullptr); + return KR_ERROR_VULKAN; + } + if (vkCreateSemaphore(deviceInfo->logicalDevice, &semaphoreInfo, nullptr, &info.renderFinishedSemaphore) != VK_SUCCESS) { + vkDestroySemaphore(deviceInfo->logicalDevice, info.imageAvailableSemaphore, nullptr); + vkDestroySurfaceKHR(m_vulkanInstance, info.surface, nullptr); + return KR_ERROR_VULKAN; + } + VkSurfaceCapabilitiesKHR surfaceCapabilities{}; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(deviceInfo->device, info.surface, &surfaceCapabilities); @@ -1039,6 +1058,8 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE; if (vkCreateSwapchainKHR(deviceInfo->logicalDevice, &swapChainCreateInfo, nullptr, &info.swapChain) != VK_SUCCESS) { + vkDestroySemaphore(deviceInfo->logicalDevice, info.renderFinishedSemaphore, nullptr); + vkDestroySemaphore(deviceInfo->logicalDevice, info.imageAvailableSemaphore, nullptr); vkDestroySurfaceKHR(m_vulkanInstance, info.surface, nullptr); return KR_ERROR_VULKAN_SWAP_CHAIN; } @@ -1069,6 +1090,8 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW for (size_t j = 0; j < i; j++) { vkDestroyImageView(deviceInfo->logicalDevice, info.swapChainImageViews[j], nullptr); } + vkDestroySemaphore(deviceInfo->logicalDevice, info.renderFinishedSemaphore, nullptr); + vkDestroySemaphore(deviceInfo->logicalDevice, info.imageAvailableSemaphore, nullptr); vkDestroySurfaceKHR(m_vulkanInstance, info.surface, nullptr); return KR_ERROR_VULKAN_SWAP_CHAIN; } @@ -1094,7 +1117,7 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = testPipeline->GetRenderPass(); + framebufferInfo.renderPass = testPipeline->getRenderPass(); framebufferInfo.attachmentCount = 1; framebufferInfo.pAttachments = attachments; framebufferInfo.width = surface.swapChainExtent.width; @@ -1140,6 +1163,8 @@ KrResult KRContext::deleteWindowSurface(const KrDeleteWindowSurfaceInfo* deleteW vkDestroyImageView(deviceInfo.logicalDevice, imageView, nullptr); } vkDestroySwapchainKHR(deviceInfo.logicalDevice, surfaceInfo->swapChain, nullptr); + vkDestroySemaphore(deviceInfo.logicalDevice, surfaceInfo->renderFinishedSemaphore, nullptr); + vkDestroySemaphore(deviceInfo.logicalDevice, surfaceInfo->imageAvailableSemaphore, nullptr); vkDestroySurfaceKHR(m_vulkanInstance, surfaceInfo->surface, nullptr); m_surfaces.erase(itr); return KR_SUCCESS; @@ -1166,7 +1191,49 @@ void KRContext::presentationThreadFunc() void KRContext::renderFrame() { + // TODO - Eliminate this and use system wide index once Vulkan path is working + static uint64_t frameIndex = 0; + // TODO - We should use fences to eliminate this mutex + const std::lock_guard surfaceLock(KRContext::g_SurfaceInfoMutex); + + for (auto surfaceItr = m_surfaces.begin(); surfaceItr != m_surfaces.end(); surfaceItr++) { + SurfaceInfo& surface = (*surfaceItr).second; + DeviceInfo& device = GetDeviceInfo(surface.deviceHandle); + // TODO - this will break with more than one surface... Expect to refactor this out + VkCommandBuffer commandBuffer = device.graphicsCommandBuffers[frameIndex % device.graphicsCommandBuffers.size()]; + KRPipeline* testPipeline = m_pPipelineManager->get("simple_blit"); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = 0; + beginInfo.pInheritanceInfo = nullptr; + + if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { + // TODO - Add error handling... + } + + VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = testPipeline->getRenderPass(); + renderPassInfo.framebuffer = surface.swapChainFramebuffers[frameIndex % surface.swapChainFramebuffers.size()]; + renderPassInfo.renderArea.offset = { 0, 0 }; + renderPassInfo.renderArea.extent = surface.swapChainExtent; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, testPipeline->getPipeline()); + vkCmdDraw(commandBuffer, 3, 1, 0, 0); + vkCmdEndRenderPass(commandBuffer); + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { + // TODO - Add error handling... + } + } + + frameIndex++; } KRContext::SurfaceInfo& KRContext::GetSurfaceInfo(KrSurfaceHandle handle) @@ -1185,6 +1252,7 @@ KRContext::DeviceInfo& KRContext::GetDeviceInfo(KrDeviceHandle handle) void KRContext::createDevices() { + const std::lock_guard deviceLock(KRContext::g_DeviceInfoMutex); if (m_devices.size() > 0) { return; } @@ -1355,6 +1423,8 @@ void KRContext::createDevices() allocInfo.commandPool = info.computeCommandPool; allocInfo.commandBufferCount = (uint32_t)info.computeCommandBuffers.size(); if (vkAllocateCommandBuffers(info.logicalDevice, &allocInfo, info.computeCommandBuffers.data()) != VK_SUCCESS) { + // Note - this repeated cleanup will likely be eliminated with later refactoring to split vulkan + // object generation out of KRContext vkDestroyCommandPool(info.logicalDevice, info.computeCommandPool, nullptr); vkDestroyCommandPool(info.logicalDevice, info.graphicsCommandPool, nullptr); vkDestroyDevice(info.logicalDevice, nullptr); diff --git a/kraken/KRContext.h b/kraken/KRContext.h index 02aa61a..362620c 100755 --- a/kraken/KRContext.h +++ b/kraken/KRContext.h @@ -128,7 +128,6 @@ public: static void activateStreamerContext(); static void activateRenderContext(); - typedef struct { VkPhysicalDevice device; @@ -146,7 +145,6 @@ public: } DeviceInfo; typedef struct { - KrSurfaceHandle surfaceHandle; KrDeviceHandle deviceHandle; VkSurfaceKHR surface; VkSwapchainKHR swapChain; @@ -155,11 +153,16 @@ public: VkExtent2D swapChainExtent; std::vector swapChainImageViews; std::vector swapChainFramebuffers; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; #ifdef WIN32 HWND hWnd; #endif } SurfaceInfo; + static std::mutex g_SurfaceInfoMutex; + static std::mutex g_DeviceInfoMutex; + DeviceInfo& GetDeviceInfo(KrDeviceHandle handle); SurfaceInfo& GetSurfaceInfo(KrSurfaceHandle handle); diff --git a/kraken/KRPipeline.cpp b/kraken/KRPipeline.cpp index 3f503d3..a065fb8 100644 --- a/kraken/KRPipeline.cpp +++ b/kraken/KRPipeline.cpp @@ -764,7 +764,12 @@ const char *KRPipeline::getKey() const { return m_szKey; } -VkRenderPass& KRPipeline::GetRenderPass() +VkRenderPass& KRPipeline::getRenderPass() { return m_renderPass; +} + +VkPipeline& KRPipeline::getPipeline() +{ + return m_graphicsPipeline; } \ No newline at end of file diff --git a/kraken/KRPipeline.h b/kraken/KRPipeline.h index b55a33e..67ba9f0 100644 --- a/kraken/KRPipeline.h +++ b/kraken/KRPipeline.h @@ -145,7 +145,8 @@ public: void setUniform(int location, const Vector4 &value); void setUniform(int location, const Matrix4 &value); - VkRenderPass& GetRenderPass(); + VkRenderPass& getRenderPass(); + VkPipeline& getPipeline(); private: GLuint m_iProgram;