From b322ce3a583fb0c1999b74ea554d7307ec58a3ce Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 14 May 2024 16:50:09 -0700 Subject: [PATCH] [Impeller] immediately encode blit commands for Vulkan. (flutter/engine#52794) No reason to defer encoding. Just like cmd buffers, we can immediately encode this. Reduce heap allocation of command objects, which were additionally stored in unique ptrs for extra memory inefficiency. --- .../flutter/ci/licenses_golden/excluded_files | 1 - .../ci/licenses_golden/licenses_flutter | 4 - .../impeller/renderer/backend/vulkan/BUILD.gn | 3 - .../backend/vulkan/blit_command_vk.cc | 422 ------------------ .../renderer/backend/vulkan/blit_command_vk.h | 67 --- .../vulkan/blit_command_vk_unittests.cc | 82 ---- .../renderer/backend/vulkan/blit_pass_vk.cc | 398 ++++++++++++++--- .../renderer/backend/vulkan/blit_pass_vk.h | 6 +- .../backend/vulkan/command_buffer_vk.cc | 2 +- .../vulkan/test/gpu_tracer_unittests.cc | 2 +- 10 files changed, 352 insertions(+), 635 deletions(-) delete mode 100644 engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc delete mode 100644 engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.h delete mode 100644 engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index da0300ef0a3..37cc6dec125 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -169,7 +169,6 @@ ../../../flutter/impeller/renderer/backend/gles/test ../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk_unittests.cc -../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index f6761efd072..325022f93d6 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -42706,8 +42706,6 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_so ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc + ../../../flutter/LICENSE @@ -45579,8 +45577,6 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_sour FILE: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.h -FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc -FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn index 04693bf9dab..def2b26dbf7 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn @@ -9,7 +9,6 @@ impeller_component("vulkan_unittests") { testonly = true sources = [ "allocator_vk_unittests.cc", - "blit_command_vk_unittests.cc", "command_encoder_vk_unittests.cc", "command_pool_vk_unittests.cc", "context_vk_unittests.cc", @@ -38,8 +37,6 @@ impeller_component("vulkan") { "allocator_vk.h", "barrier_vk.cc", "barrier_vk.h", - "blit_command_vk.cc", - "blit_command_vk.h", "blit_pass_vk.cc", "blit_pass_vk.h", "capabilities_vk.cc", diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc deleted file mode 100644 index bc1c2194782..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "impeller/renderer/backend/vulkan/blit_command_vk.h" - -#include - -#include "impeller/renderer/backend/vulkan/barrier_vk.h" -#include "impeller/renderer/backend/vulkan/command_encoder_vk.h" -#include "impeller/renderer/backend/vulkan/texture_vk.h" -#include "vulkan/vulkan_core.h" -#include "vulkan/vulkan_enums.hpp" -#include "vulkan/vulkan_structs.hpp" - -namespace impeller { - -static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, - const vk::Image& image, - vk::AccessFlags src_access_mask, - vk::AccessFlags dst_access_mask, - vk::ImageLayout old_layout, - vk::ImageLayout new_layout, - vk::PipelineStageFlags src_stage, - vk::PipelineStageFlags dst_stage, - uint32_t base_mip_level, - uint32_t mip_level_count = 1u) { - if (old_layout == new_layout) { - return; - } - - vk::ImageMemoryBarrier barrier; - barrier.srcAccessMask = src_access_mask; - barrier.dstAccessMask = dst_access_mask; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - barrier.subresourceRange.baseMipLevel = base_mip_level; - barrier.subresourceRange.levelCount = mip_level_count; - barrier.subresourceRange.baseArrayLayer = 0u; - barrier.subresourceRange.layerCount = 1u; - - cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier); -} - -BlitEncodeVK::~BlitEncodeVK() = default; - -//------------------------------------------------------------------------------ -/// BlitCopyTextureToTextureCommandVK -/// - -BlitCopyTextureToTextureCommandVK::~BlitCopyTextureToTextureCommandVK() = - default; - -std::string BlitCopyTextureToTextureCommandVK::GetLabel() const { - return label; -} - -bool BlitCopyTextureToTextureCommandVK::Encode( - CommandEncoderVK& encoder) const { - const auto& cmd_buffer = encoder.GetCommandBuffer(); - - const auto& src = TextureVK::Cast(*source); - const auto& dst = TextureVK::Cast(*destination); - - if (!encoder.Track(source) || !encoder.Track(destination)) { - return false; - } - - BarrierVK src_barrier; - src_barrier.cmd_buffer = cmd_buffer; - src_barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal; - src_barrier.src_access = vk::AccessFlagBits::eTransferWrite | - vk::AccessFlagBits::eShaderWrite | - vk::AccessFlagBits::eColorAttachmentWrite; - src_barrier.src_stage = vk::PipelineStageFlagBits::eTransfer | - vk::PipelineStageFlagBits::eFragmentShader | - vk::PipelineStageFlagBits::eColorAttachmentOutput; - src_barrier.dst_access = vk::AccessFlagBits::eTransferRead; - src_barrier.dst_stage = vk::PipelineStageFlagBits::eTransfer; - - BarrierVK dst_barrier; - dst_barrier.cmd_buffer = cmd_buffer; - dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal; - dst_barrier.src_access = {}; - dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; - dst_barrier.dst_access = - vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite; - dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader | - vk::PipelineStageFlagBits::eTransfer; - - if (!src.SetLayout(src_barrier) || !dst.SetLayout(dst_barrier)) { - VALIDATION_LOG << "Could not complete layout transitions."; - return false; - } - - vk::ImageCopy image_copy; - - image_copy.setSrcSubresource( - vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); - image_copy.setDstSubresource( - vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); - - image_copy.srcOffset = - vk::Offset3D(source_region.GetX(), source_region.GetY(), 0); - image_copy.dstOffset = - vk::Offset3D(destination_origin.x, destination_origin.y, 0); - image_copy.extent = - vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1); - - // Issue the copy command now that the images are already in the right - // layouts. - cmd_buffer.copyImage(src.GetImage(), // - src_barrier.new_layout, // - dst.GetImage(), // - dst_barrier.new_layout, // - image_copy // - ); - - // If this is an onscreen texture, do not transition the layout - // back to shader read. - if (dst.IsSwapchainImage()) { - return true; - } - - BarrierVK barrier; - barrier.cmd_buffer = cmd_buffer; - barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.src_access = {}; - barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; - barrier.dst_access = vk::AccessFlagBits::eShaderRead; - barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; - - return dst.SetLayout(barrier); -} - -//------------------------------------------------------------------------------ -/// BlitCopyTextureToBufferCommandVK -/// - -BlitCopyTextureToBufferCommandVK::~BlitCopyTextureToBufferCommandVK() = default; - -std::string BlitCopyTextureToBufferCommandVK::GetLabel() const { - return label; -} - -bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const { - const auto& cmd_buffer = encoder.GetCommandBuffer(); - - // cast source and destination to TextureVK - const auto& src = TextureVK::Cast(*source); - - if (!encoder.Track(source) || !encoder.Track(destination)) { - return false; - } - - BarrierVK barrier; - barrier.cmd_buffer = cmd_buffer; - barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal; - barrier.src_access = vk::AccessFlagBits::eShaderWrite | - vk::AccessFlagBits::eTransferWrite | - vk::AccessFlagBits::eColorAttachmentWrite; - barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader | - vk::PipelineStageFlagBits::eTransfer | - vk::PipelineStageFlagBits::eColorAttachmentOutput; - barrier.dst_access = vk::AccessFlagBits::eShaderRead; - barrier.dst_stage = vk::PipelineStageFlagBits::eVertexShader | - vk::PipelineStageFlagBits::eFragmentShader; - - const auto& dst = DeviceBufferVK::Cast(*destination); - - vk::BufferImageCopy image_copy; - image_copy.setBufferOffset(destination_offset); - image_copy.setBufferRowLength(0); - image_copy.setBufferImageHeight(0); - image_copy.setImageSubresource( - vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); - image_copy.setImageOffset( - vk::Offset3D(source_region.GetX(), source_region.GetY(), 0)); - image_copy.setImageExtent( - vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1)); - - if (!src.SetLayout(barrier)) { - VALIDATION_LOG << "Could not encode layout transition."; - return false; - } - - cmd_buffer.copyImageToBuffer(src.GetImage(), // - barrier.new_layout, // - dst.GetBuffer(), // - image_copy // - ); - - // If the buffer is used for readback, then apply a transfer -> host memory - // barrier. - if (destination->GetDeviceBufferDescriptor().readback) { - vk::MemoryBarrier barrier; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eHostRead; - - cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eHost, {}, 1, - &barrier, 0, {}, 0, {}); - } - - return true; -} - -//------------------------------------------------------------------------------ -/// BlitCopyBufferToTextureCommandVK -/// - -BlitCopyBufferToTextureCommandVK::~BlitCopyBufferToTextureCommandVK() = default; - -std::string BlitCopyBufferToTextureCommandVK::GetLabel() const { - return label; -} - -bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const { - const auto& cmd_buffer = encoder.GetCommandBuffer(); - - // cast destination to TextureVK - const auto& dst = TextureVK::Cast(*destination); - const auto& src = DeviceBufferVK::Cast(*source.buffer); - - if (!encoder.Track(source.buffer) || !encoder.Track(destination)) { - return false; - } - - BarrierVK dst_barrier; - dst_barrier.cmd_buffer = cmd_buffer; - dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal; - dst_barrier.src_access = {}; - dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; - dst_barrier.dst_access = - vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite; - dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader | - vk::PipelineStageFlagBits::eTransfer; - - vk::BufferImageCopy image_copy; - image_copy.setBufferOffset(source.range.offset); - image_copy.setBufferRowLength(0); - image_copy.setBufferImageHeight(0); - image_copy.setImageSubresource( - vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); - image_copy.imageOffset.x = destination_region.GetX(); - image_copy.imageOffset.y = destination_region.GetY(); - image_copy.imageOffset.z = 0u; - image_copy.imageExtent.width = destination_region.GetWidth(); - image_copy.imageExtent.height = destination_region.GetHeight(); - image_copy.imageExtent.depth = 1u; - - if (!dst.SetLayout(dst_barrier)) { - VALIDATION_LOG << "Could not encode layout transition."; - return false; - } - - cmd_buffer.copyBufferToImage(src.GetBuffer(), // - dst.GetImage(), // - dst_barrier.new_layout, // - image_copy // - ); - - // Transition to shader-read. - { - BarrierVK barrier; - barrier.cmd_buffer = cmd_buffer; - barrier.src_access = vk::AccessFlagBits::eTransferWrite; - barrier.src_stage = vk::PipelineStageFlagBits::eTransfer; - barrier.dst_access = vk::AccessFlagBits::eShaderRead; - barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; - - barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; - - if (!dst.SetLayout(barrier)) { - return false; - } - } - - return true; -} - -//------------------------------------------------------------------------------ -/// BlitGenerateMipmapCommandVK -/// - -BlitGenerateMipmapCommandVK::~BlitGenerateMipmapCommandVK() = default; - -std::string BlitGenerateMipmapCommandVK::GetLabel() const { - return label; -} - -bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { - auto& src = TextureVK::Cast(*texture); - - const auto size = src.GetTextureDescriptor().size; - uint32_t mip_count = src.GetTextureDescriptor().mip_count; - - if (mip_count < 2u) { - return true; - } - - const auto& image = src.GetImage(); - const auto& cmd = encoder.GetCommandBuffer(); - - if (!encoder.Track(texture)) { - return false; - } - - // Initialize all mip levels to be in TransferDst mode. Later, in a loop, - // after writing to that mip level, we'll first switch its layout to - // TransferSrc to prepare the mip level after it, use the image as the source - // of the blit, before finally switching it to ShaderReadOnly so its available - // for sampling in a shader. - InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - vk::AccessFlagBits::eTransferWrite, // src access mask - vk::AccessFlagBits::eTransferRead, // dst access mask - src.GetLayout(), // old layout - vk::ImageLayout::eTransferDstOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eTransfer, // dst stage - 0u, // mip level - mip_count // mip level count - ); - - vk::ImageMemoryBarrier barrier; - barrier.image = image; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.subresourceRange.levelCount = 1; - - // Blit from the mip level N - 1 to mip level N. - size_t width = size.width; - size_t height = size.height; - for (size_t mip_level = 1u; mip_level < mip_count; mip_level++) { - barrier.subresourceRange.baseMipLevel = mip_level - 1; - barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; - barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; - - // We just finished writing to the previous (N-1) mip level or it was the - // base mip level. These were initialized to TransferDst earler. We are now - // going to read from it to write to the current level (N) . So it must be - // converted to TransferSrc. - cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, - {barrier}); - - vk::ImageBlit blit; - blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; - blit.srcSubresource.baseArrayLayer = 0u; - blit.srcSubresource.layerCount = 1u; - blit.srcSubresource.mipLevel = mip_level - 1; - - blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; - blit.dstSubresource.baseArrayLayer = 0u; - blit.dstSubresource.layerCount = 1u; - blit.dstSubresource.mipLevel = mip_level; - - // offsets[0] is origin. - blit.srcOffsets[1].x = std::max(width, 1u); - blit.srcOffsets[1].y = std::max(height, 1u); - blit.srcOffsets[1].z = 1u; - - width = width / 2; - height = height / 2; - - // offsets[0] is origin. - blit.dstOffsets[1].x = std::max(width, 1u); - blit.dstOffsets[1].y = std::max(height, 1u); - blit.dstOffsets[1].z = 1u; - - cmd.blitImage(image, // src image - vk::ImageLayout::eTransferSrcOptimal, // src layout - image, // dst image - vk::ImageLayout::eTransferDstOptimal, // dst layout - 1u, // region count - &blit, // regions - vk::Filter::eLinear // filter - ); - - barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - - // Now that the blit is done, the image at the previous level (N-1) - // is done reading from (TransferSrc)/ Now we must prepare it to be read - // from a shader (ShaderReadOnly). - cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, - {barrier}); - } - - barrier.subresourceRange.baseMipLevel = mip_count - 1; - barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; - barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - - cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, - {barrier}); - - // We modified the layouts of this image from underneath it. Tell it its new - // state so it doesn't try to perform redundant transitions under the hood. - src.SetLayoutWithoutEncoding(vk::ImageLayout::eShaderReadOnlyOptimal); - src.SetMipMapGenerated(); - - return true; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.h deleted file mode 100644 index 7fa7589e55b..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_BLIT_COMMAND_VK_H_ -#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_BLIT_COMMAND_VK_H_ - -#include -#include "impeller/base/backend_cast.h" -#include "impeller/renderer/backend/vulkan/context_vk.h" -#include "impeller/renderer/blit_command.h" -#include "impeller/renderer/context.h" - -namespace impeller { - -class CommandEncoderVK; - -// TODO(csg): Should these be backend castable to blit command? -/// Mixin for dispatching Vulkan commands. -struct BlitEncodeVK : BackendCast { - virtual ~BlitEncodeVK(); - - virtual std::string GetLabel() const = 0; - - [[nodiscard]] virtual bool Encode(CommandEncoderVK& encoder) const = 0; -}; - -struct BlitCopyTextureToTextureCommandVK - : public BlitCopyTextureToTextureCommand, - public BlitEncodeVK { - ~BlitCopyTextureToTextureCommandVK() override; - - std::string GetLabel() const override; - - [[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override; -}; - -struct BlitCopyTextureToBufferCommandVK : public BlitCopyTextureToBufferCommand, - public BlitEncodeVK { - ~BlitCopyTextureToBufferCommandVK() override; - - std::string GetLabel() const override; - - [[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override; -}; - -struct BlitCopyBufferToTextureCommandVK : public BlitCopyBufferToTextureCommand, - public BlitEncodeVK { - ~BlitCopyBufferToTextureCommandVK() override; - - std::string GetLabel() const override; - - [[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override; -}; - -struct BlitGenerateMipmapCommandVK : public BlitGenerateMipmapCommand, - public BlitEncodeVK { - ~BlitGenerateMipmapCommandVK() override; - - std::string GetLabel() const override; - - [[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override; -}; - -} // namespace impeller - -#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_BLIT_COMMAND_VK_H_ diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc deleted file mode 100644 index db4fbdf38bf..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/testing/testing.h" // IWYU pragma: keep -#include "impeller/renderer/backend/vulkan/blit_command_vk.h" -#include "impeller/renderer/backend/vulkan/command_encoder_vk.h" -#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" - -namespace impeller { -namespace testing { - -TEST(BlitCommandVkTest, BlitCopyTextureToTextureCommandVK) { - auto context = MockVulkanContextBuilder().Build(); - auto pool = context->GetCommandPoolRecycler()->Get(); - auto encoder = std::make_unique(context)->Create(); - BlitCopyTextureToTextureCommandVK cmd; - cmd.source = context->GetResourceAllocator()->CreateTexture({ - .format = PixelFormat::kR8G8B8A8UNormInt, - .size = ISize(100, 100), - }); - cmd.destination = context->GetResourceAllocator()->CreateTexture({ - .format = PixelFormat::kR8G8B8A8UNormInt, - .size = ISize(100, 100), - }); - bool result = cmd.Encode(*encoder.get()); - EXPECT_TRUE(result); - EXPECT_TRUE(encoder->IsTracking(cmd.source)); - EXPECT_TRUE(encoder->IsTracking(cmd.destination)); -} - -TEST(BlitCommandVkTest, BlitCopyTextureToBufferCommandVK) { - auto context = MockVulkanContextBuilder().Build(); - auto encoder = std::make_unique(context)->Create(); - BlitCopyTextureToBufferCommandVK cmd; - cmd.source = context->GetResourceAllocator()->CreateTexture({ - .format = PixelFormat::kR8G8B8A8UNormInt, - .size = ISize(100, 100), - }); - cmd.destination = context->GetResourceAllocator()->CreateBuffer({ - .size = 1, - }); - bool result = cmd.Encode(*encoder.get()); - EXPECT_TRUE(result); - EXPECT_TRUE(encoder->IsTracking(cmd.source)); - EXPECT_TRUE(encoder->IsTracking(cmd.destination)); -} - -TEST(BlitCommandVkTest, BlitCopyBufferToTextureCommandVK) { - auto context = MockVulkanContextBuilder().Build(); - auto encoder = std::make_unique(context)->Create(); - BlitCopyBufferToTextureCommandVK cmd; - cmd.destination = context->GetResourceAllocator()->CreateTexture({ - .format = PixelFormat::kR8G8B8A8UNormInt, - .size = ISize(100, 100), - }); - cmd.source = - DeviceBuffer::AsBufferView(context->GetResourceAllocator()->CreateBuffer({ - .size = 1, - })); - bool result = cmd.Encode(*encoder.get()); - EXPECT_TRUE(result); - EXPECT_TRUE(encoder->IsTracking(cmd.source.buffer)); - EXPECT_TRUE(encoder->IsTracking(cmd.destination)); -} - -TEST(BlitCommandVkTest, BlitGenerateMipmapCommandVK) { - auto context = MockVulkanContextBuilder().Build(); - auto encoder = std::make_unique(context)->Create(); - BlitGenerateMipmapCommandVK cmd; - cmd.texture = context->GetResourceAllocator()->CreateTexture({ - .format = PixelFormat::kR8G8B8A8UNormInt, - .size = ISize(100, 100), - .mip_count = 2, - }); - bool result = cmd.Encode(*encoder.get()); - EXPECT_TRUE(result); - EXPECT_TRUE(encoder->IsTracking(cmd.texture)); -} - -} // namespace testing -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc index 814ebd1efe3..289561a86eb 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc @@ -4,13 +4,48 @@ #include "impeller/renderer/backend/vulkan/blit_pass_vk.h" -#include "flutter/fml/logging.h" -#include "flutter/fml/trace_event.h" +#include "impeller/renderer/backend/vulkan/barrier_vk.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/command_encoder_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "vulkan/vulkan_core.h" +#include "vulkan/vulkan_enums.hpp" +#include "vulkan/vulkan_structs.hpp" namespace impeller { -BlitPassVK::BlitPassVK(std::weak_ptr command_buffer) +static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, + const vk::Image& image, + vk::AccessFlags src_access_mask, + vk::AccessFlags dst_access_mask, + vk::ImageLayout old_layout, + vk::ImageLayout new_layout, + vk::PipelineStageFlags src_stage, + vk::PipelineStageFlags dst_stage, + uint32_t base_mip_level, + uint32_t mip_level_count = 1u) { + if (old_layout == new_layout) { + return; + } + + vk::ImageMemoryBarrier barrier; + barrier.srcAccessMask = src_access_mask; + barrier.dstAccessMask = dst_access_mask; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + barrier.subresourceRange.baseMipLevel = base_mip_level; + barrier.subresourceRange.levelCount = mip_level_count; + barrier.subresourceRange.baseArrayLayer = 0u; + barrier.subresourceRange.layerCount = 1u; + + cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier); +} + +BlitPassVK::BlitPassVK(std::shared_ptr command_buffer) : command_buffer_(std::move(command_buffer)) {} BlitPassVK::~BlitPassVK() = default; @@ -30,27 +65,6 @@ bool BlitPassVK::IsValid() const { // |BlitPass| bool BlitPassVK::EncodeCommands( const std::shared_ptr& transients_allocator) const { - TRACE_EVENT0("impeller", "BlitPassVK::EncodeCommands"); - - if (!IsValid()) { - return false; - } - - auto command_buffer = command_buffer_.lock(); - if (!command_buffer) { - return false; - } - auto encoder = command_buffer->GetEncoder(); - if (!encoder) { - return false; - } - - for (auto& command : commands_) { - if (!command->Encode(*encoder)) { - return false; - } - } - return true; } @@ -61,16 +75,81 @@ bool BlitPassVK::OnCopyTextureToTextureCommand( IRect source_region, IPoint destination_origin, std::string label) { - auto command = std::make_unique(); + auto& encoder = *command_buffer_->GetEncoder(); + const auto& cmd_buffer = encoder.GetCommandBuffer(); - command->source = std::move(source); - command->destination = std::move(destination); - command->source_region = source_region; - command->destination_origin = destination_origin; - command->label = std::move(label); + const auto& src = TextureVK::Cast(*source); + const auto& dst = TextureVK::Cast(*destination); - commands_.push_back(std::move(command)); - return true; + if (!encoder.Track(source) || !encoder.Track(destination)) { + return false; + } + + BarrierVK src_barrier; + src_barrier.cmd_buffer = cmd_buffer; + src_barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal; + src_barrier.src_access = vk::AccessFlagBits::eTransferWrite | + vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eColorAttachmentWrite; + src_barrier.src_stage = vk::PipelineStageFlagBits::eTransfer | + vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eColorAttachmentOutput; + src_barrier.dst_access = vk::AccessFlagBits::eTransferRead; + src_barrier.dst_stage = vk::PipelineStageFlagBits::eTransfer; + + BarrierVK dst_barrier; + dst_barrier.cmd_buffer = cmd_buffer; + dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal; + dst_barrier.src_access = {}; + dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + dst_barrier.dst_access = + vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite; + dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer; + + if (!src.SetLayout(src_barrier) || !dst.SetLayout(dst_barrier)) { + VALIDATION_LOG << "Could not complete layout transitions."; + return false; + } + + vk::ImageCopy image_copy; + + image_copy.setSrcSubresource( + vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); + image_copy.setDstSubresource( + vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); + + image_copy.srcOffset = + vk::Offset3D(source_region.GetX(), source_region.GetY(), 0); + image_copy.dstOffset = + vk::Offset3D(destination_origin.x, destination_origin.y, 0); + image_copy.extent = + vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1); + + // Issue the copy command now that the images are already in the right + // layouts. + cmd_buffer.copyImage(src.GetImage(), // + src_barrier.new_layout, // + dst.GetImage(), // + dst_barrier.new_layout, // + image_copy // + ); + + // If this is an onscreen texture, do not transition the layout + // back to shader read. + if (dst.IsSwapchainImage()) { + return true; + } + + BarrierVK barrier; + barrier.cmd_buffer = cmd_buffer; + barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + barrier.src_access = {}; + barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + barrier.dst_access = vk::AccessFlagBits::eShaderRead; + barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + return dst.SetLayout(barrier); } // |BlitPass| @@ -80,15 +159,65 @@ bool BlitPassVK::OnCopyTextureToBufferCommand( IRect source_region, size_t destination_offset, std::string label) { - auto command = std::make_unique(); + auto& encoder = *command_buffer_->GetEncoder(); + const auto& cmd_buffer = encoder.GetCommandBuffer(); - command->source = std::move(source); - command->destination = std::move(destination); - command->source_region = source_region; - command->destination_offset = destination_offset; - command->label = std::move(label); + // cast source and destination to TextureVK + const auto& src = TextureVK::Cast(*source); + + if (!encoder.Track(source) || !encoder.Track(destination)) { + return false; + } + + BarrierVK barrier; + barrier.cmd_buffer = cmd_buffer; + barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal; + barrier.src_access = vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eTransferWrite | + vk::AccessFlagBits::eColorAttachmentWrite; + barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer | + vk::PipelineStageFlagBits::eColorAttachmentOutput; + barrier.dst_access = vk::AccessFlagBits::eShaderRead; + barrier.dst_stage = vk::PipelineStageFlagBits::eVertexShader | + vk::PipelineStageFlagBits::eFragmentShader; + + const auto& dst = DeviceBufferVK::Cast(*destination); + + vk::BufferImageCopy image_copy; + image_copy.setBufferOffset(destination_offset); + image_copy.setBufferRowLength(0); + image_copy.setBufferImageHeight(0); + image_copy.setImageSubresource( + vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); + image_copy.setImageOffset( + vk::Offset3D(source_region.GetX(), source_region.GetY(), 0)); + image_copy.setImageExtent( + vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1)); + + if (!src.SetLayout(barrier)) { + VALIDATION_LOG << "Could not encode layout transition."; + return false; + } + + cmd_buffer.copyImageToBuffer(src.GetImage(), // + barrier.new_layout, // + dst.GetBuffer(), // + image_copy // + ); + + // If the buffer is used for readback, then apply a transfer -> host memory + // barrier. + if (destination->GetDeviceBufferDescriptor().readback) { + vk::MemoryBarrier barrier; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits::eHostRead; + + cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eHost, {}, 1, + &barrier, 0, {}, 0, {}); + } - commands_.push_back(std::move(command)); return true; } @@ -99,27 +228,196 @@ bool BlitPassVK::OnCopyBufferToTextureCommand( IRect destination_region, std::string label, uint32_t slice) { - auto command = std::make_unique(); + auto& encoder = *command_buffer_->GetEncoder(); + const auto& cmd_buffer = encoder.GetCommandBuffer(); - command->source = std::move(source); - command->destination = std::move(destination); - command->destination_region = destination_region; - command->label = std::move(label); - command->slice = slice; + // cast destination to TextureVK + const auto& dst = TextureVK::Cast(*destination); + const auto& src = DeviceBufferVK::Cast(*source.buffer); + + if (!encoder.Track(source.buffer) || !encoder.Track(destination)) { + return false; + } + + BarrierVK dst_barrier; + dst_barrier.cmd_buffer = cmd_buffer; + dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal; + dst_barrier.src_access = {}; + dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + dst_barrier.dst_access = + vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite; + dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer; + + vk::BufferImageCopy image_copy; + image_copy.setBufferOffset(source.range.offset); + image_copy.setBufferRowLength(0); + image_copy.setBufferImageHeight(0); + image_copy.setImageSubresource( + vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)); + image_copy.imageOffset.x = destination_region.GetX(); + image_copy.imageOffset.y = destination_region.GetY(); + image_copy.imageOffset.z = 0u; + image_copy.imageExtent.width = destination_region.GetWidth(); + image_copy.imageExtent.height = destination_region.GetHeight(); + image_copy.imageExtent.depth = 1u; + + if (!dst.SetLayout(dst_barrier)) { + VALIDATION_LOG << "Could not encode layout transition."; + return false; + } + + cmd_buffer.copyBufferToImage(src.GetBuffer(), // + dst.GetImage(), // + dst_barrier.new_layout, // + image_copy // + ); + + // Transition to shader-read. + { + BarrierVK barrier; + barrier.cmd_buffer = cmd_buffer; + barrier.src_access = vk::AccessFlagBits::eTransferWrite; + barrier.src_stage = vk::PipelineStageFlagBits::eTransfer; + barrier.dst_access = vk::AccessFlagBits::eShaderRead; + barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + + if (!dst.SetLayout(barrier)) { + return false; + } + } - commands_.push_back(std::move(command)); return true; } // |BlitPass| bool BlitPassVK::OnGenerateMipmapCommand(std::shared_ptr texture, std::string label) { - auto command = std::make_unique(); + auto& encoder = *command_buffer_->GetEncoder(); + auto& src = TextureVK::Cast(*texture); - command->texture = std::move(texture); - command->label = std::move(label); + const auto size = src.GetTextureDescriptor().size; + uint32_t mip_count = src.GetTextureDescriptor().mip_count; + + if (mip_count < 2u) { + return true; + } + + const auto& image = src.GetImage(); + const auto& cmd = encoder.GetCommandBuffer(); + + if (!encoder.Track(texture)) { + return false; + } + + // Initialize all mip levels to be in TransferDst mode. Later, in a loop, + // after writing to that mip level, we'll first switch its layout to + // TransferSrc to prepare the mip level after it, use the image as the source + // of the blit, before finally switching it to ShaderReadOnly so its available + // for sampling in a shader. + InsertImageMemoryBarrier( + cmd, // command buffer + image, // image + vk::AccessFlagBits::eTransferWrite, // src access mask + vk::AccessFlagBits::eTransferRead, // dst access mask + src.GetLayout(), // old layout + vk::ImageLayout::eTransferDstOptimal, // new layout + vk::PipelineStageFlagBits::eTransfer, // src stage + vk::PipelineStageFlagBits::eTransfer, // dst stage + 0u, // mip level + mip_count // mip level count + ); + + vk::ImageMemoryBarrier barrier; + barrier.image = image; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + + // Blit from the mip level N - 1 to mip level N. + size_t width = size.width; + size_t height = size.height; + for (size_t mip_level = 1u; mip_level < mip_count; mip_level++) { + barrier.subresourceRange.baseMipLevel = mip_level - 1; + barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; + barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; + + // We just finished writing to the previous (N-1) mip level or it was the + // base mip level. These were initialized to TransferDst earler. We are now + // going to read from it to write to the current level (N) . So it must be + // converted to TransferSrc. + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, + {barrier}); + + vk::ImageBlit blit; + blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; + blit.srcSubresource.baseArrayLayer = 0u; + blit.srcSubresource.layerCount = 1u; + blit.srcSubresource.mipLevel = mip_level - 1; + + blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; + blit.dstSubresource.baseArrayLayer = 0u; + blit.dstSubresource.layerCount = 1u; + blit.dstSubresource.mipLevel = mip_level; + + // offsets[0] is origin. + blit.srcOffsets[1].x = std::max(width, 1u); + blit.srcOffsets[1].y = std::max(height, 1u); + blit.srcOffsets[1].z = 1u; + + width = width / 2; + height = height / 2; + + // offsets[0] is origin. + blit.dstOffsets[1].x = std::max(width, 1u); + blit.dstOffsets[1].y = std::max(height, 1u); + blit.dstOffsets[1].z = 1u; + + cmd.blitImage(image, // src image + vk::ImageLayout::eTransferSrcOptimal, // src layout + image, // dst image + vk::ImageLayout::eTransferDstOptimal, // dst layout + 1u, // region count + &blit, // regions + vk::Filter::eLinear // filter + ); + + barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; + barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; + barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + + // Now that the blit is done, the image at the previous level (N-1) + // is done reading from (TransferSrc)/ Now we must prepare it to be read + // from a shader (ShaderReadOnly). + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, + {barrier}); + } + + barrier.subresourceRange.baseMipLevel = mip_count - 1; + barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; + barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, + {barrier}); + + // We modified the layouts of this image from underneath it. Tell it its new + // state so it doesn't try to perform redundant transitions under the hood. + src.SetLayoutWithoutEncoding(vk::ImageLayout::eShaderReadOnlyOptimal); + src.SetMipMapGenerated(); - commands_.push_back(std::move(command)); return true; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h index 1d336c27a42..b3967ed8c8b 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h @@ -7,7 +7,6 @@ #include "flutter/impeller/base/config.h" #include "impeller/geometry/rect.h" -#include "impeller/renderer/backend/vulkan/blit_command_vk.h" #include "impeller/renderer/blit_pass.h" namespace impeller { @@ -23,11 +22,10 @@ class BlitPassVK final : public BlitPass { private: friend class CommandBufferVK; - std::weak_ptr command_buffer_; - std::vector> commands_; + std::shared_ptr command_buffer_; std::string label_; - explicit BlitPassVK(std::weak_ptr command_buffer); + explicit BlitPassVK(std::shared_ptr command_buffer); // |BlitPass| bool IsValid() const override; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 62e271f7b19..1418121f70d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -76,7 +76,7 @@ std::shared_ptr CommandBufferVK::OnCreateBlitPass() { if (!IsValid()) { return nullptr; } - auto pass = std::shared_ptr(new BlitPassVK(weak_from_this())); + auto pass = std::shared_ptr(new BlitPassVK(shared_from_this())); if (!pass->IsValid()) { return nullptr; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/test/gpu_tracer_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/test/gpu_tracer_unittests.cc index 8f8e195d1a6..c9e07943be7 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/test/gpu_tracer_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/test/gpu_tracer_unittests.cc @@ -130,7 +130,6 @@ TEST(GPUTracerVK, TracesWithPartialFrameOverlap) { auto cmd_buffer = context->CreateCommandBuffer(); auto blit_pass = cmd_buffer->CreateBlitPass(); blit_pass->EncodeCommands(context->GetResourceAllocator()); - tracer->MarkFrameEnd(); auto latch = std::make_shared(1u); if (!context->GetCommandQueue() @@ -140,6 +139,7 @@ TEST(GPUTracerVK, TracesWithPartialFrameOverlap) { .ok()) { GTEST_FAIL() << "Failed to submit cmd buffer"; } + tracer->MarkFrameEnd(); latch->Wait();