From 1ee89154c06c876588a28c30c1a82ffff8ae0536 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 30 Sep 2024 19:58:45 -0300 Subject: [PATCH] vulkan: memory barrier after compute dispatches. --- src/modules/graphics/vulkan/Buffer.cpp | 69 ++++++++--------- src/modules/graphics/vulkan/Buffer.h | 7 +- src/modules/graphics/vulkan/Graphics.cpp | 98 +++++++++++++++++++----- src/modules/graphics/vulkan/Graphics.h | 4 +- src/modules/graphics/vulkan/Shader.cpp | 16 +++- src/modules/graphics/vulkan/Shader.h | 18 +++++ src/modules/graphics/vulkan/Texture.cpp | 20 ++--- src/modules/graphics/vulkan/Vulkan.cpp | 28 +++++-- src/modules/graphics/vulkan/Vulkan.h | 5 +- 9 files changed, 184 insertions(+), 81 deletions(-) diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 33cb0e965..a09b2e889 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -62,6 +62,36 @@ Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const st , vgfx(dynamic_cast(gfx)) , usageFlags(settings.usageFlags) { + // All buffers can be copied to and from. + barrierDstAccessFlags = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + barrierDstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT; + + if (usageFlags & BUFFERUSAGEFLAG_VERTEX) + { + barrierDstAccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + } + if (usageFlags & BUFFERUSAGEFLAG_INDEX) + { + barrierDstAccessFlags |= VK_ACCESS_INDEX_READ_BIT; + barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + } + if (usageFlags & BUFFERUSAGEFLAG_TEXEL) + { + barrierDstAccessFlags |= VK_ACCESS_SHADER_READ_BIT; + barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + } + if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE) + { + barrierDstAccessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + } + if (usageFlags & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS) + { + barrierDstAccessFlags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + barrierDstStageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + } + loadVolatile(); } @@ -302,44 +332,9 @@ void Buffer::postGPUWriteBarrier(VkCommandBuffer cmd) VkMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = barrierDstAccessFlags; - VkPipelineStageFlags dstStageMask = 0; - addPostGPUWriteBarrierFlags(barrier.dstAccessMask, dstStageMask); - - vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr); -} - -void Buffer::addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags) -{ - // All buffers can be copied to and from. - dstAccessFlags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT; - - if (usageFlags & BUFFERUSAGEFLAG_VERTEX) - { - dstAccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - } - if (usageFlags & BUFFERUSAGEFLAG_INDEX) - { - dstAccessFlags |= VK_ACCESS_INDEX_READ_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - } - if (usageFlags & BUFFERUSAGEFLAG_TEXEL) - { - dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - } - if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE) - { - dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - } - if (usageFlags & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS) - { - dstAccessFlags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - dstStageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - } + vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, barrierDstStageFlags, 0, 1, &barrier, 0, nullptr, 0, nullptr); } } // vulkan diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index fda7b7295..f1d9c23c6 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -56,7 +56,9 @@ public: ptrdiff_t getTexelBufferHandle() const override; void postGPUWriteBarrier(VkCommandBuffer cmd); - void addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags); + + VkAccessFlags getBarrierDstAccessFlags() const { return barrierDstAccessFlags; } + VkPipelineStageFlags getBarrierDstStageFlags() const { return barrierDstStageFlags; } private: @@ -76,6 +78,9 @@ private: BufferUsageFlags usageFlags; Range mappedRange; bool coherent; + + VkAccessFlags barrierDstAccessFlags = 0; + VkPipelineStageFlags barrierDstStageFlags = 0; }; } // vulkan diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 150503808..c9ac8368c 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -351,7 +351,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), backbufferImage, - swapChainPixelFormat, + swapChainPixelFormat, true, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } @@ -382,7 +382,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), backbufferImage, - swapChainPixelFormat, + swapChainPixelFormat, true, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); @@ -405,7 +405,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), backbufferImage, - swapChainPixelFormat, + swapChainPixelFormat, true, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, fakeBackbuffer == nullptr ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } @@ -1194,8 +1194,56 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) return new StreamBuffer(this, type, size); } +static bool computeDispatchBarrierFlags(Shader *shader, VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags) +{ + for (const auto &info : shader->getActiveTextureInfo()) + { + if ((info.access & Shader::ACCESS_WRITE) == 0) + continue; + + if (info.texture == nullptr) + return false; + + auto tex = (Texture *) info.texture; + + // All writable images use the GENERAL layout. + // TODO: this is pretty messy. + VkAccessFlags texAccessFlags = 0; + VkPipelineStageFlags texStageFlags = 0; + const PixelFormatInfo &info = getPixelFormatInfo(tex->getPixelFormat()); + Vulkan::setImageLayoutTransitionOptions(false, tex->isRenderTarget(), info, VK_IMAGE_LAYOUT_GENERAL, texAccessFlags, texStageFlags); + + dstAccessFlags |= texAccessFlags; + dstStageFlags |= texStageFlags; + } + + for (const auto &info : shader->getActiveStorageBufferInfo()) + { + if ((info.access & Shader::ACCESS_WRITE) == 0) + continue; + + if (info.buffer == nullptr) + return false; + + auto b = (Buffer *) info.buffer; + dstAccessFlags |= b->getBarrierDstAccessFlags(); + dstStageFlags |= b->getBarrierDstStageFlags(); + } + + return true; +} + bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z) { + auto computeShader = (Shader *) shader; + + VkMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + VkPipelineStageFlags dstStageMask = 0; + if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask)) + return false; + usedShadersInFrame.insert(computeShader); if (renderPassState.active) @@ -1205,14 +1253,26 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z) computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE); - // TODO: does this need any layout transitions? vkCmdDispatch(commandBuffers.at(currentFrame), (uint32) x, (uint32) y, (uint32) z); + // Image layout transitions aren't needed, every writable image will be in the GENERAL layout. + if (barrier.dstAccessMask != 0 || dstStageMask != 0) + vkCmdPipelineBarrier(commandBuffers.at(currentFrame), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr); + return true; } bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset) { + auto computeShader = (Shader *) shader; + + VkMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + VkPipelineStageFlags dstStageMask = 0; + if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask)) + return false; + usedShadersInFrame.insert(computeShader); if (renderPassState.active) @@ -1222,9 +1282,12 @@ bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer * computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE); - // TODO: does this need any layout transitions? vkCmdDispatchIndirect(commandBuffers.at(currentFrame), (VkBuffer) indirectargs->getHandle(), argsoffset); + // Image layout transitions aren't needed, every writable image will be in the GENERAL layout. + if (barrier.dstAccessMask != 0 || dstStageMask != 0) + vkCmdPipelineBarrier(commandBuffers.at(currentFrame), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr); + return true; } @@ -1315,7 +1378,7 @@ void Graphics::beginFrame() Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), swapChainImages[imageIndex], - swapChainPixelFormat, + swapChainPixelFormat, true, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } @@ -1326,7 +1389,7 @@ void Graphics::beginFrame() Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), depthImage, - depthStencilPixelFormat, + depthStencilPixelFormat, true, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -1334,7 +1397,7 @@ void Graphics::beginFrame() Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), colorImage, - swapChainPixelFormat, + swapChainPixelFormat, true, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -2503,7 +2566,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b FramebufferConfiguration configuration{}; - std::vector> transitionImages; + std::vector> transitionImages; for (const auto &color : rts.colors) { @@ -2513,7 +2576,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b VkImageLayout imagelayout = tex->getImageLayout(); if (imagelayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), tex->isRenderTarget(), imagelayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, viewinfo.startMipmap + color.mipmap, viewinfo.startLayer + color.slice }); } } @@ -2525,7 +2588,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b VkImageLayout imagelayout = tex->getImageLayout(); if (imagelayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), tex->isRenderTarget(), imagelayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, viewinfo.startMipmap + rts.depthStencil.mipmap, viewinfo.startLayer + rts.depthStencil.slice }); } } @@ -2581,8 +2644,8 @@ void Graphics::startRenderPass() renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass; renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration); - for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) - Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, imageLayout, renderLayout, rootmip, 1, rootlayer, 1); + for (const auto &[image, format, renderTarget, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) + Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderTarget, imageLayout, renderLayout, rootmip, 1, rootlayer, 1); vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassState.beginInfo, VK_SUBPASS_CONTENTS_INLINE); @@ -2595,8 +2658,8 @@ void Graphics::endRenderPass() vkCmdEndRenderPass(commandBuffers.at(currentFrame)); - for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) - Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderLayout, imageLayout, rootmip, 1, rootlayer, 1); + for (const auto &[image, format, renderTarget, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) + Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderTarget, renderLayout, imageLayout, rootmip, 1, rootlayer, 1); for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments) colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -2686,11 +2749,6 @@ void Graphics::requestSwapchainRecreation() } } -void Graphics::setComputeShader(Shader *shader) -{ - computeShader = shader; -} - VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) { auto samplerkey = samplerState.toKey(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index b9b844199..ee2474e5a 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -196,7 +196,7 @@ struct RenderpassState RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; VkPipeline pipeline = VK_NULL_HANDLE; - std::vector> transitionImages; + std::vector> transitionImages; uint32_t numColorAttachments = 0; uint64 packedColorAttachmentFormats = 0; float width = 0.0f; @@ -267,7 +267,6 @@ public: void addReadbackCallback(std::function callback); void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr); VkSampler getCachedSampler(const SamplerState &sampler); - void setComputeShader(Shader *computeShader); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const; const OptionalInstanceExtensions &getEnabledOptionalInstanceExtensions() const; @@ -377,7 +376,6 @@ private: std::unordered_map samplers; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector commandBuffers; - Shader *computeShader = nullptr; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; std::vector inFlightFences; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 4340e6f97..34bfe5c85 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -337,8 +337,6 @@ void Shader::attach() Vulkan::shaderSwitch(); } } - else - vgfx->setComputeShader(this); } int Shader::getVertexAttributeIndex(const std::string &name) @@ -777,12 +775,18 @@ void Shader::compileShaders() descriptorBufferViews.clear(); descriptorBufferViews.reserve(numBufferViews); + allTextureInfo.clear(); + allTextureInfo.reserve(numTextures); + storageBufferInfo.clear(); + storageBufferInfo.reserve(numBuffers); + if (localUniformData.size() > 0) { VkDescriptorBufferInfo bufferInfo{}; bufferInfo.range = localUniformData.size(); descriptorBuffers.push_back(bufferInfo); + storageBufferInfo.push_back({ nullptr, ACCESS_READ }); // Dummy value. VkWriteDescriptorSet write{}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -807,6 +811,8 @@ void Shader::compileShaders() VkDescriptorImageInfo imageInfo{}; descriptorImages.push_back(imageInfo); + allTextureInfo.push_back({ nullptr, info.access }); + auto texture = activeTextures[info.resourceIndex + i]; if (texture != nullptr) setTextureDescriptor(&info, texture, i); @@ -836,6 +842,8 @@ void Shader::compileShaders() VkDescriptorImageInfo imageInfo{}; descriptorImages.push_back(imageInfo); + allTextureInfo.push_back({ nullptr, info.access }); + auto texture = activeTextures[info.resourceIndex + i]; if (texture != nullptr) setTextureDescriptor(&info, texture, i); @@ -893,6 +901,8 @@ void Shader::compileShaders() VkDescriptorBufferInfo bufferInfo{}; descriptorBuffers.push_back(bufferInfo); + storageBufferInfo.push_back({ nullptr, info.access }); + auto buffer = activeBuffers[info.resourceIndex + i]; if (buffer != nullptr) setBufferDescriptor(&info, buffer, i); @@ -1039,6 +1049,7 @@ void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Textu { imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED; imageInfo.imageView = view; + allTextureInfo[info->bindingStartIndex + index].texture = texture; resourceDescriptorsDirty = true; } } @@ -1055,6 +1066,7 @@ void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer bufferInfo.buffer = vkbuffer; bufferInfo.offset = 0; bufferInfo.range = range; + storageBufferInfo[info->bindingStartIndex + index].buffer = buffer; resourceDescriptorsDirty = true; } } diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 7751f3d4c..b395c8c31 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -124,6 +124,18 @@ public: DataBaseType baseType; }; + struct TextureInfo + { + love::graphics::Texture *texture; + Access access; + }; + + struct BufferInfo + { + love::graphics::Buffer *buffer; + Access access; + }; + Shader(StrongRef stages[], const CompileOptions &options); virtual ~Shader(); @@ -158,6 +170,9 @@ public: VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationCore &configuration); VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationFull &configuration); + const std::vector &getActiveTextureInfo() const { return allTextureInfo; } + const std::vector &getActiveStorageBufferInfo() const { return storageBufferInfo; } + private: void compileShaders(); void createDescriptorSetLayout(); @@ -189,6 +204,9 @@ private: std::vector shaderStages; std::vector shaderModules; + std::vector allTextureInfo; + std::vector storageBufferInfo; + Graphics *vgfx = nullptr; VkDevice device = VK_NULL_HANDLE; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index bbf4f60e1..2f64905c0 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -169,7 +169,7 @@ bool Texture::loadVolatile() else // TODO: is there a better layout for this situation? imageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_UNDEFINED, imageLayout, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); @@ -383,7 +383,7 @@ void Texture::clear() if (clearLayout != imageLayout) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, clearLayout, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); } @@ -403,7 +403,7 @@ void Texture::clear() if (clearLayout != imageLayout) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, clearLayout, imageLayout, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); } @@ -451,7 +451,7 @@ void Texture::generateMipmapsInternal() auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, rootView.startMipmap, static_cast(getMipmapCount()), rootView.startLayer, static_cast(layerCount)); @@ -589,7 +589,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, level, 1, baseLayer, 1); @@ -602,7 +602,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice ®ion ); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, level, 1, baseLayer, 1); } @@ -643,11 +643,11 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1); vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1); } else vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); @@ -676,11 +676,11 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1); vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1); } else vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, ®ion); diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index a6acaa64e..6f9c6c95b 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -822,7 +822,7 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) } } -static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags) +void Vulkan::setImageLayoutTransitionOptions(bool previous, bool renderTarget, const PixelFormatInfo &info, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags) { switch (layout) { @@ -837,7 +837,20 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, // We use the general image layout for images that are both compute write and readable. // todo: can we optimize this? accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; - stageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + if (renderTarget) + { + if (info.color) + { + accessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + stageFlags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if (info.depth || info.stencil) + { + accessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + stageFlags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + } + } break; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; @@ -849,7 +862,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, break; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: accessMask = VK_ACCESS_SHADER_READ_BIT; - stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: accessMask = VK_ACCESS_TRANSFER_READ_BIT; @@ -868,7 +881,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, } } -void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) +void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) { VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -882,13 +895,14 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima barrier.subresourceRange.baseArrayLayer = baseLayer; barrier.subresourceRange.layerCount = layerCount; + const PixelFormatInfo &info = getPixelFormatInfo(format); + VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; - setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage); - setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage); + setImageLayoutTransitionOptions(true, renderTarget, info, oldLayout, barrier.srcAccessMask, sourceStage); + setImageLayoutTransitionOptions(false, renderTarget, info, newLayout, barrier.dstAccessMask, destinationStage); - const PixelFormatInfo &info = getPixelFormatInfo(format); if (info.color) barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; if (info.depth) diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index 7e4db7c70..6c71b30ea 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/src/modules/graphics/vulkan/Vulkan.h @@ -80,8 +80,11 @@ public: static VkStencilOp getStencilOp(StencilAction); static VkIndexType getVulkanIndexBufferType(IndexDataType type); + static void setImageLayoutTransitionOptions( + bool previous, bool renderTarget, const PixelFormatInfo &info, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags); + static void cmdTransitionImageLayout( - VkCommandBuffer, VkImage, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, + VkCommandBuffer, VkImage, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel = 0, uint32_t levelCount = VK_REMAINING_MIP_LEVELS, uint32_t baseLayer = 0, uint32_t layerCount = VK_REMAINING_ARRAY_LAYERS); };