From a8cf9efd376251f061c6ccf7d77be0646a452b42 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 3 May 2023 12:11:10 -0700 Subject: [PATCH 1/5] [Impeller] add buffer to texture blit for Vulkan --- impeller/playground/playground.cc | 2 +- .../backend/vulkan/blit_command_vk.cc | 59 +++++++++++++++++++ .../renderer/backend/vulkan/blit_command_vk.h | 9 +++ .../vulkan/blit_command_vk_unittests.cc | 20 +++++++ .../renderer/backend/vulkan/blit_pass_vk.cc | 17 ++++++ .../renderer/backend/vulkan/blit_pass_vk.h | 6 +- .../backend/vulkan/capabilities_vk.cc | 2 +- .../backend/vulkan/command_encoder_vk.cc | 10 ++-- .../backend/vulkan/command_encoder_vk.h | 8 ++- .../backend/vulkan/device_buffer_vk.h | 2 +- 10 files changed, 120 insertions(+), 15 deletions(-) diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 4f61c5c5020ef..f1066d010cf5a 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -400,7 +400,7 @@ static std::shared_ptr CreateTextureForDecompressedImage( DecompressedImage& decompressed_image, bool enable_mipmapping) { // TODO(https://github.com/flutter/flutter/issues/123468): copying buffers to - // textures is not implemented for GLES/Vulkan. + // textures is not implemented for GLES. if (context->GetCapabilities()->SupportsBufferToTextureBlits()) { impeller::TextureDescriptor texture_descriptor; texture_descriptor.storage_mode = impeller::StorageMode::kDevicePrivate; diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index edf2cd73dc555..fdb1e4c369573 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -144,6 +144,65 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const { 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; + } + + LayoutTransition transition; + transition.cmd_buffer = cmd_buffer; + transition.new_layout = vk::ImageLayout::eTransferSrcOptimal; + transition.src_access = vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eTransferWrite | + vk::AccessFlagBits::eColorAttachmentWrite; + transition.src_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer | + vk::PipelineStageFlagBits::eColorAttachmentOutput; + transition.dst_access = vk::AccessFlagBits::eShaderRead; + transition.dst_stage = vk::PipelineStageFlagBits::eVertexShader | + vk::PipelineStageFlagBits::eFragmentShader; + + 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.setImageOffset( + vk::Offset3D(destination_origin.x, destination_origin.y, 0)); + image_copy.setImageExtent(vk::Extent3D(destination->GetSize().width, + destination->GetSize().height, 1)); + + if (!dst.SetLayout(transition)) { + VALIDATION_LOG << "Could not encode layout transition."; + return false; + } + + cmd_buffer.copyBufferToImage(src.GetBuffer(), // + dst.GetImage(), // + transition.new_layout, // + image_copy // + ); + + return true; +} + //------------------------------------------------------------------------------ /// BlitGenerateMipmapCommandVK /// diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.h b/impeller/renderer/backend/vulkan/blit_command_vk.h index 4e84d931b7329..dbbf5881556a3 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.h +++ b/impeller/renderer/backend/vulkan/blit_command_vk.h @@ -43,6 +43,15 @@ struct BlitCopyTextureToBufferCommandVK : public BlitCopyTextureToBufferCommand, [[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; diff --git a/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc b/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc index a6f871d64c694..a96084df74e8c 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc @@ -46,6 +46,26 @@ TEST(BlitCommandVkTest, BlitCopyTextureToBufferCommandVK) { EXPECT_TRUE(encoder.IsTracking(cmd.destination)); } +TEST(BlitCommandVkTest, BlitCopyBufferToTextureCommandVK) { + auto context = CreateMockVulkanContext(); + auto pool = CommandPoolVK::GetThreadLocal(context.get()); + CommandEncoderVK encoder(context->GetDevice(), context->GetGraphicsQueue(), + pool, context->GetFenceWaiter()); + BlitCopyBufferToTextureCommandVK cmd; + cmd.destination = context->GetResourceAllocator()->CreateTexture({ + .size = ISize(100, 100), + }); + cmd.source = context->GetResourceAllocator() + ->CreateBuffer({ + .size = 1, + }) + ->AsBufferView(); + bool result = cmd.Encode(encoder); + EXPECT_TRUE(result); + EXPECT_TRUE(encoder.IsTracking(cmd.source.buffer)); + EXPECT_TRUE(encoder.IsTracking(cmd.destination)); +} + TEST(BlitCommandVkTest, BlitGenerateMipmapCommandVK) { auto context = CreateMockVulkanContext(); auto pool = CommandPoolVK::GetThreadLocal(context.get()); diff --git a/impeller/renderer/backend/vulkan/blit_pass_vk.cc b/impeller/renderer/backend/vulkan/blit_pass_vk.cc index f563681af3455..1eb58296d6487 100644 --- a/impeller/renderer/backend/vulkan/blit_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_pass_vk.cc @@ -87,6 +87,23 @@ bool BlitPassVK::OnCopyTextureToBufferCommand( return true; } +// |BlitPass| +bool BlitPassVK::OnCopyBufferToTextureCommand( + BufferView source, + std::shared_ptr destination, + IPoint destination_origin, + std::string label) { + auto command = std::make_unique(); + + command->source = std::move(source); + command->destination = std::move(destination); + command->destination_origin = destination_origin; + command->label = std::move(label); + + commands_.push_back(std::move(command)); + return true; +} + // |BlitPass| bool BlitPassVK::OnGenerateMipmapCommand(std::shared_ptr texture, std::string label) { diff --git a/impeller/renderer/backend/vulkan/blit_pass_vk.h b/impeller/renderer/backend/vulkan/blit_pass_vk.h index 6aa5f8a5fc4de..1367ceae43ceb 100644 --- a/impeller/renderer/backend/vulkan/blit_pass_vk.h +++ b/impeller/renderer/backend/vulkan/blit_pass_vk.h @@ -55,11 +55,7 @@ class BlitPassVK final : public BlitPass { bool OnCopyBufferToTextureCommand(BufferView source, std::shared_ptr destination, IPoint destination_origin, - std::string label) override { - IMPELLER_UNIMPLEMENTED; - return false; - } - + std::string label) override; // |BlitPass| bool OnGenerateMipmapCommand(std::shared_ptr texture, std::string label) override; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index ff4410f15935a..98f0abf4065a7 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -315,7 +315,7 @@ bool CapabilitiesVK::SupportsSSBO() const { // |Capabilities| bool CapabilitiesVK::SupportsBufferToTextureBlits() const { - return false; + return true; } // |Capabilities| diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.cc b/impeller/renderer/backend/vulkan/command_encoder_vk.cc index fd6cbec90be2a..2e2de23d7af93 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc @@ -51,14 +51,14 @@ class TrackedObjectsVK { tracked_objects_.insert(std::move(object)); } - void Track(std::shared_ptr buffer) { + void Track(std::shared_ptr buffer) { if (!buffer) { return; } tracked_buffers_.insert(std::move(buffer)); } - bool IsTracking(const std::shared_ptr& buffer) const { + bool IsTracking(const std::shared_ptr& buffer) const { if (!buffer) { return false; } @@ -88,7 +88,7 @@ class TrackedObjectsVK { std::weak_ptr pool_; vk::UniqueCommandBuffer buffer_; std::set> tracked_objects_; - std::set> tracked_buffers_; + std::set> tracked_buffers_; std::set> tracked_textures_; bool is_valid_ = false; @@ -178,7 +178,7 @@ bool CommandEncoderVK::Track(std::shared_ptr object) { return true; } -bool CommandEncoderVK::Track(std::shared_ptr buffer) { +bool CommandEncoderVK::Track(std::shared_ptr buffer) { if (!IsValid()) { return false; } @@ -187,7 +187,7 @@ bool CommandEncoderVK::Track(std::shared_ptr buffer) { } bool CommandEncoderVK::IsTracking( - const std::shared_ptr& buffer) const { + const std::shared_ptr& buffer) const { if (!IsValid()) { return false; } diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.h b/impeller/renderer/backend/vulkan/command_encoder_vk.h index 9a4581cdf9c9b..4df8aa2637754 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.h +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h @@ -19,11 +19,13 @@ namespace impeller { namespace testing { class BlitCommandVkTest_BlitCopyTextureToTextureCommandVK_Test; class BlitCommandVkTest_BlitCopyTextureToBufferCommandVK_Test; +class BlitCommandVkTest_BlitCopyBufferToTextureCommandVK_Test; class BlitCommandVkTest_BlitGenerateMipmapCommandVK_Test; } // namespace testing class ContextVK; class DeviceBuffer; +class Buffer; class Texture; class TextureSourceVK; class TrackedObjectsVK; @@ -39,9 +41,9 @@ class CommandEncoderVK { bool Track(std::shared_ptr object); - bool Track(std::shared_ptr buffer); + bool Track(std::shared_ptr buffer); - bool IsTracking(const std::shared_ptr& texture) const; + bool IsTracking(const std::shared_ptr& texture) const; bool Track(const std::shared_ptr& texture); @@ -68,6 +70,8 @@ class CommandEncoderVK { BlitCommandVkTest_BlitCopyTextureToBufferCommandVK_Test; friend class ::impeller::testing:: BlitCommandVkTest_BlitGenerateMipmapCommandVK_Test; + friend class ::impeller::testing:: + BlitCommandVkTest_BlitCopyBufferToTextureCommandVK_Test; vk::Device device_ = {}; std::shared_ptr queue_; diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 5f92ca291114d..229a1b6b04325 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h @@ -14,7 +14,7 @@ namespace impeller { class DeviceBufferVK final : public DeviceBuffer, - public BackendCast { + public BackendCast { public: DeviceBufferVK(DeviceBufferDescriptor desc, std::weak_ptr context, From 541302d128ea42b0d9b62e8d365868aa2e7043d4 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 3 May 2023 13:10:40 -0700 Subject: [PATCH 2/5] ++ --- .../backend/vulkan/blit_command_vk.cc | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index fdb1e4c369573..fbe2340da5b12 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -165,18 +165,13 @@ bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const { return false; } - LayoutTransition transition; - transition.cmd_buffer = cmd_buffer; - transition.new_layout = vk::ImageLayout::eTransferSrcOptimal; - transition.src_access = vk::AccessFlagBits::eShaderWrite | - vk::AccessFlagBits::eTransferWrite | - vk::AccessFlagBits::eColorAttachmentWrite; - transition.src_stage = vk::PipelineStageFlagBits::eFragmentShader | - vk::PipelineStageFlagBits::eTransfer | - vk::PipelineStageFlagBits::eColorAttachmentOutput; - transition.dst_access = vk::AccessFlagBits::eShaderRead; - transition.dst_stage = vk::PipelineStageFlagBits::eVertexShader | - vk::PipelineStageFlagBits::eFragmentShader; + LayoutTransition dst_tran; + dst_tran.cmd_buffer = cmd_buffer; + dst_tran.new_layout = vk::ImageLayout::eTransferDstOptimal; + dst_tran.src_access = {}; + dst_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + dst_tran.dst_access = vk::AccessFlagBits::eShaderRead; + dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; vk::BufferImageCopy image_copy; image_copy.setBufferOffset(source.range.offset); @@ -189,15 +184,15 @@ bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const { image_copy.setImageExtent(vk::Extent3D(destination->GetSize().width, destination->GetSize().height, 1)); - if (!dst.SetLayout(transition)) { + if (!dst.SetLayout(dst_tran)) { VALIDATION_LOG << "Could not encode layout transition."; return false; } - cmd_buffer.copyBufferToImage(src.GetBuffer(), // - dst.GetImage(), // - transition.new_layout, // - image_copy // + cmd_buffer.copyBufferToImage(src.GetBuffer(), // + dst.GetImage(), // + dst_tran.new_layout, // + image_copy // ); return true; From cc6526e992b4cf3c2bce2d817fbf5a730225edc7 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 3 May 2023 13:40:29 -0700 Subject: [PATCH 3/5] fix validation error? --- impeller/renderer/backend/vulkan/blit_command_vk.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index fbe2340da5b12..f4ddb10476b2d 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -170,8 +170,10 @@ bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const { dst_tran.new_layout = vk::ImageLayout::eTransferDstOptimal; dst_tran.src_access = {}; dst_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; - dst_tran.dst_access = vk::AccessFlagBits::eShaderRead; - dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + dst_tran.dst_access = + vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite; + dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer; vk::BufferImageCopy image_copy; image_copy.setBufferOffset(source.range.offset); From 36efb05c2a88d27826313674735d6f992f24823b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 3 May 2023 13:58:04 -0700 Subject: [PATCH 4/5] image decoding --- lib/ui/painting/image_decoder_impeller.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 037e0c78a277b..339d4300ddc27 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -415,14 +415,14 @@ void ImageDecoderImpeller::Decode(fml::RefPtr descriptor, auto upload_texture_and_invoke_result = [result, context, bitmap_result = bitmap_result.value()]() { -// TODO(jonahwilliams): remove ifdef once blit from buffer to texture is -// implemented on other platforms. -#ifdef FML_OS_IOS - result(UploadTextureToPrivate(context, bitmap_result.device_buffer, - bitmap_result.image_info)); -#else - result(UploadTextureToShared(context, bitmap_result.sk_bitmap)); -#endif + // TODO(jonahwilliams): remove ifdef once blit from buffer to texture + // is implemented on other platforms. + if (context->GetCapabilities()->SupportsBufferToTextureBlits()) { + result(UploadTextureToPrivate(context, bitmap_result.device_buffer, + bitmap_result.image_info)); + } else { + result(UploadTextureToShared(context, bitmap_result.sk_bitmap)); + } }; // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/123058 // Technically we don't need to post tasks to the io runner, but without From 8aeb103a5176614a8dd9348c4cbc5c99d1ab122f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 12 May 2023 09:07:15 -0700 Subject: [PATCH 5/5] fix test --- impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc b/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc index 17b16b8e3e57a..6b08b7b5177e1 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc @@ -49,8 +49,8 @@ TEST(BlitCommandVkTest, BlitCopyTextureToBufferCommandVK) { TEST(BlitCommandVkTest, BlitCopyBufferToTextureCommandVK) { auto context = CreateMockVulkanContext(); auto pool = CommandPoolVK::GetThreadLocal(context.get()); - CommandEncoderVK encoder(context->GetDevice(), context->GetGraphicsQueue(), - pool, context->GetFenceWaiter()); + CommandEncoderVK encoder(context, context->GetGraphicsQueue(), pool, + context->GetFenceWaiter()); BlitCopyBufferToTextureCommandVK cmd; cmd.destination = context->GetResourceAllocator()->CreateTexture({ .size = ISize(100, 100),