Refactoring: Add VulkanBlitter, inspired by MetalBlitter.

This is a prep step to fix #3485.
This commit is contained in:
Philip Rideout
2020-11-03 08:54:02 -08:00
parent 9f68daeb8f
commit 89bf201b6c
7 changed files with 216 additions and 132 deletions

View File

@@ -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

View File

@@ -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 <utils/Panic.h>
#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

View File

@@ -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

View File

@@ -41,8 +41,6 @@ static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceP
#include <utils/Panic.h>
#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,

View File

@@ -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

View File

@@ -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<VulkanDriver>()),
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<HwRenderTarget> 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);
}
}

View File

@@ -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;