Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1089ce6

Browse files
[Impeller] Add buffer to texture blit for Vulkan. (#41706)
Work towards flutter/flutter#123468 In order to support the usage of BufferView, I generalized the tracked buffer type from DeviceBuffer to Buffer. Should be mostly safe! I confirmed that this runs correctly under moltenvk but I'm uncertain if there are additional ways to validate.
1 parent 71c9d51 commit 1089ce6

File tree

11 files changed

+129
-28
lines changed

11 files changed

+129
-28
lines changed

impeller/playground/playground.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ static std::shared_ptr<Texture> CreateTextureForDecompressedImage(
383383
DecompressedImage& decompressed_image,
384384
bool enable_mipmapping) {
385385
// TODO(https://github.com/flutter/flutter/issues/123468): copying buffers to
386-
// textures is not implemented for GLES/Vulkan.
386+
// textures is not implemented for GLES.
387387
if (context->GetCapabilities()->SupportsBufferToTextureBlits()) {
388388
impeller::TextureDescriptor texture_descriptor;
389389
texture_descriptor.storage_mode = impeller::StorageMode::kDevicePrivate;

impeller/renderer/backend/vulkan/blit_command_vk.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,62 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const {
144144
return true;
145145
}
146146

147+
//------------------------------------------------------------------------------
148+
/// BlitCopyBufferToTextureCommandVK
149+
///
150+
151+
BlitCopyBufferToTextureCommandVK::~BlitCopyBufferToTextureCommandVK() = default;
152+
153+
std::string BlitCopyBufferToTextureCommandVK::GetLabel() const {
154+
return label;
155+
}
156+
157+
bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const {
158+
const auto& cmd_buffer = encoder.GetCommandBuffer();
159+
160+
// cast destination to TextureVK
161+
const auto& dst = TextureVK::Cast(*destination);
162+
const auto& src = DeviceBufferVK::Cast(*source.buffer);
163+
164+
if (!encoder.Track(source.buffer) || !encoder.Track(destination)) {
165+
return false;
166+
}
167+
168+
LayoutTransition dst_tran;
169+
dst_tran.cmd_buffer = cmd_buffer;
170+
dst_tran.new_layout = vk::ImageLayout::eTransferDstOptimal;
171+
dst_tran.src_access = {};
172+
dst_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
173+
dst_tran.dst_access =
174+
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite;
175+
dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader |
176+
vk::PipelineStageFlagBits::eTransfer;
177+
178+
vk::BufferImageCopy image_copy;
179+
image_copy.setBufferOffset(source.range.offset);
180+
image_copy.setBufferRowLength(0);
181+
image_copy.setBufferImageHeight(0);
182+
image_copy.setImageSubresource(
183+
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1));
184+
image_copy.setImageOffset(
185+
vk::Offset3D(destination_origin.x, destination_origin.y, 0));
186+
image_copy.setImageExtent(vk::Extent3D(destination->GetSize().width,
187+
destination->GetSize().height, 1));
188+
189+
if (!dst.SetLayout(dst_tran)) {
190+
VALIDATION_LOG << "Could not encode layout transition.";
191+
return false;
192+
}
193+
194+
cmd_buffer.copyBufferToImage(src.GetBuffer(), //
195+
dst.GetImage(), //
196+
dst_tran.new_layout, //
197+
image_copy //
198+
);
199+
200+
return true;
201+
}
202+
147203
//------------------------------------------------------------------------------
148204
/// BlitGenerateMipmapCommandVK
149205
///

impeller/renderer/backend/vulkan/blit_command_vk.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ struct BlitCopyTextureToBufferCommandVK : public BlitCopyTextureToBufferCommand,
4343
[[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override;
4444
};
4545

46+
struct BlitCopyBufferToTextureCommandVK : public BlitCopyBufferToTextureCommand,
47+
public BlitEncodeVK {
48+
~BlitCopyBufferToTextureCommandVK() override;
49+
50+
std::string GetLabel() const override;
51+
52+
[[nodiscard]] bool Encode(CommandEncoderVK& encoder) const override;
53+
};
54+
4655
struct BlitGenerateMipmapCommandVK : public BlitGenerateMipmapCommand,
4756
public BlitEncodeVK {
4857
~BlitGenerateMipmapCommandVK() override;

impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,27 @@ TEST(BlitCommandVkTest, BlitCopyTextureToBufferCommandVK) {
4848
EXPECT_TRUE(encoder.IsTracking(cmd.destination));
4949
}
5050

51+
TEST(BlitCommandVkTest, BlitCopyBufferToTextureCommandVK) {
52+
auto context = CreateMockVulkanContext();
53+
auto pool = CommandPoolVK::GetThreadLocal(context.get());
54+
CommandEncoderVK encoder(context->GetDeviceHolder(),
55+
context->GetGraphicsQueue(), pool,
56+
context->GetFenceWaiter());
57+
BlitCopyBufferToTextureCommandVK cmd;
58+
cmd.destination = context->GetResourceAllocator()->CreateTexture({
59+
.size = ISize(100, 100),
60+
});
61+
cmd.source = context->GetResourceAllocator()
62+
->CreateBuffer({
63+
.size = 1,
64+
})
65+
->AsBufferView();
66+
bool result = cmd.Encode(encoder);
67+
EXPECT_TRUE(result);
68+
EXPECT_TRUE(encoder.IsTracking(cmd.source.buffer));
69+
EXPECT_TRUE(encoder.IsTracking(cmd.destination));
70+
}
71+
5172
TEST(BlitCommandVkTest, BlitGenerateMipmapCommandVK) {
5273
auto context = CreateMockVulkanContext();
5374
auto pool = CommandPoolVK::GetThreadLocal(context.get());

impeller/renderer/backend/vulkan/blit_pass_vk.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ bool BlitPassVK::OnCopyTextureToBufferCommand(
8787
return true;
8888
}
8989

90+
// |BlitPass|
91+
bool BlitPassVK::OnCopyBufferToTextureCommand(
92+
BufferView source,
93+
std::shared_ptr<Texture> destination,
94+
IPoint destination_origin,
95+
std::string label) {
96+
auto command = std::make_unique<BlitCopyBufferToTextureCommandVK>();
97+
98+
command->source = std::move(source);
99+
command->destination = std::move(destination);
100+
command->destination_origin = destination_origin;
101+
command->label = std::move(label);
102+
103+
commands_.push_back(std::move(command));
104+
return true;
105+
}
106+
90107
// |BlitPass|
91108
bool BlitPassVK::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
92109
std::string label) {

impeller/renderer/backend/vulkan/blit_pass_vk.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,7 @@ class BlitPassVK final : public BlitPass {
5555
bool OnCopyBufferToTextureCommand(BufferView source,
5656
std::shared_ptr<Texture> destination,
5757
IPoint destination_origin,
58-
std::string label) override {
59-
IMPELLER_UNIMPLEMENTED;
60-
return false;
61-
}
62-
58+
std::string label) override;
6359
// |BlitPass|
6460
bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
6561
std::string label) override;

impeller/renderer/backend/vulkan/capabilities_vk.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ bool CapabilitiesVK::SupportsSSBO() const {
328328

329329
// |Capabilities|
330330
bool CapabilitiesVK::SupportsBufferToTextureBlits() const {
331-
return false;
331+
return true;
332332
}
333333

334334
// |Capabilities|

impeller/renderer/backend/vulkan/command_encoder_vk.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ class TrackedObjectsVK {
5252
tracked_objects_.insert(std::move(object));
5353
}
5454

55-
void Track(std::shared_ptr<const DeviceBuffer> buffer) {
55+
void Track(std::shared_ptr<const Buffer> buffer) {
5656
if (!buffer) {
5757
return;
5858
}
5959
tracked_buffers_.insert(std::move(buffer));
6060
}
6161

62-
bool IsTracking(const std::shared_ptr<const DeviceBuffer>& buffer) const {
62+
bool IsTracking(const std::shared_ptr<const Buffer>& buffer) const {
6363
if (!buffer) {
6464
return false;
6565
}
@@ -89,7 +89,7 @@ class TrackedObjectsVK {
8989
std::weak_ptr<CommandPoolVK> pool_;
9090
vk::UniqueCommandBuffer buffer_;
9191
std::set<std::shared_ptr<SharedObjectVK>> tracked_objects_;
92-
std::set<std::shared_ptr<const DeviceBuffer>> tracked_buffers_;
92+
std::set<std::shared_ptr<const Buffer>> tracked_buffers_;
9393
std::set<std::shared_ptr<const TextureSourceVK>> tracked_textures_;
9494
bool is_valid_ = false;
9595

@@ -202,7 +202,7 @@ bool CommandEncoderVK::Track(std::shared_ptr<SharedObjectVK> object) {
202202
return true;
203203
}
204204

205-
bool CommandEncoderVK::Track(std::shared_ptr<const DeviceBuffer> buffer) {
205+
bool CommandEncoderVK::Track(std::shared_ptr<const Buffer> buffer) {
206206
if (!IsValid()) {
207207
return false;
208208
}
@@ -211,7 +211,7 @@ bool CommandEncoderVK::Track(std::shared_ptr<const DeviceBuffer> buffer) {
211211
}
212212

213213
bool CommandEncoderVK::IsTracking(
214-
const std::shared_ptr<const DeviceBuffer>& buffer) const {
214+
const std::shared_ptr<const Buffer>& buffer) const {
215215
if (!IsValid()) {
216216
return false;
217217
}

impeller/renderer/backend/vulkan/command_encoder_vk.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ namespace impeller {
2121
namespace testing {
2222
class BlitCommandVkTest_BlitCopyTextureToTextureCommandVK_Test;
2323
class BlitCommandVkTest_BlitCopyTextureToBufferCommandVK_Test;
24+
class BlitCommandVkTest_BlitCopyBufferToTextureCommandVK_Test;
2425
class BlitCommandVkTest_BlitGenerateMipmapCommandVK_Test;
2526
} // namespace testing
2627

2728
class ContextVK;
2829
class DeviceBuffer;
30+
class Buffer;
2931
class Texture;
3032
class TextureSourceVK;
3133
class TrackedObjectsVK;
@@ -43,9 +45,9 @@ class CommandEncoderVK {
4345

4446
bool Track(std::shared_ptr<SharedObjectVK> object);
4547

46-
bool Track(std::shared_ptr<const DeviceBuffer> buffer);
48+
bool Track(std::shared_ptr<const Buffer> buffer);
4749

48-
bool IsTracking(const std::shared_ptr<const DeviceBuffer>& texture) const;
50+
bool IsTracking(const std::shared_ptr<const Buffer>& texture) const;
4951

5052
bool Track(const std::shared_ptr<const Texture>& texture);
5153

@@ -72,6 +74,8 @@ class CommandEncoderVK {
7274
BlitCommandVkTest_BlitCopyTextureToBufferCommandVK_Test;
7375
friend class ::impeller::testing::
7476
BlitCommandVkTest_BlitGenerateMipmapCommandVK_Test;
77+
friend class ::impeller::testing::
78+
BlitCommandVkTest_BlitCopyBufferToTextureCommandVK_Test;
7579

7680
std::weak_ptr<const DeviceHolder> device_holder_;
7781
std::shared_ptr<QueueVK> queue_;

impeller/renderer/backend/vulkan/device_buffer_vk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
namespace impeller {
1515

1616
class DeviceBufferVK final : public DeviceBuffer,
17-
public BackendCast<DeviceBufferVK, DeviceBuffer> {
17+
public BackendCast<DeviceBufferVK, Buffer> {
1818
public:
1919
DeviceBufferVK(DeviceBufferDescriptor desc,
2020
std::weak_ptr<Context> context,

lib/ui/painting/image_decoder_impeller.cc

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -481,21 +481,19 @@ void ImageDecoderImpeller::Decode(fml::RefPtr<ImageDescriptor> descriptor,
481481
}
482482
auto upload_texture_and_invoke_result = [result, context, bitmap_result,
483483
gpu_disabled_switch]() {
484-
// TODO(jonahwilliams): remove ifdef once blit from buffer
485-
// to texture is implemented on other platforms.
486484
sk_sp<DlImage> image;
487485
std::string decode_error;
488-
489-
#ifdef FML_OS_IOS
490-
std::tie(image, decode_error) = UploadTextureToPrivate(
491-
context, bitmap_result.device_buffer, bitmap_result.image_info,
492-
bitmap_result.sk_bitmap, gpu_disabled_switch);
493-
#else
494-
std::tie(image, decode_error) =
495-
UploadTextureToShared(context, bitmap_result.sk_bitmap,
496-
gpu_disabled_switch, /*create_mips=*/true);
497-
#endif // FML_OS_IOS
498-
result(image, decode_error);
486+
if (context->GetCapabilities()->SupportsBufferToTextureBlits()) {
487+
std::tie(image, decode_error) = UploadTextureToPrivate(
488+
context, bitmap_result.device_buffer, bitmap_result.image_info,
489+
bitmap_result.sk_bitmap, gpu_disabled_switch);
490+
result(image, decode_error);
491+
} else {
492+
std::tie(image, decode_error) = UploadTextureToShared(
493+
context, bitmap_result.sk_bitmap, gpu_disabled_switch,
494+
/*create_mips=*/true);
495+
result(image, decode_error);
496+
}
499497
};
500498
// TODO(jonahwilliams):
501499
// https://github.com/flutter/flutter/issues/123058 Technically we

0 commit comments

Comments
 (0)