Skip to content

Commit 95b9b5d

Browse files
[Impeller] Add blit command to copy texture to buffer (flutter#37198)
1 parent fbe98c0 commit 95b9b5d

18 files changed

+416
-19
lines changed

impeller/renderer/backend/gles/blit_command_gles.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "flutter/fml/closure.h"
88
#include "impeller/base/validation.h"
9+
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
910
#include "impeller/renderer/backend/gles/texture_gles.h"
1011

1112
namespace impeller {
@@ -116,6 +117,44 @@ bool BlitCopyTextureToTextureCommandGLES::Encode(
116117
return true;
117118
};
118119

120+
BlitCopyTextureToBufferCommandGLES::~BlitCopyTextureToBufferCommandGLES() =
121+
default;
122+
123+
std::string BlitCopyTextureToBufferCommandGLES::GetLabel() const {
124+
return label;
125+
}
126+
127+
bool BlitCopyTextureToBufferCommandGLES::Encode(
128+
const ReactorGLES& reactor) const {
129+
if (source->GetTextureDescriptor().format != PixelFormat::kR8G8B8A8UNormInt) {
130+
VALIDATION_LOG << "Only textures with pixel format RGBA are supported yet.";
131+
return false;
132+
}
133+
134+
const auto& gl = reactor.GetProcTable();
135+
136+
GLuint read_fbo = GL_NONE;
137+
fml::ScopedCleanupClosure delete_fbos(
138+
[&gl, &read_fbo]() { DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER); });
139+
140+
{
141+
auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
142+
if (!read.has_value()) {
143+
return false;
144+
}
145+
read_fbo = read.value();
146+
}
147+
148+
DeviceBufferGLES::Cast(*destination)
149+
.UpdateBufferData([&gl, this](uint8_t* data, size_t length) {
150+
gl.ReadPixels(source_region.origin.x, source_region.origin.y,
151+
source_region.size.width, source_region.size.height,
152+
GL_RGBA, GL_UNSIGNED_BYTE, data + destination_offset);
153+
});
154+
155+
return true;
156+
};
157+
119158
BlitGenerateMipmapCommandGLES::~BlitGenerateMipmapCommandGLES() = default;
120159

121160
std::string BlitGenerateMipmapCommandGLES::GetLabel() const {

impeller/renderer/backend/gles/blit_command_gles.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ struct BlitCopyTextureToTextureCommandGLES
2929
[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
3030
};
3131

32+
struct BlitCopyTextureToBufferCommandGLES
33+
: public BlitEncodeGLES,
34+
public BlitCopyTextureToBufferCommand {
35+
~BlitCopyTextureToBufferCommandGLES() override;
36+
37+
std::string GetLabel() const override;
38+
39+
[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
40+
};
41+
3242
struct BlitGenerateMipmapCommandGLES : public BlitEncodeGLES,
3343
public BlitGenerateMipmapCommand {
3444
~BlitGenerateMipmapCommandGLES() override;

impeller/renderer/backend/gles/blit_pass_gles.cc

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ bool BlitPassGLES::EncodeCommands(
9595
}
9696

9797
// |BlitPass|
98-
void BlitPassGLES::OnCopyTextureToTextureCommand(
98+
bool BlitPassGLES::OnCopyTextureToTextureCommand(
9999
std::shared_ptr<Texture> source,
100100
std::shared_ptr<Texture> destination,
101101
IRect source_region,
@@ -109,16 +109,36 @@ void BlitPassGLES::OnCopyTextureToTextureCommand(
109109
command->destination_origin = destination_origin;
110110

111111
commands_.emplace_back(std::move(command));
112+
return true;
112113
}
113114

114115
// |BlitPass|
115-
void BlitPassGLES::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
116+
bool BlitPassGLES::OnCopyTextureToBufferCommand(
117+
std::shared_ptr<Texture> source,
118+
std::shared_ptr<DeviceBuffer> destination,
119+
IRect source_region,
120+
size_t destination_offset,
121+
std::string label) {
122+
auto command = std::make_unique<BlitCopyTextureToBufferCommandGLES>();
123+
command->label = label;
124+
command->source = std::move(source);
125+
command->destination = std::move(destination);
126+
command->source_region = source_region;
127+
command->destination_offset = destination_offset;
128+
129+
commands_.emplace_back(std::move(command));
130+
return true;
131+
}
132+
133+
// |BlitPass|
134+
bool BlitPassGLES::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
116135
std::string label) {
117136
auto command = std::make_unique<BlitGenerateMipmapCommandGLES>();
118137
command->label = label;
119138
command->texture = std::move(texture);
120139

121140
commands_.emplace_back(std::move(command));
141+
return true;
122142
}
123143

124144
} // namespace impeller

impeller/renderer/backend/gles/blit_pass_gles.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,21 @@ class BlitPassGLES final : public BlitPass {
3737
const std::shared_ptr<Allocator>& transients_allocator) const override;
3838

3939
// |BlitPass|
40-
void OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
40+
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
4141
std::shared_ptr<Texture> destination,
4242
IRect source_region,
4343
IPoint destination_origin,
4444
std::string label) override;
4545

4646
// |BlitPass|
47-
void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
47+
bool OnCopyTextureToBufferCommand(std::shared_ptr<Texture> source,
48+
std::shared_ptr<DeviceBuffer> destination,
49+
IRect source_region,
50+
size_t destination_offset,
51+
std::string label) override;
52+
53+
// |BlitPass|
54+
bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
4855
std::string label) override;
4956

5057
FML_DISALLOW_COPY_AND_ASSIGN(BlitPassGLES);

impeller/renderer/backend/gles/device_buffer_gles.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,15 @@ bool DeviceBufferGLES::SetLabel(const std::string& label, Range range) {
109109
const uint8_t* DeviceBufferGLES::GetBufferData() const {
110110
return backing_store_->GetBuffer();
111111
}
112+
113+
void DeviceBufferGLES::UpdateBufferData(
114+
const std::function<void(uint8_t* data, size_t length)>&
115+
update_buffer_data) {
116+
if (update_buffer_data) {
117+
update_buffer_data(backing_store_->GetBuffer(),
118+
backing_store_->GetLength());
119+
++generation_;
120+
}
121+
}
122+
112123
} // namespace impeller

impeller/renderer/backend/gles/device_buffer_gles.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class DeviceBufferGLES final
2727

2828
const uint8_t* GetBufferData() const;
2929

30+
void UpdateBufferData(
31+
const std::function<void(uint8_t*, size_t length)>& update_buffer_data);
32+
3033
enum class BindingType {
3134
kArrayBuffer,
3235
kElementArrayBuffer,

impeller/renderer/backend/gles/proc_table_gles.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ struct GLProc {
162162
PROC(UniformMatrix4fv); \
163163
PROC(UseProgram); \
164164
PROC(VertexAttribPointer); \
165-
PROC(Viewport);
165+
PROC(Viewport); \
166+
PROC(ReadPixels);
166167

167168
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC) PROC(BlitFramebuffer);
168169

impeller/renderer/backend/metal/blit_command_mtl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ struct BlitCopyTextureToTextureCommandMTL
3131
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
3232
};
3333

34+
struct BlitCopyTextureToBufferCommandMTL
35+
: public BlitCopyTextureToBufferCommand,
36+
public BlitEncodeMTL {
37+
~BlitCopyTextureToBufferCommandMTL() override;
38+
39+
std::string GetLabel() const override;
40+
41+
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
42+
};
43+
3444
struct BlitGenerateMipmapCommandMTL : public BlitGenerateMipmapCommand,
3545
public BlitEncodeMTL {
3646
~BlitGenerateMipmapCommandMTL() override;

impeller/renderer/backend/metal/blit_command_mtl.mm

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
66

7+
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
78
#include "impeller/renderer/backend/metal/texture_mtl.h"
89

910
namespace impeller {
@@ -49,6 +50,50 @@
4950
return true;
5051
};
5152

53+
BlitCopyTextureToBufferCommandMTL::~BlitCopyTextureToBufferCommandMTL() =
54+
default;
55+
56+
std::string BlitCopyTextureToBufferCommandMTL::GetLabel() const {
57+
return label;
58+
}
59+
60+
bool BlitCopyTextureToBufferCommandMTL::Encode(
61+
id<MTLBlitCommandEncoder> encoder) const {
62+
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
63+
if (!source_mtl) {
64+
return false;
65+
}
66+
67+
auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
68+
if (!destination_mtl) {
69+
return false;
70+
}
71+
72+
auto source_origin_mtl =
73+
MTLOriginMake(source_region.origin.x, source_region.origin.y, 0);
74+
auto source_size_mtl =
75+
MTLSizeMake(source_region.size.width, source_region.size.height, 1);
76+
77+
auto destination_bytes_per_pixel =
78+
BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
79+
auto destination_bytes_per_row =
80+
source_size_mtl.width * destination_bytes_per_pixel;
81+
auto destination_bytes_per_image =
82+
source_size_mtl.height * destination_bytes_per_row;
83+
84+
[encoder copyFromTexture:source_mtl
85+
sourceSlice:0
86+
sourceLevel:0
87+
sourceOrigin:source_origin_mtl
88+
sourceSize:source_size_mtl
89+
toBuffer:destination_mtl
90+
destinationOffset:destination_offset
91+
destinationBytesPerRow:destination_bytes_per_row
92+
destinationBytesPerImage:destination_bytes_per_image];
93+
94+
return true;
95+
};
96+
5297
BlitGenerateMipmapCommandMTL::~BlitGenerateMipmapCommandMTL() = default;
5398

5499
std::string BlitGenerateMipmapCommandMTL::GetLabel() const {

impeller/renderer/backend/metal/blit_pass_mtl.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,21 @@ class BlitPassMTL final : public BlitPass {
4040
bool EncodeCommands(id<MTLBlitCommandEncoder> pass) const;
4141

4242
// |BlitPass|
43-
void OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
43+
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
4444
std::shared_ptr<Texture> destination,
4545
IRect source_region,
4646
IPoint destination_origin,
4747
std::string label) override;
4848

4949
// |BlitPass|
50-
void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
50+
bool OnCopyTextureToBufferCommand(std::shared_ptr<Texture> source,
51+
std::shared_ptr<DeviceBuffer> destination,
52+
IRect source_region,
53+
size_t destination_offset,
54+
std::string label) override;
55+
56+
// |BlitPass|
57+
bool OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
5158
std::string label) override;
5259

5360
FML_DISALLOW_COPY_AND_ASSIGN(BlitPassMTL);

0 commit comments

Comments
 (0)