From 6de05f13f1aed8eb85aad44b443a70f9bf0823bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 31 May 2023 14:10:36 +0200 Subject: [PATCH] More barrier batching --- Common/GPU/Vulkan/VulkanBarrier.h | 11 ++- Common/GPU/Vulkan/VulkanFramebuffer.cpp | 24 +++-- Common/GPU/Vulkan/VulkanFramebuffer.h | 5 +- Common/GPU/Vulkan/VulkanImage.cpp | 107 +++++++++++++--------- Common/GPU/Vulkan/VulkanImage.h | 4 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 18 ++-- Common/GPU/Vulkan/VulkanQueueRunner.h | 4 +- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- Common/GPU/Vulkan/VulkanRenderManager.h | 4 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 19 ++-- 10 files changed, 116 insertions(+), 82 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanBarrier.h b/Common/GPU/Vulkan/VulkanBarrier.h index 72fae64d61..7a0283ed2d 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.h +++ b/Common/GPU/Vulkan/VulkanBarrier.h @@ -13,9 +13,10 @@ class VulkanContext; class VulkanBarrierBatch { public: ~VulkanBarrierBatch() { - _dbg_assert_(false); + _dbg_assert_(imageBarriers_.empty()); } - VkImageMemoryBarrier &Add(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) { + + VkImageMemoryBarrier *Add(VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) { srcStageMask_ |= srcStageMask; dstStageMask_ |= dstStageMask; dependencyFlags_ |= dependencyFlags; @@ -30,8 +31,10 @@ public: barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.layerCount = 1; barrier.subresourceRange.levelCount = 1; - return barrier; + barrier.image = image; + return &barrier; } + void Flush(VkCommandBuffer cmd) { if (!imageBarriers_.empty()) { vkCmdPipelineBarrier(cmd, srcStageMask_, dstStageMask_, dependencyFlags_, 0, nullptr, 0, nullptr, (uint32_t)imageBarriers_.size(), imageBarriers_.data()); @@ -42,6 +45,8 @@ public: } } + bool empty() const { return imageBarriers_.empty(); } + private: FastVec imageBarriers_; VkPipelineStageFlags srcStageMask_ = 0; diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index aceb2db6e1..f3702180b9 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -56,23 +56,23 @@ void VKRImage::Delete(VulkanContext *vulkan) { } } -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag) +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VulkanBarrierBatch *barriers, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { _dbg_assert_(tag); - CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + CreateImage(vulkan_, barriers, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + CreateImage(vulkan_, barriers, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); } if (_multiSampleLevel > 0) { sampleCount = MultiSampleLevelToFlagBits(_multiSampleLevel); // TODO: Create a different tag for these? - CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + CreateImage(vulkan_, barriers, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, msaaDepth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + CreateImage(vulkan_, barriers, initCmd, msaaDepth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); } } else { sampleCount = VK_SAMPLE_COUNT_1_BIT; @@ -161,7 +161,7 @@ VKRFramebuffer::~VKRFramebuffer() { // NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. // This requires a different sampling path! -void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { +void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VulkanBarrierBatch *barriers, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { // We don't support more exotic layer setups for now. Mono or stereo. _dbg_assert_(numLayers == 1 || numLayers == 2); @@ -251,10 +251,14 @@ void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKR return; } - TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects, - VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, - 0, dstAccessMask); + VkImageMemoryBarrier *barrier = barriers->Add(img.image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, 0); + barrier->subresourceRange.layerCount = numLayers; + barrier->subresourceRange.aspectMask = aspects; + barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier->newLayout = initialLayout; + barrier->srcAccessMask = 0; + barrier->dstAccessMask = dstAccessMask; + img.layout = initialLayout; img.format = format; img.sampleCount = sampleCount; diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h index 97ff9e367a..b807de8803 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.h +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -4,6 +4,7 @@ #include "Common/GPU/Vulkan/VulkanContext.h" class VKRRenderPass; +class VulkanBarrierBatch; // Pipelines need to be created for the right type of render pass. // TODO: Rename to RenderPassFlags? @@ -57,7 +58,7 @@ struct VKRImage { class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag); + VKRFramebuffer(VulkanContext *vk, VulkanBarrierBatch *barriers, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag); ~VKRFramebuffer(); VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); @@ -94,7 +95,7 @@ public: VulkanContext *Vulkan() const { return vulkan_; } private: - static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); + static void CreateImage(VulkanContext *vulkan, VulkanBarrierBatch *barriers, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index d3dce6356a..ebe6248bba 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -5,6 +5,7 @@ #include "Common/GPU/Vulkan/VulkanAlloc.h" #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/Vulkan/VulkanBarrier.h" #include "Common/StringUtils.h" using namespace PPSSPP_VK; @@ -90,20 +91,21 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i vulkan_->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_); // Write a command to transition the image to the requested layout, if it's not already that layout. + // TODO: We may generate mipmaps right after, so can't add to the end of frame batch. Well actually depending + // on the amount of mips we probably sometimes can.. + if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { + VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + VkAccessFlagBits dstAccessFlags; switch (initialLayout) { case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, VK_ACCESS_TRANSFER_WRITE_BIT); + dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dstAccessFlags = VK_ACCESS_TRANSFER_WRITE_BIT; break; case VK_IMAGE_LAYOUT_GENERAL: // We use this initial layout when we're about to write to the image using a compute shader, only. - TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, VK_ACCESS_SHADER_WRITE_BIT); + dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dstAccessFlags = VK_ACCESS_SHADER_READ_BIT; break; default: // If you planned to use UploadMip, you want VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. After the @@ -111,6 +113,10 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(false); break; } + TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, + 0, dstAccessFlags); } // Create the view while we're at it. @@ -205,24 +211,29 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo _assert_msg_(firstMipToGenerate > 0, "Cannot generate the first level"); _assert_msg_(firstMipToGenerate < numMips_, "Can't generate levels beyond storage"); + VulkanBarrierBatch batch; // Transition the pre-set levels to GENERAL. - TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT, - fromCompute ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - fromCompute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - fromCompute ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT); - // Do the same with the uninitialized levels, transition from UNDEFINED. - TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, 1, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_GENERAL, + VkImageMemoryBarrier *barrier = batch.Add(image_, + fromCompute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0); + barrier->oldLayout = fromCompute ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->srcAccessMask = fromCompute ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_TRANSFER_WRITE_BIT; + barrier->dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier->subresourceRange.levelCount = firstMipToGenerate; + + barrier = batch.Add(image_, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT); + VK_PIPELINE_STAGE_TRANSFER_BIT, 0); + barrier->subresourceRange.baseMipLevel = firstMipToGenerate; + barrier->subresourceRange.levelCount = numMips_ - firstMipToGenerate; + barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->srcAccessMask = 0; + barrier->dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + batch.Flush(cmd); // Now we can blit and barrier the whole pipeline. for (int mip = firstMipToGenerate; mip < numMips_; mip++) { @@ -248,35 +259,45 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo vkCmdBlitImage(cmd, image_, VK_IMAGE_LAYOUT_GENERAL, image_, VK_IMAGE_LAYOUT_GENERAL, 1, &blit, VK_FILTER_LINEAR); - TransitionImageLayout2(cmd, image_, mip, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + barrier = batch.Add(image_, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0); + barrier->subresourceRange.baseMipLevel = mip; + barrier->oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier->dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + batch.Flush(cmd); } } void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture, VkPipelineStageFlags prevStage, VkImageLayout layout) { - TransitionImageLayout2(cmd, image_, 0, numMips_, 1, - VK_IMAGE_ASPECT_COLOR_BIT, - layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - prevStage, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - prevStage == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + VulkanBarrierBatch batch; + VkImageMemoryBarrier *barrier = batch.Add(image_, prevStage, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0); + barrier->subresourceRange.levelCount = numMips_; + barrier->oldLayout = layout; + barrier->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier->srcAccessMask = prevStage == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_TRANSFER_WRITE_BIT; + barrier->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + batch.Flush(cmd); } void VulkanTexture::PrepareForTransferDst(VkCommandBuffer cmd, int levels) { - TransitionImageLayout2(cmd, image_, 0, levels, 1, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); + VulkanBarrierBatch batch; + VkImageMemoryBarrier *barrier = batch.Add(image_, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0); + barrier->subresourceRange.levelCount = levels; + barrier->srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier->dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier->oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier->newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + batch.Flush(cmd); } -void VulkanTexture::RestoreAfterTransferDst(VkCommandBuffer cmd, int levels) { - TransitionImageLayout2(cmd, image_, 0, levels, 1, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +void VulkanTexture::RestoreAfterTransferDst(int levels, VulkanBarrierBatch *barriers) { + VkImageMemoryBarrier *barrier = barriers->Add(image_, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0); + barrier->subresourceRange.levelCount = levels; + barrier->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier->oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } VkImageView VulkanTexture::CreateViewForMip(int mip) { diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index 41d7fe72ce..4adaf4f1a1 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -7,6 +7,8 @@ class VulkanDeviceAllocator; VK_DEFINE_HANDLE(VmaAllocation); +class VulkanBarrierBatch; + struct TextureCopyBatch { std::vector copies; VkBuffer buffer = VK_NULL_HANDLE; @@ -39,7 +41,7 @@ public: // For updating levels after creation. Careful with the timelines! void PrepareForTransferDst(VkCommandBuffer cmd, int levels); - void RestoreAfterTransferDst(VkCommandBuffer cmd, int levels); + void RestoreAfterTransferDst(int levels, VulkanBarrierBatch *barriers); // When loading mips from compute shaders, you need to pass VK_IMAGE_LAYOUT_GENERAL to the above function. // In addition, ignore UploadMip and GenerateMip, and instead use GetViewForMip. Make sure to delete the returned views when used. diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 9be5da0364..29c4350bdb 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -80,7 +80,7 @@ void VulkanQueueRunner::DestroyDeviceObjects() { renderPasses_.Clear(); } -bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { +bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit, VulkanBarrierBatch *barriers) { VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr); _dbg_assert_(res == VK_SUCCESS); @@ -123,7 +123,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { delete[] swapchainImages; // Must be before InitBackbufferRenderPass. - if (InitDepthStencilBuffer(cmdInit)) { + if (InitDepthStencilBuffer(cmdInit, barriers)) { InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); } return true; @@ -157,7 +157,7 @@ bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) { return true; } -bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { +bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd, VulkanBarrierBatch *barriers) { const VkFormat depth_format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat; int aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; @@ -189,12 +189,14 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth"); - TransitionImageLayout2(cmd, depth_.image, 0, 1, 1, - aspectMask, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VkImageMemoryBarrier *barrier = barriers->Add(depth_.image, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0); + barrier->subresourceRange.aspectMask = aspectMask; + barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier->newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barrier->srcAccessMask = 0; + barrier->dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; VkImageViewCreateInfo depth_view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; depth_view_info.image = depth_.image; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 590e821432..c68a4e8b7d 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -230,7 +230,7 @@ public: // Swapchain void DestroyBackBuffers(); - bool CreateSwapchain(VkCommandBuffer cmdInit); + bool CreateSwapchain(VkCommandBuffer cmdInit, VulkanBarrierBatch *barriers); bool HasBackbuffers() const { return !framebuffers_.empty(); @@ -277,7 +277,7 @@ public: private: bool InitBackbufferFramebuffers(int width, int height); - bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. + bool InitDepthStencilBuffer(VkCommandBuffer cmd, VulkanBarrierBatch *barriers); // Used for non-buffered rendering. VKRRenderPass *PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd); void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd, int curFrame, QueueProfileContext &profile); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 9dc8db917f..17f93040c3 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -291,7 +291,7 @@ bool VulkanRenderManager::CreateBackbuffers() { VkCommandBuffer cmdInit = GetInitCmd(); - if (!queueRunner_.CreateSwapchain(cmdInit)) { + if (!queueRunner_.CreateSwapchain(cmdInit, &postInitBarrier_)) { return false; } diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 6b07b0c198..9dbb450d0c 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -538,7 +538,7 @@ public: void Invalidate(InvalidationFlags flags); - VulkanBarrier &PostInitBarrier() { + VulkanBarrierBatch &PostInitBarrier() { return postInitBarrier_; } @@ -633,7 +633,7 @@ private: SimpleStat renderCPUTimeMs_; SimpleStat descUpdateTimeMs_; - VulkanBarrier postInitBarrier_; + VulkanBarrierBatch postInitBarrier_; std::function invalidationCallback_; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 5d47efb3a4..572cb8fbc8 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -331,8 +331,8 @@ public: : vulkan_(vulkan), mipLevels_(desc.mipLevels) { format_ = desc.format; } - bool Create(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const TextureDesc &desc); - void Update(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels); + bool Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const TextureDesc &desc); + void Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels); ~VKTexture() { Destroy(); @@ -759,7 +759,7 @@ enum class TextureState { PENDING_DESTRUCTION, }; -bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const TextureDesc &desc) { +bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const TextureDesc &desc) { // Zero-sized textures not allowed. _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! if (desc.width * desc.height * desc.depth <= 0) { @@ -799,25 +799,24 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const Te return true; } -void VKTexture::Update(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) { +void VKTexture::Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) { // Before we can use UpdateInternal, we need to transition the image to the same state as after CreateDirect, // making it ready for writing. vkTex_->PrepareForTransferDst(cmd, numLevels); UpdateInternal(cmd, pushBuffer, data, initDataCallback, numLevels); - vkTex_->RestoreAfterTransferDst(cmd, numLevels); + vkTex_->RestoreAfterTransferDst(numLevels, postBarriers); } void VKTexture::UpdateInternal(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) { int w = width_; int h = height_; int d = depth_; - int i; VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); int bytesPerPixel = bpp / 8; TextureCopyBatch batch; batch.reserve(numLevels); - for (i = 0; i < numLevels; i++) { + for (int i = 0; i < numLevels; i++) { uint32_t offset; VkBuffer buf; size_t size = w * h * d * bytesPerPixel; @@ -1294,7 +1293,7 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) { return nullptr; } VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc); - if (tex->Create(initCmd, push_, desc)) { + if (tex->Create(initCmd, &renderManager_.PostInitBarrier(), push_, desc)) { return tex; } else { ERROR_LOG(G3D, "Failed to create texture"); @@ -1314,7 +1313,7 @@ void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, Text VKTexture *tex = (VKTexture *)texture; _dbg_assert_(numLevels <= tex->NumLevels()); - tex->Update(initCmd, push_, data, initDataCallback, numLevels); + tex->Update(initCmd, &renderManager_.PostInitBarrier(), push_, data, initDataCallback, numLevels); } static inline void CopySide(VkStencilOpState &dest, const StencilSetup &src) { @@ -1627,7 +1626,7 @@ Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { _assert_(desc.height > 0); VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, &renderManager_.PostInitBarrier(), cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag); return new VKFramebuffer(vkrfb, desc.multiSampleLevel); }