diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 80cd41201f4d1..ce81afab97f0c 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -383,7 +383,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..f4ddb10476b2d 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -144,6 +144,62 @@ 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 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 | vk::AccessFlagBits::eTransferWrite; + dst_tran.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.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(dst_tran)) { + VALIDATION_LOG << "Could not encode layout transition."; + return false; + } + + cmd_buffer.copyBufferToImage(src.GetBuffer(), // + dst.GetImage(), // + dst_tran.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 d3dc53848e350..92f951452b73e 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc @@ -48,6 +48,27 @@ TEST(BlitCommandVkTest, BlitCopyTextureToBufferCommandVK) { EXPECT_TRUE(encoder.IsTracking(cmd.destination)); } +TEST(BlitCommandVkTest, BlitCopyBufferToTextureCommandVK) { + auto context = CreateMockVulkanContext(); + auto pool = CommandPoolVK::GetThreadLocal(context.get()); + CommandEncoderVK encoder(context->GetDeviceHolder(), + 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 e917bed3ae3b8..e93e98e301882 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -328,7 +328,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 540e1832158c5..58511136435ae 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc @@ -52,14 +52,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; } @@ -89,7 +89,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; @@ -202,7 +202,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; } @@ -211,7 +211,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 756c417a4520b..32e176023d049 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.h +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h @@ -21,11 +21,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; @@ -43,9 +45,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); @@ -72,6 +74,8 @@ class CommandEncoderVK { BlitCommandVkTest_BlitCopyTextureToBufferCommandVK_Test; friend class ::impeller::testing:: BlitCommandVkTest_BlitGenerateMipmapCommandVK_Test; + friend class ::impeller::testing:: + BlitCommandVkTest_BlitCopyBufferToTextureCommandVK_Test; std::weak_ptr device_holder_; 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, diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 1da53feb0c846..ecb455c1bdaa0 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -481,21 +481,19 @@ void ImageDecoderImpeller::Decode(fml::RefPtr descriptor, } auto upload_texture_and_invoke_result = [result, context, bitmap_result, gpu_disabled_switch]() { - // TODO(jonahwilliams): remove ifdef once blit from buffer - // to texture is implemented on other platforms. sk_sp image; std::string decode_error; - -#ifdef FML_OS_IOS - std::tie(image, decode_error) = UploadTextureToPrivate( - context, bitmap_result.device_buffer, bitmap_result.image_info, - bitmap_result.sk_bitmap, gpu_disabled_switch); -#else - std::tie(image, decode_error) = - UploadTextureToShared(context, bitmap_result.sk_bitmap, - gpu_disabled_switch, /*create_mips=*/true); -#endif // FML_OS_IOS - result(image, decode_error); + if (context->GetCapabilities()->SupportsBufferToTextureBlits()) { + std::tie(image, decode_error) = UploadTextureToPrivate( + context, bitmap_result.device_buffer, bitmap_result.image_info, + bitmap_result.sk_bitmap, gpu_disabled_switch); + result(image, decode_error); + } else { + std::tie(image, decode_error) = UploadTextureToShared( + context, bitmap_result.sk_bitmap, gpu_disabled_switch, + /*create_mips=*/true); + result(image, decode_error); + } }; // TODO(jonahwilliams): // https://github.com/flutter/flutter/issues/123058 Technically we