diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 343cda302305b..f1fdd7f70cdda 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -514,7 +514,7 @@ EndConfig() // Vulkan Display Settings BeginSubConfig(GPUSettingsDisplayVulkan, vulkan, configStandalone.display, "GLV", 0, "Vulkan display settings", display_vulkan) -AddOption(nFramesInFlight, int32_t, 0, "", 0, "Max number of render frames in flight (0 = as many as swapchain images)") +AddOption(nFramesInFlight, uint32_t, 3, "", 0, "Max number of render frames in flight") AddOption(uniformBuffersInDeviceMemory, bool, 1, "", 0, "Have uniform buffers in host-accessible device memory") AddOption(forceDevice, int32_t, -1, "", 0, "Force Vulkan device number to use") AddHelp("help", 'h') diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 74b311356c164..63bec89446d4e 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -68,7 +68,12 @@ GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, uint32_t maxTPCHits, mFlatObjectsDevice.mChainTracking = this; } -GPUChainTracking::~GPUChainTracking() = default; +GPUChainTracking::~GPUChainTracking() +{ + if (mDisplayRunning) { + GetProcessingSettings().eventDisplay->StopDisplay(); + } +} void GPUChainTracking::RegisterPermanentMemoryAndProcessors() { @@ -867,7 +872,7 @@ int32_t GPUChainTracking::RunChainFinalize() } while (GetProcessingSettings().eventDisplay->getDisplayControl() == 0); if (GetProcessingSettings().eventDisplay->getDisplayControl() == 2) { mDisplayRunning = false; - GetProcessingSettings().eventDisplay->DisplayExit(); + GetProcessingSettings().eventDisplay->StopDisplay(); const_cast(GetProcessingSettings()).eventDisplay = nullptr; // TODO: fixme - eventDisplay should probably not be put into ProcessingSettings in the first place return GPUReconstruction::retValValue::retDoExit; } diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx index 469b26f89bda1..008bb2a1f1079 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.cxx @@ -39,7 +39,7 @@ GPUO2InterfaceDisplay::GPUO2InterfaceDisplay(const GPUO2InterfaceConfiguration* GPUO2InterfaceDisplay::~GPUO2InterfaceDisplay() = default; -int32_t GPUO2InterfaceDisplay::startDisplay() +int32_t GPUO2InterfaceDisplay::StartUnmanagedDisplay() { int32_t retVal = mDisplay->StartDisplay(); if (retVal) { @@ -71,12 +71,9 @@ int32_t GPUO2InterfaceDisplay::show(const GPUTrackingInOutPointers* ptrs) return 0; } -int32_t GPUO2InterfaceDisplay::endDisplay() +int32_t GPUO2InterfaceDisplay::StopUnmanagedDisplay() { - mFrontend->DisplayExit(); - while (mFrontend->IsRunning()) { - usleep(10000); - } + mFrontend->StopDisplay(); return 0; } diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h index c0946bab0076d..87990adce5ff1 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h @@ -37,9 +37,9 @@ class GPUO2InterfaceDisplay void UpdateCalib(const GPUCalibObjectsConst* calib); void UpdateGRP(const GPUSettingsGRP* grp); - int32_t startDisplay(); + int32_t StartUnmanagedDisplay(); int32_t show(const GPUTrackingInOutPointers* ptrs); - int32_t endDisplay(); + int32_t StopUnmanagedDisplay(); private: std::unique_ptr mDisplay; diff --git a/GPU/GPUTracking/display/GPUDisplay.cxx b/GPU/GPUTracking/display/GPUDisplay.cxx index 2d7e43ec2b891..e7f5580e3f79f 100644 --- a/GPU/GPUTracking/display/GPUDisplay.cxx +++ b/GPU/GPUTracking/display/GPUDisplay.cxx @@ -734,6 +734,12 @@ void GPUDisplay::ShowNextEvent(const GPUTrackingInOutPointers* ptrs) void GPUDisplay::BlockTillNextEvent() { mSemLockDisplay.Lock(); } +void GPUDisplay::UnblockDisplay() +{ + mSemLockDisplay.Trylock(); + mSemLockDisplay.Unlock(); +} + void GPUDisplay::WaitTillEventShown() { std::unique_lock lock(mMutexLoadAndShowEvent); diff --git a/GPU/GPUTracking/display/GPUDisplay.h b/GPU/GPUTracking/display/GPUDisplay.h index 006db4bbe5b06..bae898cf38674 100644 --- a/GPU/GPUTracking/display/GPUDisplay.h +++ b/GPU/GPUTracking/display/GPUDisplay.h @@ -49,8 +49,10 @@ class GPUDisplay : public GPUDisplayInterface ~GPUDisplay() override = default; int32_t StartDisplay() override; + void ExitDisplay(); void ShowNextEvent(const GPUTrackingInOutPointers* ptrs = nullptr) override; void BlockTillNextEvent() override; + void UnblockDisplay(); void WaitTillEventShown() override; void SetCollisionFirstCluster(uint32_t collision, int32_t sector, int32_t cluster) override; void UpdateCalib(const GPUCalibObjectsConst* calib) override { mCalib = calib; } @@ -60,7 +62,6 @@ class GPUDisplay : public GPUDisplayInterface int32_t DrawGLScene(); void HandleSendKey(int32_t key); int32_t InitDisplay(bool initFailure = false); - void ExitDisplay(); void ResizeScene(int32_t width, int32_t height, bool init = false); const GPUSettingsDisplayRenderer& cfgR() const { return mCfgR; } diff --git a/GPU/GPUTracking/display/GPUDisplayInterface.h b/GPU/GPUTracking/display/GPUDisplayInterface.h index ff83b1cbaa38e..5f5a101233191 100644 --- a/GPU/GPUTracking/display/GPUDisplayInterface.h +++ b/GPU/GPUTracking/display/GPUDisplayInterface.h @@ -56,11 +56,10 @@ class GPUDisplayFrontendInterface public: virtual ~GPUDisplayFrontendInterface(); static GPUDisplayFrontendInterface* getFrontend(const char* type); - virtual void DisplayExit() = 0; + virtual void StopDisplay() = 0; virtual bool EnableSendKey() = 0; virtual int32_t getDisplayControl() const = 0; virtual void setDisplayControl(int32_t v) = 0; - virtual bool IsRunning() const = 0; virtual void sendKey(int32_t v) = 0; virtual const char* frontendName() const = 0; diff --git a/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx b/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx index 80bb794a6d9d1..7f2d2353a9207 100644 --- a/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx +++ b/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx @@ -532,8 +532,8 @@ void GPUDisplayBackendVulkan::createCommandBuffers() vk::CommandBufferAllocateInfo allocInfo{}; allocInfo.commandPool = mCommandPool; allocInfo.level = vk::CommandBufferLevel::ePrimary; - allocInfo.commandBufferCount = mFramesInFlight; - mCommandBufferUpToDate.resize(mFramesInFlight, false); + allocInfo.commandBufferCount = mImageCount; + mCommandBufferUpToDate.resize(mImageCount, false); mCommandBuffers = mDevice.allocateCommandBuffers(allocInfo); mCommandBuffersText = mDevice.allocateCommandBuffers(allocInfo); mCommandBuffersTexture = mDevice.allocateCommandBuffers(allocInfo); @@ -558,19 +558,17 @@ void GPUDisplayBackendVulkan::createSemaphoresAndFences() vk::FenceCreateInfo fenceInfo{}; fenceInfo.flags = vk::FenceCreateFlagBits::eSignaled; mImageAvailableSemaphore.resize(mFramesInFlight); - mRenderFinishedSemaphore.resize(mFramesInFlight); - mTextFinishedSemaphore.resize(mFramesInFlight); - mMixFinishedSemaphore.resize(mFramesInFlight); - mDownsampleFinishedSemaphore.resize(mFramesInFlight); + mPresentSemaphore.resize(mImageCount); mInFlightFence.resize(mFramesInFlight); + mImageFence.resize(mImageCount); for (uint32_t i = 0; i < mFramesInFlight; i++) { mImageAvailableSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); - mRenderFinishedSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); - mTextFinishedSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); - mMixFinishedSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); - mDownsampleFinishedSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); mInFlightFence[i] = mDevice.createFence(fenceInfo, nullptr); } + for (uint32_t i = 0; i < mImageCount; i++) { + mPresentSemaphore[i] = mDevice.createSemaphore(semaphoreInfo, nullptr); + mImageFence[i] = VkFence(VK_NULL_HANDLE); + } fenceInfo.flags = {}; mSingleCommitFence = mDevice.createFence(fenceInfo, nullptr); } @@ -578,10 +576,7 @@ void GPUDisplayBackendVulkan::createSemaphoresAndFences() void GPUDisplayBackendVulkan::clearSemaphoresAndFences() { clearVector(mImageAvailableSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); - clearVector(mRenderFinishedSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); - clearVector(mTextFinishedSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); - clearVector(mMixFinishedSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); - clearVector(mDownsampleFinishedSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); + clearVector(mPresentSemaphore, [&](auto& x) { mDevice.destroySemaphore(x, nullptr); }); clearVector(mInFlightFence, [&](auto& x) { mDevice.destroyFence(x, nullptr); }); mDevice.destroyFence(mSingleCommitFence, nullptr); } @@ -591,9 +586,9 @@ void GPUDisplayBackendVulkan::clearSemaphoresAndFences() void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers() { for (int32_t j = 0; j < 3; j++) { - mUniformBuffersMat[j].resize(mFramesInFlight); - mUniformBuffersCol[j].resize(mFramesInFlight); - for (uint32_t i = 0; i < mFramesInFlight; i++) { + mUniformBuffersMat[j].resize(mImageCount); + mUniformBuffersCol[j].resize(mImageCount); + for (uint32_t i = 0; i < mImageCount; i++) { mUniformBuffersMat[j][i] = createBuffer(sizeof(hmm_mat4), nullptr, vk::BufferUsageFlagBits::eUniformBuffer, mDisplay->cfg().vulkan.uniformBuffersInDeviceMemory ? 2 : 0); mUniformBuffersCol[j][i] = createBuffer(sizeof(float) * 4, nullptr, vk::BufferUsageFlagBits::eUniformBuffer, mDisplay->cfg().vulkan.uniformBuffersInDeviceMemory ? 2 : 0); } @@ -601,13 +596,13 @@ void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers() std::array poolSizes{}; poolSizes[0].type = vk::DescriptorType::eUniformBuffer; - poolSizes[0].descriptorCount = (uint32_t)mFramesInFlight * (2 * 3); + poolSizes[0].descriptorCount = (uint32_t)mImageCount * (2 * 3); poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler; - poolSizes[1].descriptorCount = (uint32_t)mFramesInFlight * 2; + poolSizes[1].descriptorCount = (uint32_t)mImageCount * 2; vk::DescriptorPoolCreateInfo poolInfo{}; poolInfo.poolSizeCount = poolSizes.size(); poolInfo.pPoolSizes = poolSizes.data(); - poolInfo.maxSets = (uint32_t)mFramesInFlight * 3; + poolInfo.maxSets = (uint32_t)mImageCount * 3; mDescriptorPool = mDevice.createDescriptorPool(poolInfo, nullptr); vk::DescriptorSetLayoutBinding uboLayoutBindingMat{}; @@ -634,15 +629,15 @@ void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers() vk::DescriptorSetAllocateInfo allocInfo{}; allocInfo.descriptorPool = mDescriptorPool; - allocInfo.descriptorSetCount = (uint32_t)mFramesInFlight; + allocInfo.descriptorSetCount = (uint32_t)mImageCount; for (int32_t j = 0; j < 3; j++) { // 0 = Render, 1 = Text, 2 = Texture - std::vector layouts(mFramesInFlight, j ? mUniformDescriptorTexture : mUniformDescriptor); + std::vector layouts(mImageCount, j ? mUniformDescriptorTexture : mUniformDescriptor); allocInfo.pSetLayouts = layouts.data(); mDescriptorSets[j] = mDevice.allocateDescriptorSets(allocInfo); for (int32_t k = 0; k < 2; k++) { auto& mUniformBuffers = k ? mUniformBuffersCol[j] : mUniformBuffersMat[j]; - for (uint32_t i = 0; i < mFramesInFlight; i++) { + for (uint32_t i = 0; i < mImageCount; i++) { vk::DescriptorBufferInfo bufferInfo{}; bufferInfo.buffer = mUniformBuffers[i].buffer; bufferInfo.offset = 0; @@ -733,7 +728,7 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing mPresentMode = chooseSwapPresentMode(mSwapChainDetails.presentModes, mDisplay->cfgR().drawQualityVSync ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eImmediate); vk::Extent2D extent = chooseSwapExtent(mSwapChainDetails.capabilities); - uint32_t imageCount = mSwapChainDetails.capabilities.minImageCount + 1; + uint32_t imageCount = std::max(mSwapChainDetails.capabilities.minImageCount + 1, mDisplay->cfg().vulkan.nFramesInFlight + 1); if (mSwapChainDetails.capabilities.maxImageCount > 0 && imageCount > mSwapChainDetails.capabilities.maxImageCount) { imageCount = mSwapChainDetails.capabilities.maxImageCount; } @@ -768,14 +763,13 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing mSwapChain = mDevice.createSwapchainKHR(swapCreateInfo, nullptr); mSwapChainImages = mDevice.getSwapchainImagesKHR(mSwapChain); - uint32_t oldFramesInFlight = mFramesInFlight; + uint32_t oldFramesInFlight = mFramesInFlight, oldImageCount = mImageCount; + mFramesInFlight = mDisplay->cfg().vulkan.nFramesInFlight; mImageCount = mSwapChainImages.size(); - mFramesInFlight = mDisplay->cfg().vulkan.nFramesInFlight == 0 ? mImageCount : mDisplay->cfg().vulkan.nFramesInFlight; - mCommandBufferPerImage = mFramesInFlight == mImageCount; - if (mFramesInFlight > oldFramesInFlight || !mCommandInfrastructureCreated) { + if (mFramesInFlight != oldFramesInFlight || mImageCount != oldImageCount || !mCommandInfrastructureCreated) { if (mCommandInfrastructureCreated) { - clearUniformLayoutsAndBuffers(); + clearUniformLayoutsAndBuffers(); // TODO: Check what must actually be cleaned up if frames in flight changes clearCommandBuffers(); clearSemaphoresAndFences(); } @@ -855,22 +849,25 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo colorAttachmentRef.attachment = nAttachments++; colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal; vk::AttachmentReference depthAttachmentRef{}; - // depthAttachmentRef.attachment // below depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; vk::AttachmentReference colorAttachmentResolveRef{}; - // colorAttachmentResolveRef.attachment // below colorAttachmentResolveRef.layout = vk::ImageLayout::eColorAttachmentOptimal; vk::SubpassDescription subpass{}; subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; - vk::SubpassDependency dependency{}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; - dependency.srcAccessMask = {}; - dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; - dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; + std::array dependencies{}; + dependencies[0].srcSubpass = dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests | vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eFragmentShader; // Includes eColorAttachmentOutput, the wait stage of the image acquire semaphore + dependencies[0].srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite | vk::AccessFlagBits::eTransferWrite; + dependencies[0].dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests; + dependencies[0].dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite; + dependencies[1].srcSubpass = 0; + dependencies[1].srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eLateFragmentTests; + dependencies[1].srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; + dependencies[1].dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eFragmentShader; + dependencies[1].dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eShaderRead; std::vector attachments = {colorAttachment}; if (mZActive) { @@ -889,8 +886,8 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; + renderPassInfo.dependencyCount = dependencies.size(); + renderPassInfo.pDependencies = dependencies.data(); mRenderPass = mDevice.createRenderPass(renderPassInfo, nullptr); const uint32_t imageCountWithMixImages = mImageCount * (mMixingSupported ? 2 : 1); @@ -922,11 +919,6 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo renderPassInfo.pAttachments = &colorAttachment; subpass.pDepthStencilAttachment = nullptr; subpass.pResolveAttachments = nullptr; - if (mFramebuffersText.size()) { - dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput; // Remove early fragment test - dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput; - dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite; // Remove depth/stencil dependencies - } colorAttachment.loadOp = vk::AttachmentLoadOp::eLoad; // Don't clear the frame buffer colorAttachment.initialLayout = vk::ImageLayout::ePresentSrcKHR; // Initial layout is not undefined after 1st pass colorAttachment.samples = vk::SampleCountFlagBits::e1; // No MSAA for Text @@ -938,11 +930,6 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo colorAttachment.initialLayout = vk::ImageLayout::eColorAttachmentOptimal; colorAttachment.finalLayout = mDownsampleFSAA ? vk::ImageLayout::eColorAttachmentOptimal : vk::ImageLayout::ePresentSrcKHR; } - if (mFramebuffersTexture.size()) { - dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput; // Remove early fragment test - dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput; - dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite; // Remove depth/stencil dependencies - } mRenderPassTexture = mDevice.createRenderPass(renderPassInfo, nullptr); } @@ -1016,14 +1003,12 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo {(float)mRenderWidth, (float)mRenderHeight, 1.0f, 1.0f}}; mMixingTextureVertexArray = createBuffer(sizeof(vertices), &vertices[0][0], vk::BufferUsageFlagBits::eVertexBuffer, 1); - if (mCommandBufferPerImage) { - for (uint32_t i = 0; i < mFramesInFlight; i++) { - setMixDescriptor(i, i); - } + for (uint32_t i = 0; i < mImageCount; i++) { + setMixDescriptor(i, i); } } - mFontVertexBuffer.resize(mFramesInFlight); + mFontVertexBuffer.resize(mImageCount); } void GPUDisplayBackendVulkan::clearOffscreenBuffers() @@ -1253,7 +1238,7 @@ void GPUDisplayBackendVulkan::startFillCommandBuffer(vk::CommandBuffer& commandB vk::DeviceSize offsets[] = {0}; commandBuffer.bindVertexBuffers(0, 1, &mVBO.buffer, offsets); - commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayout, 0, 1, &mDescriptorSets[0][mCurrentBufferSet], 0, nullptr); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayout, 0, 1, &mDescriptorSets[0][mCurrentImageIndex], 0, nullptr); } void GPUDisplayBackendVulkan::endFillCommandBuffer(vk::CommandBuffer& commandBuffer) @@ -1428,7 +1413,7 @@ void GPUDisplayBackendVulkan::clearImage(VulkanImage& image) int32_t GPUDisplayBackendVulkan::InitBackendA() { mEnableValidationLayers = (mDisplay->param() && mDisplay->GetProcessingSettings().debugLevel >= 2) || (getenv("GPUCA_VULKAN_VALIDATION") && atoi(getenv("GPUCA_VULKAN_VALIDATION"))); - mFramesInFlight = 2; + mFramesInFlight = mDisplay->cfg().vulkan.nFramesInFlight; createDevice(); createShaders(); @@ -1496,7 +1481,7 @@ uint32_t GPUDisplayBackendVulkan::drawVertices(const vboList& v, const drawType if (count == 0) { return 0; } - if (mCommandBufferUpToDate[mCurrentBufferSet]) { + if (mCommandBufferUpToDate[mCurrentImageIndex]) { return count; } @@ -1525,128 +1510,101 @@ void GPUDisplayBackendVulkan::prepareDraw(const hmm_mat4& proj, const hmm_mat4& mCurrentFrame = (mCurrentFrame + 1) % mFramesInFlight; CHKERR(mDevice.waitForFences(1, &mInFlightFence[mCurrentFrame], true, UINT64_MAX)); auto getImage = [&]() { - vk::Fence fen = VkFence(VK_NULL_HANDLE); - vk::Semaphore sem = VkSemaphore(VK_NULL_HANDLE); - if (mCommandBufferPerImage) { - fen = mInFlightFence[mCurrentFrame]; - CHKERR(mDevice.resetFences(1, &fen)); - } else { - sem = mImageAvailableSemaphore[mCurrentFrame]; - } - return mDevice.acquireNextImageKHR(mSwapChain, UINT64_MAX, sem, fen, &mCurrentImageIndex); + return mDevice.acquireNextImageKHR(mSwapChain, UINT64_MAX, mImageAvailableSemaphore[mCurrentFrame], VkFence(VK_NULL_HANDLE), &mCurrentImageIndex); }; vk::Result retVal = vk::Result::eSuccess; - bool mustUpdateRendering = mMustUpdateSwapChain; - if (mDisplay->updateRenderPipeline() || (requestScreenshot && !mSwapchainImageReadable) || (toMixBuffer && !mMixingSupported) || mDownsampleFactor != getDownsampleFactor(requestScreenshot)) { - mustUpdateRendering = true; - } else if (!mMustUpdateSwapChain) { + bool mustUpdateSwapChain = mMustUpdateSwapChain || mDisplay->updateRenderPipeline() || (requestScreenshot && !mSwapchainImageReadable) || (toMixBuffer && !mMixingSupported) || mDownsampleFactor != getDownsampleFactor(requestScreenshot); + if (!mustUpdateSwapChain) { retVal = getImage(); - } - if (mMustUpdateSwapChain || mustUpdateRendering || retVal == vk::Result::eErrorOutOfDateKHR || retVal == vk::Result::eSuboptimalKHR) { - if (!mustUpdateRendering) { - GPUInfo("Pipeline out of data / suboptimal, recreating"); + if (retVal == vk::Result::eErrorOutOfDateKHR) { + mustUpdateSwapChain = mMustUpdateSwapChain = true; } + } + if (mustUpdateSwapChain) { recreateRendering(requestScreenshot, toMixBuffer); retVal = getImage(); } + mMustUpdateSwapChain = retVal == vk::Result::eSuboptimalKHR; CHKERR(retVal); - if (mCommandBufferPerImage) { - CHKERR(mDevice.waitForFences(1, &mInFlightFence[mCurrentFrame], true, UINT64_MAX)); + if (mImageFence[mCurrentImageIndex]) { + CHKERR(mDevice.waitForFences(1, &mImageFence[mCurrentImageIndex], true, UINT64_MAX)); } + mImageFence[mCurrentImageIndex] = mInFlightFence[mCurrentFrame]; CHKERR(mDevice.resetFences(1, &mInFlightFence[mCurrentFrame])); - mMustUpdateSwapChain = false; - mHasDrawnText = false; - mCurrentBufferSet = mCommandBufferPerImage ? mCurrentImageIndex : mCurrentFrame; + mHasDrawnText = false; + mFrameCommandBuffers.clear(); const hmm_mat4 modelViewProj = proj * view; - writeToBuffer(mUniformBuffersMat[0][mCurrentBufferSet], sizeof(modelViewProj), &modelViewProj); + writeToBuffer(mUniformBuffersMat[0][mCurrentImageIndex], sizeof(modelViewProj), &modelViewProj); } - mCurrentCommandBuffer = toMixBuffer ? mCommandBuffersMix[mCurrentBufferSet] : mCommandBuffers[mCurrentBufferSet]; + mCurrentCommandBuffer = toMixBuffer ? mCommandBuffersMix[mCurrentImageIndex] : mCommandBuffers[mCurrentImageIndex]; mCurrentCommandBufferLastPipeline = -1; - if (!mCommandBufferUpToDate[mCurrentBufferSet]) { + if (!mCommandBufferUpToDate[mCurrentImageIndex]) { startFillCommandBuffer(mCurrentCommandBuffer, mCurrentImageIndex, toMixBuffer); } } void GPUDisplayBackendVulkan::finishDraw(bool doScreenshot, bool toMixBuffer, float includeMixImage) { - if (!mCommandBufferUpToDate[mCurrentBufferSet]) { + if (!mCommandBufferUpToDate[mCurrentImageIndex]) { endFillCommandBuffer(mCurrentCommandBuffer); - if (!toMixBuffer && includeMixImage == 0.f && mCommandBufferPerImage) { - mCommandBufferUpToDate[mCurrentBufferSet] = true; + if (!toMixBuffer && includeMixImage == 0.f) { + mCommandBufferUpToDate[mCurrentImageIndex] = true; } } } void GPUDisplayBackendVulkan::finishFrame(bool doScreenshot, bool toMixBuffer, float includeMixImage) { - vk::Semaphore* stageFinishedSemaphore = &mRenderFinishedSemaphore[mCurrentFrame]; - const vk::Fence noFence = VkFence(VK_NULL_HANDLE); - - vk::SubmitInfo submitInfo{}; - vk::PipelineStageFlags waitStages[] = {vk::PipelineStageFlagBits::eColorAttachmentOutput}; - submitInfo.pWaitSemaphores = includeMixImage > 0.f ? &mRenderFinishedSemaphore[mCurrentFrame] : (!mCommandBufferPerImage ? &mImageAvailableSemaphore[mCurrentFrame] : nullptr); - submitInfo.waitSemaphoreCount = submitInfo.pWaitSemaphores != nullptr ? 1 : 0; - submitInfo.pWaitDstStageMask = waitStages; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &mCurrentCommandBuffer; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = stageFinishedSemaphore; - CHKERR(mGraphicsQueue.submit(1, &submitInfo, includeMixImage > 0 || toMixBuffer || mHasDrawnText || mDownsampleFSAA ? noFence : mInFlightFence[mCurrentFrame])); + mFrameCommandBuffers.emplace_back(mCurrentCommandBuffer); if (!toMixBuffer) { if (includeMixImage > 0.f) { - mixImages(mCommandBuffersTexture[mCurrentBufferSet], includeMixImage); - submitInfo.pWaitSemaphores = stageFinishedSemaphore; - waitStages[0] = {vk::PipelineStageFlagBits::eColorAttachmentOutput}; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pCommandBuffers = &mCommandBuffersTexture[mCurrentBufferSet]; - stageFinishedSemaphore = &mMixFinishedSemaphore[mCurrentFrame]; - submitInfo.pSignalSemaphores = stageFinishedSemaphore; - CHKERR(mGraphicsQueue.submit(1, &submitInfo, mHasDrawnText || mDownsampleFSAA ? noFence : mInFlightFence[mCurrentFrame])); + mixImages(mCommandBuffersTexture[mCurrentImageIndex], includeMixImage); + mFrameCommandBuffers.emplace_back(mCommandBuffersTexture[mCurrentImageIndex]); } - if (mDownsampleFSAA) { - downsampleToFramebuffer(mCommandBuffersDownsample[mCurrentBufferSet]); - submitInfo.pCommandBuffers = &mCommandBuffersDownsample[mCurrentBufferSet]; - submitInfo.pWaitSemaphores = stageFinishedSemaphore; - waitStages[0] = {vk::PipelineStageFlagBits::eTransfer}; - submitInfo.waitSemaphoreCount = 1; - stageFinishedSemaphore = &mDownsampleFinishedSemaphore[mCurrentFrame]; - submitInfo.pSignalSemaphores = stageFinishedSemaphore; - CHKERR(mGraphicsQueue.submit(1, &submitInfo, mHasDrawnText ? noFence : mInFlightFence[mCurrentFrame])); + downsampleToFramebuffer(mCommandBuffersDownsample[mCurrentImageIndex]); + mFrameCommandBuffers.emplace_back(mCommandBuffersDownsample[mCurrentImageIndex]); } + vk::PipelineStageFlags waitStage = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eTransfer; + vk::SubmitInfo submitInfo{}; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &mImageAvailableSemaphore[mCurrentFrame]; + submitInfo.pWaitDstStageMask = &waitStage; if (doScreenshot) { + submitInfo.commandBufferCount = mFrameCommandBuffers.size(); + submitInfo.pCommandBuffers = mFrameCommandBuffers.data(); + CHKERR(mGraphicsQueue.submit(1, &submitInfo, VkFence(VK_NULL_HANDLE))); mDevice.waitIdle(); if (mDisplay->cfgR().screenshotScaleFactor != 1) { readImageToPixels(mDownsampleImages[mCurrentImageIndex].image, vk::ImageLayout::eColorAttachmentOptimal, mScreenshotPixels); } else { readImageToPixels(mSwapChainImages[mCurrentImageIndex], vk::ImageLayout::ePresentSrcKHR, mScreenshotPixels); } + mFrameCommandBuffers.clear(); + submitInfo.waitSemaphoreCount = 0; } - if (mHasDrawnText) { - submitInfo.pWaitSemaphores = stageFinishedSemaphore; - waitStages[0] = {vk::PipelineStageFlagBits::eColorAttachmentOutput}; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pCommandBuffers = &mCommandBuffersText[mCurrentBufferSet]; - stageFinishedSemaphore = &mTextFinishedSemaphore[mCurrentFrame]; - submitInfo.pSignalSemaphores = stageFinishedSemaphore; - CHKERR(mGraphicsQueue.submit(1, &submitInfo, mInFlightFence[mCurrentFrame])); + mFrameCommandBuffers.emplace_back(mCommandBuffersText[mCurrentImageIndex]); } + submitInfo.commandBufferCount = mFrameCommandBuffers.size(); + submitInfo.pCommandBuffers = mFrameCommandBuffers.data(); + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &mPresentSemaphore[mCurrentImageIndex]; + CHKERR(mGraphicsQueue.submit(1, &submitInfo, mInFlightFence[mCurrentFrame])); - CHKERR(mDevice.waitForFences(1, &mInFlightFence[mCurrentFrame], true, UINT64_MAX)); // TODO: I think we need to wait for the fence, so that the image was acquired before we present. Perhaps we can present later to avoid delays vk::PresentInfoKHR presentInfo{}; presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = stageFinishedSemaphore; + presentInfo.pWaitSemaphores = &mPresentSemaphore[mCurrentImageIndex]; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &mSwapChain; presentInfo.pImageIndices = &mCurrentImageIndex; presentInfo.pResults = nullptr; vk::Result retVal = mGraphicsQueue.presentKHR(&presentInfo); - if (retVal == vk::Result::eErrorOutOfDateKHR) { + if (retVal == vk::Result::eErrorOutOfDateKHR || retVal == vk::Result::eSuboptimalKHR) { mMustUpdateSwapChain = true; } else { CHKERR(retVal); @@ -1662,7 +1620,7 @@ void GPUDisplayBackendVulkan::downsampleToFramebuffer(vk::CommandBuffer& command commandBuffer.begin(beginInfo); cmdImageMemoryBarrier(commandBuffer, mSwapChainImages[mCurrentImageIndex], {}, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); - cmdImageMemoryBarrier(commandBuffer, mDownsampleImages[mCurrentImageIndex].image, vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); + cmdImageMemoryBarrier(commandBuffer, mDownsampleImages[mCurrentImageIndex].image, vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eTransfer); vk::Offset3D blitSizeSrc; blitSizeSrc.x = mRenderWidth; @@ -1681,8 +1639,8 @@ void GPUDisplayBackendVulkan::downsampleToFramebuffer(vk::CommandBuffer& command imageBlitRegion.dstOffsets[1] = blitSizeDst; commandBuffer.blitImage(mDownsampleImages[mCurrentImageIndex].image, vk::ImageLayout::eTransferSrcOptimal, mSwapChainImages[mCurrentImageIndex], vk::ImageLayout::eTransferDstOptimal, 1, &imageBlitRegion, vk::Filter::eLinear); - cmdImageMemoryBarrier(commandBuffer, mSwapChainImages[mCurrentImageIndex], vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eMemoryRead, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::ePresentSrcKHR, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); - cmdImageMemoryBarrier(commandBuffer, mDownsampleImages[mCurrentImageIndex].image, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryRead, vk::ImageLayout::eUndefined, vk::ImageLayout::eColorAttachmentOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); + cmdImageMemoryBarrier(commandBuffer, mSwapChainImages[mCurrentImageIndex], vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::ePresentSrcKHR, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput); // Next: text pass, or present (ordered by the present semaphore) + cmdImageMemoryBarrier(commandBuffer, mDownsampleImages[mCurrentImageIndex].image, {}, vk::AccessFlagBits::eColorAttachmentWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eColorAttachmentOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput); // Next frame renders into it again commandBuffer.end(); } @@ -1690,7 +1648,7 @@ void GPUDisplayBackendVulkan::downsampleToFramebuffer(vk::CommandBuffer& command void GPUDisplayBackendVulkan::prepareText() { hmm_mat4 proj = HMM_Orthographic(0.f, mScreenWidth, 0.f, mScreenHeight, -1, 1); - writeToBuffer(mUniformBuffersMat[1][mCurrentBufferSet], sizeof(proj), &proj); + writeToBuffer(mUniformBuffersMat[1][mCurrentImageIndex], sizeof(proj), &proj); mFontVertexBufferHost.clear(); mTextDrawCommands.clear(); @@ -1702,11 +1660,11 @@ void GPUDisplayBackendVulkan::finishText() return; } - mCommandBuffersText[mCurrentBufferSet].reset({}); + mCommandBuffersText[mCurrentImageIndex].reset({}); vk::CommandBufferBeginInfo beginInfo{}; beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - mCommandBuffersText[mCurrentBufferSet].begin(beginInfo); + mCommandBuffersText[mCurrentImageIndex].begin(beginInfo); vk::RenderPassBeginInfo renderPassInfo{}; renderPassInfo.renderPass = mRenderPassText; @@ -1714,33 +1672,33 @@ void GPUDisplayBackendVulkan::finishText() renderPassInfo.renderArea.offset = vk::Offset2D{0, 0}; renderPassInfo.renderArea.extent = vk::Extent2D{mScreenWidth, mScreenHeight}; renderPassInfo.clearValueCount = 0; - mCommandBuffersText[mCurrentBufferSet].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); + mCommandBuffersText[mCurrentImageIndex].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); - if (mFontVertexBuffer[mCurrentBufferSet].size) { - clearBuffer(mFontVertexBuffer[mCurrentBufferSet]); + if (mFontVertexBuffer[mCurrentImageIndex].size) { + clearBuffer(mFontVertexBuffer[mCurrentImageIndex]); } - mFontVertexBuffer[mCurrentBufferSet] = createBuffer(mFontVertexBufferHost.size() * sizeof(float), mFontVertexBufferHost.data(), vk::BufferUsageFlagBits::eVertexBuffer, 0); + mFontVertexBuffer[mCurrentImageIndex] = createBuffer(mFontVertexBufferHost.size() * sizeof(float), mFontVertexBufferHost.data(), vk::BufferUsageFlagBits::eVertexBuffer, 0); - mCommandBuffersText[mCurrentBufferSet].bindPipeline(vk::PipelineBindPoint::eGraphics, mPipelines[3]); - mCommandBuffersText[mCurrentBufferSet].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayoutTexture, 0, 1, &mDescriptorSets[1][mCurrentBufferSet], 0, nullptr); + mCommandBuffersText[mCurrentImageIndex].bindPipeline(vk::PipelineBindPoint::eGraphics, mPipelines[3]); + mCommandBuffersText[mCurrentImageIndex].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayoutTexture, 0, 1, &mDescriptorSets[1][mCurrentImageIndex], 0, nullptr); vk::DeviceSize offsets[] = {0}; - mCommandBuffersText[mCurrentBufferSet].bindVertexBuffers(0, 1, &mFontVertexBuffer[mCurrentBufferSet].buffer, offsets); + mCommandBuffersText[mCurrentImageIndex].bindVertexBuffers(0, 1, &mFontVertexBuffer[mCurrentImageIndex].buffer, offsets); for (const auto& cmd : mTextDrawCommands) { - mCommandBuffersText[mCurrentBufferSet].pushConstants(mPipelineLayoutTexture, vk::ShaderStageFlagBits::eFragment, 0, sizeof(cmd.color), cmd.color); - mCommandBuffersText[mCurrentBufferSet].draw(cmd.nVertices, 1, cmd.firstVertex, 0); + mCommandBuffersText[mCurrentImageIndex].pushConstants(mPipelineLayoutTexture, vk::ShaderStageFlagBits::eFragment, 0, sizeof(cmd.color), cmd.color); + mCommandBuffersText[mCurrentImageIndex].draw(cmd.nVertices, 1, cmd.firstVertex, 0); } mFontVertexBufferHost.clear(); - mCommandBuffersText[mCurrentBufferSet].endRenderPass(); - mCommandBuffersText[mCurrentBufferSet].end(); + mCommandBuffersText[mCurrentImageIndex].endRenderPass(); + mCommandBuffersText[mCurrentImageIndex].end(); } void GPUDisplayBackendVulkan::mixImages(vk::CommandBuffer commandBuffer, float mixSlaveImage) { hmm_mat4 proj = HMM_Orthographic(0.f, mRenderWidth, 0.f, mRenderHeight, -1, 1); - writeToBuffer(mUniformBuffersMat[2][mCurrentBufferSet], sizeof(proj), &proj); + writeToBuffer(mUniformBuffersMat[2][mCurrentImageIndex], sizeof(proj), &proj); commandBuffer.reset({}); vk::CommandBufferBeginInfo beginInfo{}; @@ -1749,7 +1707,7 @@ void GPUDisplayBackendVulkan::mixImages(vk::CommandBuffer commandBuffer, float m vk::Image& image = mDownsampleFSAA ? mDownsampleImages[mCurrentImageIndex + mImageCount].image : mMixImages[mCurrentImageIndex].image; vk::ImageLayout srcLayout = mDownsampleFSAA ? vk::ImageLayout::eColorAttachmentOptimal : vk::ImageLayout::ePresentSrcKHR; - cmdImageMemoryBarrier(commandBuffer, image, {}, vk::AccessFlagBits::eMemoryRead, srcLayout, vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eFragmentShader); + cmdImageMemoryBarrier(commandBuffer, image, vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eShaderRead, srcLayout, vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader); vk::RenderPassBeginInfo renderPassInfo{}; renderPassInfo.renderPass = mRenderPassTexture; @@ -1760,10 +1718,7 @@ void GPUDisplayBackendVulkan::mixImages(vk::CommandBuffer commandBuffer, float m commandBuffer.beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, mPipelines[4]); - if (!mCommandBufferPerImage) { - setMixDescriptor(mCurrentBufferSet, mCurrentImageIndex); - } - commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayoutTexture, 0, 1, &mDescriptorSets[2][mCurrentBufferSet], 0, nullptr); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, mPipelineLayoutTexture, 0, 1, &mDescriptorSets[2][mCurrentImageIndex], 0, nullptr); vk::DeviceSize offsets[] = {0}; commandBuffer.bindVertexBuffers(0, 1, &mMixingTextureVertexArray.buffer, offsets); @@ -1776,7 +1731,7 @@ void GPUDisplayBackendVulkan::mixImages(vk::CommandBuffer commandBuffer, float m void GPUDisplayBackendVulkan::ActivateColor(std::array& color) { - if (mCommandBufferUpToDate[mCurrentBufferSet]) { + if (mCommandBufferUpToDate[mCurrentImageIndex]) { return; } mCurrentCommandBuffer.pushConstants(mPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, sizeof(color), color.data()); @@ -1784,7 +1739,7 @@ void GPUDisplayBackendVulkan::ActivateColor(std::array& color) void GPUDisplayBackendVulkan::pointSizeFactor(float factor) { - if (mCommandBufferUpToDate[mCurrentBufferSet]) { + if (mCommandBufferUpToDate[mCurrentImageIndex]) { return; } float size = mDisplay->cfgL().pointSize * mDownsampleFactor * factor; @@ -1793,7 +1748,7 @@ void GPUDisplayBackendVulkan::pointSizeFactor(float factor) void GPUDisplayBackendVulkan::lineWidthFactor(float factor) { - if (mCommandBufferUpToDate[mCurrentBufferSet]) { + if (mCommandBufferUpToDate[mCurrentImageIndex]) { return; } mCurrentCommandBuffer.setLineWidth(mDisplay->cfgL().lineWidth * mDownsampleFactor * factor); @@ -1893,7 +1848,7 @@ void GPUDisplayBackendVulkan::updateFontTextureDescriptor() imageInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; imageInfo.imageView = mFontImage.view; imageInfo.sampler = mTextureSampler; - for (uint32_t i = 0; i < mFramesInFlight; i++) { + for (uint32_t i = 0; i < mImageCount; i++) { vk::WriteDescriptorSet descriptorWrite{}; descriptorWrite.dstSet = mDescriptorSets[1][i]; descriptorWrite.dstBinding = 2; @@ -2024,5 +1979,5 @@ uint32_t GPUDisplayBackendVulkan::DepthBits() bool GPUDisplayBackendVulkan::backendNeedRedraw() { - return !mCommandBufferUpToDate[mCurrentBufferSet]; + return !mCommandBufferUpToDate[mCurrentImageIndex]; } diff --git a/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h b/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h index b36a46f3170a1..24afb12fadee4 100644 --- a/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h +++ b/GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h @@ -162,13 +162,11 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend std::vector mFramebuffersTexture; vk::CommandPool mCommandPool; - bool mCommandBufferPerImage = false; bool mCommandInfrastructureCreated = false; uint32_t mImageCount = 0; uint32_t mFramesInFlight = 0; int32_t mCurrentFrame = 0; uint32_t mCurrentImageIndex = 0; - int32_t mCurrentBufferSet = 0; vk::CommandBuffer mCurrentCommandBuffer; int32_t mCurrentCommandBufferLastPipeline = -1; @@ -177,13 +175,12 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend std::vector mCommandBuffersText; std::vector mCommandBuffersTexture; std::vector mCommandBuffersMix; + std::vector mFrameCommandBuffers; // All command buffers of the current frame, submitted as one batch, ordered by render pass dependencies and barriers std::vector mCommandBufferUpToDate; std::vector mImageAvailableSemaphore; - std::vector mRenderFinishedSemaphore; - std::vector mTextFinishedSemaphore; - std::vector mMixFinishedSemaphore; - std::vector mDownsampleFinishedSemaphore; + std::vector mPresentSemaphore; std::vector mInFlightFence; + std::vector mImageFence; std::vector mUniformBuffersMat[3]; std::vector mUniformBuffersCol[3]; std::vector mDescriptorSets[3]; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx index f5bbeef3cf76e..ab6d8162c6d0c 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx @@ -248,3 +248,20 @@ int32_t GPUDisplayFrontend::StartDisplay() #endif return (0); } + +void GPUDisplayFrontend::StopDisplay() +{ + { + std::lock_guard lock(mExitStateMutex); + if (mDisplayRunning) { + mDisplayControl = 2; + StopDisplayA(); + mDisplay->UnblockDisplay(); + } + } + while (mDisplayRunning) { + std::this_thread::sleep_for(std::chrono::microseconds(10000)); // TODO: Signal by semaphore + } +} + +void GPUDisplayFrontend::StopDisplayA() {} diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h index 56fe18c9c223e..d53cd5f1f621e 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h @@ -52,8 +52,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface static constexpr int32_t GL_MIN_VERSION_MINOR = 5; int32_t StartDisplay(); // Start the display. This function returns, and should spawn a thread that runs the display, and calls InitDisplay - void DisplayExit() override = 0; // Stop the display. Display thread should call ExitDisplay and then wait that IsRunning() returns false - bool IsRunning() const override { return mDisplayRunning; } + void StopDisplay() override; // Stop the display. Display thread should call ExitDisplay. Functions waits for display thread to terminate virtual void SwitchFullscreen(bool set) = 0; // Toggle full-screen mode virtual void ToggleMaximized(bool set) = 0; // Maximize window virtual void SetVSync(bool enable) = 0; // Enable / disable vsync @@ -79,6 +78,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface protected: virtual int32_t FrontendMain() = 0; + virtual void StopDisplayA(); static void* FrontendThreadWrapper(void*); void waitForFPSLimit(); // Sleep until the next frame is due according to fpsRate (no sleep with maxFPSRate or fpsRate <= 0) @@ -121,6 +121,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface volatile int32_t mNeedUpdate = 0; // flag that backend shall update the GL window, and call DrawGLScene std::mutex mSendKeyMutex; std::vector mSendKeys; // Keys sent by external entity (usually console), may be ignored by backend. + std::mutex mExitStateMutex; // Keyboard / Mouse actions bool mMouseDn = false; // Mouse button down diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx index 836ab53bedb84..ad19130aa47ee 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx @@ -328,9 +328,10 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain() glfwSwapInterval(1); } - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = true; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = true; + } if (mBackend->ExtInit()) { fprintf(stderr, "Error initializing GL extension wrapper\n"); @@ -362,23 +363,20 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain() } ExitDisplay(); - mDisplayControl = 2; - pthread_mutex_lock(&mSemLockExit); - glfwDestroyWindow(mWindow); - glfwTerminate(); - mDisplayRunning = false; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayControl = 2; + glfwDestroyWindow(mWindow); + glfwTerminate(); + mDisplayRunning = false; + } return 0; } -void GPUDisplayFrontendGlfw::DisplayExit() +void GPUDisplayFrontendGlfw::StopDisplayA() { - pthread_mutex_lock(&mSemLockExit); - if (mDisplayRunning) { - glfwSetWindowShouldClose(mWindow, true); - } - pthread_mutex_unlock(&mSemLockExit); + glfwSetWindowShouldClose(mWindow, true); } void GPUDisplayFrontendGlfw::OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton) diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h index 77b27f48c32a5..31b9a8b5211d7 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h @@ -16,7 +16,6 @@ #define GPUDISPLAYFRONTENDGLFW_H #include "GPUDisplayFrontend.h" -#include struct GLFWwindow; @@ -28,7 +27,7 @@ class GPUDisplayFrontendGlfw : public GPUDisplayFrontend GPUDisplayFrontendGlfw(); ~GPUDisplayFrontendGlfw() override = default; - void DisplayExit() override; + void StopDisplayA() override; void SwitchFullscreen(bool set) override; void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; @@ -63,7 +62,6 @@ class GPUDisplayFrontendGlfw : public GPUDisplayFrontend bool mRestoreWindowedSize = false; double mPixelRatio = 1.; // Framebuffer pixels per window coordinate (1 on X11 / Win32, scale on Wayland / macOS) - pthread_mutex_t mSemLockExit = PTHREAD_MUTEX_INITIALIZER; int32_t mWindowX = 0; int32_t mWindowY = 0; int32_t mWindowWidth = INIT_WIDTH; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx index 6adfd0091bb65..6b75eb7493627 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx @@ -265,26 +265,24 @@ int32_t GPUDisplayFrontendGlut::FrontendMain() glutMouseWheelFunc(mMouseWheelFunc); applyInitialWindowState(); - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = true; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = true; + } glutMainLoop(); - mDisplayControl = 2; - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = false; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayControl = 2; + mDisplayRunning = false; + } ExitDisplay(); return 0; } -void GPUDisplayFrontendGlut::DisplayExit() +void GPUDisplayFrontendGlut::StopDisplayA() { - pthread_mutex_lock(&mSemLockExit); - if (mDisplayRunning) { - glutLeaveMainLoop(); - } - pthread_mutex_unlock(&mSemLockExit); + glutLeaveMainLoop(); } void GPUDisplayFrontendGlut::OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton) diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.h index acb63e863126a..d595fedcb16cf 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.h @@ -16,7 +16,6 @@ #define GPUDISPLAYFRONTENDGLUT_H #include "GPUDisplayFrontend.h" -#include namespace o2::gpu { @@ -26,7 +25,7 @@ class GPUDisplayFrontendGlut : public GPUDisplayFrontend GPUDisplayFrontendGlut(); ~GPUDisplayFrontendGlut() override = default; - void DisplayExit() override; + void StopDisplayA() override; void SwitchFullscreen(bool set) override; void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; @@ -48,8 +47,6 @@ class GPUDisplayFrontendGlut : public GPUDisplayFrontend static int32_t GetKey(int32_t key); static void GetKey(int32_t keyin, int32_t& keyOut, int32_t& keyPressOut, bool special); - pthread_mutex_t mSemLockExit = PTHREAD_MUTEX_INITIALIZER; - int32_t mWidth = INIT_WIDTH; int32_t mHeight = INIT_HEIGHT; bool mFullScreen = false; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.h index 3c7b67c35a0ce..c6eab47c60441 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.h @@ -25,7 +25,6 @@ class GPUDisplayFrontendNone : public GPUDisplayFrontend GPUDisplayFrontendNone(); ~GPUDisplayFrontendNone() override = default; - void DisplayExit() override {} void SwitchFullscreen(bool set) override {} void ToggleMaximized(bool set) override {} void SetVSync(bool enable) override {} diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx index 2af8513b7c4c4..987217f93f336 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx @@ -559,9 +559,10 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() return (1); } - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = true; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = true; + } while (mDisplayControl != 2) { bool error = false; @@ -606,9 +607,10 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() } xkb_context_unref(mXKBcontext); - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = false; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = false; + } if (mCursorShapeDevice) { wp_cursor_shape_device_v1_destroy(mCursorShapeDevice); @@ -678,15 +680,6 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() return (0); } -void GPUDisplayFrontendWayland::DisplayExit() -{ - pthread_mutex_lock(&mSemLockExit); - if (mDisplayRunning) { - mDisplayControl = 2; - } - pthread_mutex_unlock(&mSemLockExit); -} - void GPUDisplayFrontendWayland::SwitchFullscreen(bool set) { if (!mCanFullscreen) { diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.h index 01af3dc49631c..61c95907d500d 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.h @@ -16,7 +16,6 @@ #define GPUDISPLAYFRONTENDWAYLAND_H #include "GPUDisplayFrontend.h" -#include #include #include "xdg-shell-client-protocol.h" #include "fractional-scale-client-protocol.h" @@ -41,7 +40,6 @@ class GPUDisplayFrontendWayland : public GPUDisplayFrontend GPUDisplayFrontendWayland(); ~GPUDisplayFrontendWayland() override = default; - void DisplayExit() override; void SwitchFullscreen(bool set) override; void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; @@ -69,8 +67,6 @@ class GPUDisplayFrontendWayland : public GPUDisplayFrontend }; OutputInfo* findOutput(wl_output* output); - pthread_mutex_t mSemLockExit = PTHREAD_MUTEX_INITIALIZER; - wl_display* mWayland = nullptr; wl_registry* mRegistry = nullptr; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx index 2188fe59a880c..14a65e6634476 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx @@ -371,7 +371,6 @@ int32_t GPUDisplayFrontendWindows::FrontendMain() return (0); } -void DisplayExit() {} void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton) {} void SwitchFullscreen(bool set) {} void ToggleMaximized(bool set) {} diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.h index cac5b62c4cc63..e28a9f4ced75b 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.h @@ -25,7 +25,6 @@ class GPUDisplayFrontendWindows : public GPUDisplayFrontend GPUDisplayFrontendWindows(); ~GPUDisplayFrontendWindows() override = default; - void DisplayExit() override; void SwitchFullscreen(bool set) override; void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx index 6bdce427bf518..e832ee88bd751 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx @@ -344,9 +344,10 @@ int32_t GPUDisplayFrontendX11::FrontendMain() return (1); } - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = true; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = true; + } while (1) { do { @@ -471,22 +472,14 @@ int32_t GPUDisplayFrontendX11::FrontendMain() XDestroyWindow(mXDisplay, mWindow); XCloseDisplay(mXDisplay); - pthread_mutex_lock(&mSemLockExit); - mDisplayRunning = false; - pthread_mutex_unlock(&mSemLockExit); + { + std::lock_guard lock(mExitStateMutex); + mDisplayRunning = false; + } return (0); } -void GPUDisplayFrontendX11::DisplayExit() -{ - pthread_mutex_lock(&mSemLockExit); - if (mDisplayRunning) { - mDisplayControl = 2; - } - pthread_mutex_unlock(&mSemLockExit); -} - void GPUDisplayFrontendX11::updateWindowState() { Atom type; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.h index 294e1b7174221..bca7def502aaa 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.h @@ -16,7 +16,6 @@ #define GPUDISPLAYFRONTENDX11_H #include "GPUDisplayFrontend.h" -#include #include #include #include @@ -30,7 +29,6 @@ class GPUDisplayFrontendX11 : public GPUDisplayFrontend GPUDisplayFrontendX11(); ~GPUDisplayFrontendX11() override = default; - void DisplayExit() override; void SwitchFullscreen(bool set) override; void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; @@ -45,8 +43,6 @@ class GPUDisplayFrontendX11 : public GPUDisplayFrontend int32_t GetKey(int32_t key); void GetKey(XEvent& event, int32_t& keyOut, int32_t& keyPressOut); - pthread_mutex_t mSemLockExit = PTHREAD_MUTEX_INITIALIZER; - GLuint mFontBase; Display* mXDisplay = nullptr; diff --git a/GPU/Workflow/src/O2GPUDPLDisplay.cxx b/GPU/Workflow/src/O2GPUDPLDisplay.cxx index fa68289517e68..3d10a47adda4f 100644 --- a/GPU/Workflow/src/O2GPUDPLDisplay.cxx +++ b/GPU/Workflow/src/O2GPUDPLDisplay.cxx @@ -129,7 +129,7 @@ void O2GPUDPLDisplaySpec::run(ProcessingContext& pc) } if (mDisplayStarted == false) { - if (mDisplay->startDisplay()) { + if (mDisplay->StartUnmanagedDisplay()) { throw std::runtime_error("Error starting event display"); } mDisplayStarted = true; @@ -143,7 +143,7 @@ void O2GPUDPLDisplaySpec::run(ProcessingContext& pc) ptrs.settingsTF = mTFSettings.get(); if (mDisplay->show(&ptrs)) { - mDisplay->endDisplay(); + mDisplay->StopUnmanagedDisplay(); mDisplayShutDown = true; } } @@ -153,7 +153,7 @@ void O2GPUDPLDisplaySpec::endOfStream(EndOfStreamContext& ec) if (mDisplayShutDown) { return; } - mDisplay->endDisplay(); + mDisplay->StopUnmanagedDisplay(); mDisplayShutDown = true; }