diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp index f1a30b08b..3e12962d4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp @@ -38,7 +38,7 @@ namespace Nz void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) override; - void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 maxLevel) override; + void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 levelCount, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout) override; void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl index 4ad253a36..7a42c101f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl @@ -10,7 +10,7 @@ namespace Nz { inline void OpenGLTexture::GenerateMipmaps(UInt8 baseLevel, UInt8 levelCount) { - NazaraAssert(baseLevel + levelCount < m_textureInfo.levelCount, "out of bounds"); + NazaraAssert(baseLevel + levelCount <= m_textureInfo.levelCount, "out of bounds"); GL::Texture* targetTexture; if (RequiresTextureViewEmulation()) @@ -26,7 +26,7 @@ namespace Nz targetTexture->SetParameteri(GL_TEXTURE_BASE_LEVEL, baseLevel); if (levelCount != m_textureInfo.levelCount) - targetTexture->SetParameteri(GL_TEXTURE_MAX_LEVEL, levelCount); + targetTexture->SetParameteri(GL_TEXTURE_MAX_LEVEL, levelCount - 1); targetTexture->GenerateMipmap(); @@ -35,7 +35,7 @@ namespace Nz targetTexture->SetParameteri(GL_TEXTURE_BASE_LEVEL, 0); if (levelCount != m_textureInfo.levelCount) - targetTexture->SetParameteri(GL_TEXTURE_MAX_LEVEL, m_textureInfo.levelCount); + targetTexture->SetParameteri(GL_TEXTURE_MAX_LEVEL, m_textureInfo.levelCount - 1); } inline PixelFormat OpenGLTexture::GetFormat() const diff --git a/include/Nazara/Renderer/CommandBufferBuilder.hpp b/include/Nazara/Renderer/CommandBufferBuilder.hpp index 6c879393a..2ac4032d8 100644 --- a/include/Nazara/Renderer/CommandBufferBuilder.hpp +++ b/include/Nazara/Renderer/CommandBufferBuilder.hpp @@ -54,7 +54,7 @@ namespace Nz virtual void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) = 0; - virtual void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 maxLevel) = 0; + virtual void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 levelCount, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout) = 0; inline void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target); virtual void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 fromOffset = 0, UInt64 toOffset = 0) = 0; diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp index 271bae143..346f4ec29 100644 --- a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp +++ b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp @@ -38,7 +38,7 @@ namespace Nz void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) override; - void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 maxLevel) override; + void BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 levelCount, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout) override; void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl index f39b671f4..fedab15e6 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -553,20 +553,7 @@ namespace Nz break; } - VkImageMemoryBarrier imageBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType - nullptr, // const void* pNext - srcAccessMask, // VkAccessFlags srcAccessMask - dstAccessMask, // VkAccessFlags dstAccessMask - oldImageLayout, // VkImageLayout oldLayout - newImageLayout, // VkImageLayout newLayout - VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex - VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex - image, // VkImage image - subresourceRange // VkImageSubresourceRange subresourceRange - }; - - return PipelineBarrier(srcStageMask, dstStageMask, 0, imageBarrier); + return ImageBarrier(srcStageMask, dstStageMask, 0, srcAccessMask, dstAccessMask, oldImageLayout, newImageLayout, image, subresourceRange); } inline void CommandBuffer::SetViewport(const Rectf& viewport, float minDepth, float maxDepth) diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp index 2808c8f9f..fef6bc711 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp @@ -93,11 +93,11 @@ namespace Nz m_commandBuffer.BlitTexture(sourceTexture, fromBox, targetTexture, toBox, filter); } - void OpenGLCommandBufferBuilder::BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 maxLevel) + void OpenGLCommandBufferBuilder::BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 levelCount, PipelineStageFlags srcStageMask, PipelineStageFlags /*dstStageMask*/, MemoryAccessFlags /*srcAccessMask*/, MemoryAccessFlags /*dstAccessMask*/, TextureLayout /*oldLayout*/, TextureLayout /*newLayout*/) { OpenGLTexture& glTexture = static_cast(texture); - glTexture.GenerateMipmaps(baseLevel, maxLevel); + m_commandBuffer.BuildMipmaps(glTexture, baseLevel, levelCount); } void OpenGLCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp index 092384374..d150f297a 100644 --- a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp +++ b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp @@ -179,20 +179,18 @@ namespace Nz m_commandBuffer.BlitImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region, ToVulkan(filter)); } - void VulkanCommandBufferBuilder::BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 maxLevel) + void VulkanCommandBufferBuilder::BuildMipmaps(Texture& texture, UInt8 baseLevel, UInt8 levelCount, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout) { - NazaraAssert(maxLevel >= baseLevel, "maxLevel must be greater than baseLevel"); - VulkanTexture& vkTexture = static_cast(texture); VkImage vkImage = vkTexture.GetImage(); const TextureInfo& textureInfo = vkTexture.GetTextureInfo(); + levelCount = std::min(levelCount, textureInfo.levelCount); + Vector3i32 mipSize(SafeCast(textureInfo.width), SafeCast(textureInfo.height), SafeCast(textureInfo.depth)); Vector3i32 prevMipSize = mipSize; - std::size_t levelCount = maxLevel - baseLevel + 1; - if (baseLevel != 0) { mipSize.x >>= baseLevel; @@ -201,34 +199,44 @@ namespace Nz mipSize.Maximize({ 1, 1, 1 }); } - for (std::size_t i = 0; i < levelCount; ++i) + // Transition all mips to transfer dst, except for the base level + m_commandBuffer.ImageBarrier(ToVulkan(srcStageMask), VK_PIPELINE_STAGE_TRANSFER_BIT, 0, ToVulkan(srcAccessMask), VK_ACCESS_TRANSFER_READ_BIT, ToVulkan(oldLayout), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vkImage, vkTexture.BuildSubresourceRange(baseLevel, 1)); + m_commandBuffer.ImageBarrier(ToVulkan(srcStageMask), VK_PIPELINE_STAGE_TRANSFER_BIT, 0, ToVulkan(srcAccessMask), VK_ACCESS_TRANSFER_WRITE_BIT, ToVulkan(oldLayout), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vkImage, vkTexture.BuildSubresourceRange(baseLevel + 1, levelCount - 1)); + + for (UInt8 i = 1; i < levelCount; ++i) { mipSize /= 2; mipSize.Maximize({ 1, 1, 1 }); + // Transition previous mip to transfer src, as it will serve as a source for the next blit (base mip is already in transfer src) + if (i != 1) + { + VkImageSubresourceRange prevMipmapRange = vkTexture.BuildSubresourceRange(baseLevel + i - 1, 1); + m_commandBuffer.ImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vkImage, prevMipmapRange); + } + + // Blit previous mipmap to next mipmap VkImageBlit blitRegion = { - vkTexture.BuildSubresourceLayers(i - 1), + vkTexture.BuildSubresourceLayers(baseLevel + i - 1), { //< srcOffsets { 0, 0, 0 }, { prevMipSize.x, prevMipSize.y, prevMipSize.z } }, - vkTexture.BuildSubresourceLayers(i), + vkTexture.BuildSubresourceLayers(baseLevel + i), { //< dstOffsets { 0, 0, 0 }, { mipSize.x, mipSize.y, mipSize.z } }, }; - VkImageSubresourceRange prevMipmapRange = vkTexture.BuildSubresourceRange(i - 1, 1, 0, textureInfo.layerCount); - - m_commandBuffer.SetImageLayout(vkImage, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, prevMipmapRange); - m_commandBuffer.BlitImage(vkImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, blitRegion, VK_FILTER_LINEAR); - m_commandBuffer.SetImageLayout(vkImage, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, prevMipmapRange); - prevMipSize = mipSize; } + + // Transition all mips (which are now in transfer src, except for the last one which is still in transfer dst) to the target layout + m_commandBuffer.ImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, ToVulkan(dstStageMask), 0, VK_ACCESS_TRANSFER_READ_BIT, ToVulkan(dstAccessMask), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, ToVulkan(newLayout), vkImage, vkTexture.BuildSubresourceRange(baseLevel, levelCount - 1)); + m_commandBuffer.ImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, ToVulkan(dstStageMask), 0, VK_ACCESS_TRANSFER_WRITE_BIT, ToVulkan(dstAccessMask), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, ToVulkan(newLayout), vkImage, vkTexture.BuildSubresourceRange(levelCount - 1, 1)); } void VulkanCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) diff --git a/tests/ComputeParticlesTest/main.cpp b/tests/ComputeParticlesTest/main.cpp index 9e4dd3d10..12456c10e 100644 --- a/tests/ComputeParticlesTest/main.cpp +++ b/tests/ComputeParticlesTest/main.cpp @@ -572,7 +572,7 @@ std::shared_ptr GenerateSpriteTexture(Nz::RenderDevice& device, std builder.BindComputeShaderBinding(0, *binding); builder.Dispatch(texParams.width / 32, texParams.height / 32, 1); - builder.TextureBarrier(Nz::PipelineStage::ComputeShader, Nz::PipelineStage::FragmentShader, Nz::MemoryAccess::ShaderWrite, Nz::MemoryAccess::ShaderRead, Nz::TextureLayout::General, Nz::TextureLayout::ColorInput, *targetTexture); + builder.BuildMipmaps(*targetTexture, 0, targetTexture->GetLevelCount(), Nz::PipelineStage::ComputeShader, Nz::PipelineStage::FragmentShader, Nz::MemoryAccess::ShaderWrite, Nz::MemoryAccess::ShaderRead, Nz::TextureLayout::General, Nz::TextureLayout::ColorInput); }, Nz::QueueType::Compute);