From 89bf201b6ce489f5c63b57209901cd2cae2d5e23 Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Tue, 3 Nov 2020 08:54:02 -0800 Subject: [PATCH] Refactoring: Add VulkanBlitter, inspired by MetalBlitter. This is a prep step to fix #3485. --- filament/backend/CMakeLists.txt | 2 + filament/backend/src/vulkan/VulkanBlitter.cpp | 135 ++++++++++++++++++ filament/backend/src/vulkan/VulkanBlitter.h | 55 +++++++ filament/backend/src/vulkan/VulkanContext.cpp | 118 --------------- filament/backend/src/vulkan/VulkanContext.h | 8 -- filament/backend/src/vulkan/VulkanDriver.cpp | 28 +++- filament/backend/src/vulkan/VulkanDriver.h | 2 + 7 files changed, 216 insertions(+), 132 deletions(-) create mode 100644 filament/backend/src/vulkan/VulkanBlitter.cpp create mode 100644 filament/backend/src/vulkan/VulkanBlitter.h diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 852af3845c..ef1358fd37 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -128,6 +128,8 @@ if (FILAMENT_SUPPORTS_VULKAN) list(APPEND SRCS src/vulkan/VulkanBinder.cpp src/vulkan/VulkanBinder.h + src/vulkan/VulkanBlitter.cpp + src/vulkan/VulkanBlitter.h src/vulkan/VulkanBuffer.cpp src/vulkan/VulkanBuffer.h src/vulkan/VulkanContext.cpp diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp new file mode 100644 index 0000000000..ef90ca10af --- /dev/null +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VulkanBlitter.h" +#include "VulkanContext.h" +#include "VulkanHandles.h" + +#include + +#define FILAMENT_VULKAN_CHECK_BLIT_FORMAT 0 + +using namespace bluevk; + +namespace filament { +namespace backend { + +void VulkanBlitter::blitColor(VkCommandBuffer cmdBuffer, BlitArgs args) { + const VulkanAttachment src = args.srcTarget->getColor(args.targetIndex); + const VulkanAttachment dst = args.dstTarget->getColor(0); + const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; + +#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT + const VkPhysicalDevice gpu = mContext.physicalDevice; + VkFormatProperties info; + vkGetPhysicalDeviceFormatProperties(gpu, src.format, &info); + if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT, + "Source format is not blittable")) { + return; + } + vkGetPhysicalDeviceFormatProperties(gpu, dst.format, &info); + if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT, + "Destination format is not blittable")) { + return; + } +#endif + + blitFast(aspect, args.filter, args.srcTarget, src, dst, args.srcRectPair, args.dstRectPair, + cmdBuffer); +} + +void VulkanBlitter::blitDepth(VkCommandBuffer cmdBuffer, BlitArgs args) { + const VulkanAttachment src = args.srcTarget->getDepth(); + const VulkanAttachment dst = args.dstTarget->getDepth(); + const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + +#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT + const VkPhysicalDevice gpu = mContext.physicalDevice; + VkFormatProperties info; + vkGetPhysicalDeviceFormatProperties(gpu, src.format, &info); + if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT, + "Depth format is not blittable")) { + return; + } + vkGetPhysicalDeviceFormatProperties(gpu, dst.format, &info); + if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT, + "Depth format is not blittable")) { + return; + } +#endif + + blitFast(aspect, args.filter, args.srcTarget, src, dst, args.srcRectPair, args.dstRectPair, + cmdBuffer); +} + +void VulkanBlitter::blitFast(VkImageAspectFlags aspect, VkFilter filter, + const VulkanRenderTarget* srcTarget, VulkanAttachment src, VulkanAttachment dst, + const VkOffset3D srcRect[2], const VkOffset3D dstRect[2], VkCommandBuffer cmdbuffer) { + const VkImageBlit blitRegions[1] = {{ + .srcSubresource = { aspect, src.level, src.layer, 1 }, + .srcOffsets = { srcRect[0], srcRect[1] }, + .dstSubresource = { aspect, dst.level, dst.layer, 1 }, + .dstOffsets = { dstRect[0], dstRect[1] } + }}; + + const VkExtent2D srcExtent = srcTarget->getExtent(); + + const VkImageResolve resolveRegions[1] = {{ + .srcSubresource = { aspect, src.level, src.layer, 1 }, + .srcOffset = srcRect[0], + .dstSubresource = { aspect, dst.level, dst.layer, 1 }, + .dstOffset = dstRect[0], + .extent = { srcExtent.width, srcExtent.height, 1 } + }}; + + VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src.level, 1, 1, aspect); + + VulkanTexture::transitionImageLayout(cmdbuffer, dst.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst.level, 1, 1, aspect); + + if (src.texture && src.texture->samples > 1 && dst.texture && dst.texture->samples == 1) { + assert(aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported."); + vkCmdResolveImage(cmdbuffer, src.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, resolveRegions); + } else { + vkCmdBlitImage(cmdbuffer, src.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, filter); + } + + if (src.texture) { + VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, + getTextureLayout(src.texture->usage), src.level, 1, 1, aspect); + } else if (!mContext.currentSurface->headlessQueue) { + VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, src.level, 1, 1, aspect); + } + + // Determine the desired texture layout for the destination while ensuring that the default + // render target is supported, which has no associated texture. + const VkImageLayout desiredLayout = dst.texture ? getTextureLayout(dst.texture->usage) : + getSwapContext(mContext).attachment.layout; + + VulkanTexture::transitionImageLayout(cmdbuffer, dst.image, VK_IMAGE_LAYOUT_UNDEFINED, + desiredLayout, dst.level, 1, 1, aspect); +} + +void VulkanBlitter::shutdown() noexcept { + // TODO +} + +} // namespace filament +} // namespace backend diff --git a/filament/backend/src/vulkan/VulkanBlitter.h b/filament/backend/src/vulkan/VulkanBlitter.h new file mode 100644 index 0000000000..329c49a0cc --- /dev/null +++ b/filament/backend/src/vulkan/VulkanBlitter.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_DRIVER_VULKANBLITTER_H +#define TNT_FILAMENT_DRIVER_VULKANBLITTER_H + +#include "VulkanContext.h" + +namespace filament { +namespace backend { + +class VulkanBlitter { +public: + VulkanBlitter(VulkanContext& context) : mContext(context) {} + + struct BlitArgs { + const VulkanRenderTarget* dstTarget; + const VkOffset3D* dstRectPair; + const VulkanRenderTarget* srcTarget; + const VkOffset3D* srcRectPair; + VkFilter filter = VK_FILTER_NEAREST; + int targetIndex = 0; + }; + + void blitColor(VkCommandBuffer cmdBuffer, BlitArgs args); + void blitDepth(VkCommandBuffer cmdBuffer, BlitArgs args); + + void shutdown() noexcept; + +private: + + void blitFast(VkImageAspectFlags aspect, VkFilter filter, const VulkanRenderTarget* srcTarget, + VulkanAttachment src, VulkanAttachment dst, const VkOffset3D srcRect[2], + const VkOffset3D dstRect[2], VkCommandBuffer cmdBuffer); + + VulkanContext& mContext; +}; + +} // namespace filament +} // namespace backend + +#endif // TNT_FILAMENT_DRIVER_VULKANBLITTER_H diff --git a/filament/backend/src/vulkan/VulkanContext.cpp b/filament/backend/src/vulkan/VulkanContext.cpp index 51a2a48a65..66e3b70975 100644 --- a/filament/backend/src/vulkan/VulkanContext.cpp +++ b/filament/backend/src/vulkan/VulkanContext.cpp @@ -41,8 +41,6 @@ static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceP #include -#define FILAMENT_VULKAN_CHECK_BLIT_FORMAT 0 - using namespace bluevk; namespace filament { @@ -841,122 +839,6 @@ VkImageLayout getTextureLayout(TextureUsage usage) { return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } -static void blit(VkImageAspectFlags aspect, VkFilter filter, VulkanContext* context, - const VulkanRenderTarget* srcTarget, VulkanAttachment src, VulkanAttachment dst, - const VkOffset3D srcRect[2], const VkOffset3D dstRect[2], VkCommandBuffer cmdbuffer) { - const VkImageBlit blitRegions[1] = {{ - .srcSubresource = { aspect, src.level, src.layer, 1 }, - .srcOffsets = { srcRect[0], srcRect[1] }, - .dstSubresource = { aspect, dst.level, dst.layer, 1 }, - .dstOffsets = { dstRect[0], dstRect[1] } - }}; - - const VkExtent2D srcExtent = srcTarget->getExtent(); - - const VkImageResolve resolveRegions[1] = {{ - .srcSubresource = { aspect, src.level, src.layer, 1 }, - .srcOffset = srcRect[0], - .dstSubresource = { aspect, dst.level, dst.layer, 1 }, - .dstOffset = dstRect[0], - .extent = { srcExtent.width, srcExtent.height, 1 } - }}; - - VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src.level, 1, 1, aspect); - - VulkanTexture::transitionImageLayout(cmdbuffer, dst.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst.level, 1, 1, aspect); - - if (src.texture && src.texture->samples > 1 && dst.texture && dst.texture->samples == 1) { - assert(aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported."); - vkCmdResolveImage(cmdbuffer, src.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, resolveRegions); - } else { - vkCmdBlitImage(cmdbuffer, src.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, filter); - } - - if (src.texture) { - VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, - getTextureLayout(src.texture->usage), src.level, 1, 1, aspect); - } else if (!context->currentSurface->headlessQueue) { - VulkanTexture::transitionImageLayout(cmdbuffer, src.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, src.level, 1, 1, aspect); - } - - // Determine the desired texture layout for the destination while ensuring that the default - // render target is supported, which has no associated texture. - const VkImageLayout desiredLayout = dst.texture ? getTextureLayout(dst.texture->usage) : - getSwapContext(*context).attachment.layout; - - VulkanTexture::transitionImageLayout(cmdbuffer, dst.image, VK_IMAGE_LAYOUT_UNDEFINED, - desiredLayout, dst.level, 1, 1, aspect); -} - -void blitDepth(VulkanContext* context, const VulkanRenderTarget* dstTarget, - const VkOffset3D dstRect[2], const VulkanRenderTarget* srcTarget, - const VkOffset3D srcRect[2]) { - const VulkanAttachment src = srcTarget->getDepth(); - const VulkanAttachment dst = dstTarget->getDepth(); - const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT; - -#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT - const VkPhysicalDevice gpu = context->physicalDevice; - VkFormatProperties info; - vkGetPhysicalDeviceFormatProperties(gpu, src.format, &info); - if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT, - "Depth format is not blittable")) { - return; - } - vkGetPhysicalDeviceFormatProperties(gpu, dst.format, &info); - if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT, - "Depth format is not blittable")) { - return; - } -#endif - - if (!context->currentCommands) { - VkCommandBuffer cmdbuf = acquireWorkCommandBuffer(*context); - blit(aspect, VK_FILTER_NEAREST, context, srcTarget, src, dst, srcRect, dstRect, cmdbuf); - flushWorkCommandBuffer(*context); - } else { - VkCommandBuffer cmdbuf = context->currentCommands->cmdbuffer; - blit(aspect, VK_FILTER_NEAREST, context, srcTarget, src, dst, srcRect, dstRect, cmdbuf); - } -} - -void blitColor(VulkanContext* context, const VulkanRenderTarget* dstTarget, - const VkOffset3D dstRect[2], const VulkanRenderTarget* srcTarget, - const VkOffset3D srcRect[2], VkFilter filter, int targetIndex) { - const VulkanAttachment src = srcTarget->getColor(targetIndex); - const VulkanAttachment dst = dstTarget->getColor(0); - const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; - -#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT - const VkPhysicalDevice gpu = context->physicalDevice; - VkFormatProperties info; - vkGetPhysicalDeviceFormatProperties(gpu, src.format, &info); - if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT, - "Source format is not blittable")) { - return; - } - vkGetPhysicalDeviceFormatProperties(gpu, dst.format, &info); - if (!ASSERT_POSTCONDITION_NON_FATAL(info.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT, - "Destination format is not blittable")) { - return; - } -#endif - - if (!context->currentCommands) { - VkCommandBuffer cmdbuf = acquireWorkCommandBuffer(*context); - blit(aspect, filter, context, srcTarget, src, dst, srcRect, dstRect, cmdbuf); - flushWorkCommandBuffer(*context); - } else { - VkCommandBuffer cmdbuf = context->currentCommands->cmdbuffer; - blit(aspect, filter, context, srcTarget, src, dst, srcRect, dstRect, cmdbuf); - } -} - void createEmptyTexture(VulkanContext& context, VulkanStagePool& stagePool) { context.emptyTexture = new VulkanTexture(context, SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1, 1, 1, 1, diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index cce1660803..0894e808f1 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -180,14 +180,6 @@ void createFinalDepthBuffer(VulkanContext& context, VulkanSurfaceContext& sc, Vk VkImageLayout getTextureLayout(TextureUsage usage); void createEmptyTexture(VulkanContext& context, VulkanStagePool& stagePool); -void blitDepth(VulkanContext* context, const VulkanRenderTarget* dstTarget, - const VkOffset3D dstRect[2], const VulkanRenderTarget* srcTarget, - const VkOffset3D srcRect[2]); - -void blitColor(VulkanContext* context, const VulkanRenderTarget* dstTarget, - const VkOffset3D dstRect[2], const VulkanRenderTarget* srcTarget, - const VkOffset3D srcRect[2], VkFilter filter, int index); - } // namespace filament } // namespace backend diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 420b5d9e92..163ffcf1c5 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -89,7 +89,10 @@ Driver* VulkanDriverFactory::create(VulkanPlatform* const platform, VulkanDriver::VulkanDriver(VulkanPlatform* platform, const char* const* ppEnabledExtensions, uint32_t enabledExtensionCount) noexcept : DriverBase(new ConcreteDispatcher()), - mContextManager(*platform), mStagePool(mContext, mDisposer), mFramebufferCache(mContext), + mContextManager(*platform), + mBlitter(mContext), + mStagePool(mContext, mDisposer), + mFramebufferCache(mContext), mSamplerCache(mContext) { mContext.rasterState = mBinder.getDefaultRasterState(); @@ -251,6 +254,8 @@ void VulkanDriver::terminate() { delete mContext.emptyTexture; + mBlitter.shutdown(); + mDisposer.release(mContext.work.resources); // Allow the stage pool and disposer to clean up. @@ -1500,24 +1505,35 @@ void VulkanDriver::blit(TargetBufferFlags buffers, Handle dst, V const int32_t dstTop = std::min(dstRect.bottom + dstRect.height, dstExtent.height); const VkOffset3D dstOffsets[2] = { { dstLeft, dstBottom, 0 }, { dstRight, dstTop, 1 }}; + VkCommandBuffer cmdbuf; + if (mContext.currentCommands) { + cmdbuf = mContext.currentCommands->cmdbuffer; + } else { + cmdbuf = acquireWorkCommandBuffer(mContext);; + } + if (any(buffers & TargetBufferFlags::DEPTH) && srcTarget->hasDepth() && dstTarget->hasDepth()) { - blitDepth(&mContext, dstTarget, dstOffsets, srcTarget, srcOffsets); + mBlitter.blitDepth(cmdbuf, {dstTarget, dstOffsets, srcTarget, srcOffsets}); } if (any(buffers & TargetBufferFlags::COLOR0)) { - blitColor(&mContext, dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 0); + mBlitter.blitColor(cmdbuf, {dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 0}); } if (any(buffers & TargetBufferFlags::COLOR1)) { - blitColor(&mContext, dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 1); + mBlitter.blitColor(cmdbuf, {dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 1}); } if (any(buffers & TargetBufferFlags::COLOR2)) { - blitColor(&mContext, dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 2); + mBlitter.blitColor(cmdbuf, {dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 2}); } if (any(buffers & TargetBufferFlags::COLOR3)) { - blitColor(&mContext, dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 3); + mBlitter.blitColor(cmdbuf, {dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, 3}); + } + + if (!mContext.currentCommands) { + flushWorkCommandBuffer(mContext); } } diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index ecba991476..65a517fac5 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -18,6 +18,7 @@ #define TNT_FILAMENT_DRIVER_VULKANDRIVER_H #include "VulkanBinder.h" +#include "VulkanBlitter.h" #include "VulkanDisposer.h" #include "VulkanContext.h" #include "VulkanFboCache.h" @@ -149,6 +150,7 @@ private: VulkanContext mContext = {}; VulkanBinder mBinder; + VulkanBlitter mBlitter; VulkanDisposer mDisposer; VulkanStagePool mStagePool; VulkanFboCache mFramebufferCache;