Skip to content

Commit ce4bc3d

Browse files
authored
[Flutter GPU] Track HostBuffer emplacements by offset. (flutter#49618)
Make the wrapped HostBuffer wrapper track/look up emplacements using a fake byte offset. This is a trick to keep Flutter GPU working after flutter/engine#49505 lands. I'll likely swing around and change how `BufferView` works later on. We can simplify a lot by making Flutter GPU `BufferView`s just take `DeviceBuffer` handles.
1 parent a35e3b0 commit ce4bc3d

File tree

5 files changed

+95
-17
lines changed

5 files changed

+95
-17
lines changed

impeller/fixtures/dart_tests.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,48 @@ gpu.RenderPipeline createUnlitRenderPipeline() {
196196
return gpu.gpuContext.createRenderPipeline(vertex!, fragment!);
197197
}
198198

199+
gpu.RenderPass createRenderPass() {
200+
final gpu.Texture? renderTexture =
201+
gpu.gpuContext.createTexture(gpu.StorageMode.devicePrivate, 100, 100);
202+
assert(renderTexture != null);
203+
204+
final gpu.CommandBuffer commandBuffer = gpu.gpuContext.createCommandBuffer();
205+
206+
final gpu.RenderTarget renderTarget = gpu.RenderTarget.singleColor(
207+
gpu.ColorAttachment(texture: renderTexture!),
208+
);
209+
return commandBuffer.createRenderPass(renderTarget);
210+
}
211+
212+
@pragma('vm:entry-point')
213+
void uniformBindFailsForInvalidHostBufferOffset() {
214+
final gpu.RenderPass encoder = createRenderPass();
215+
216+
final gpu.RenderPipeline pipeline = createUnlitRenderPipeline();
217+
encoder.bindPipeline(pipeline);
218+
219+
final gpu.HostBuffer transients = gpu.HostBuffer();
220+
final gpu.BufferView vertInfoData = transients.emplace(float32(<double>[
221+
1, 0, 0, 0, // mvp
222+
0, 1, 0, 0, // mvp
223+
0, 0, 1, 0, // mvp
224+
0, 0, 0, 1, // mvp
225+
0, 1, 0, 1, // color
226+
]));
227+
final gpu.BufferView viewWithBadOffset = gpu.BufferView(vertInfoData.buffer,
228+
offsetInBytes: 1, lengthInBytes: vertInfoData.lengthInBytes);
229+
230+
final gpu.UniformSlot vertInfo =
231+
pipeline.vertexShader.getUniformSlot('VertInfo');
232+
String? exception;
233+
try {
234+
encoder.bindUniform(vertInfo, viewWithBadOffset);
235+
} catch (e) {
236+
exception = e.toString();
237+
}
238+
assert(exception!.contains('Failed to bind uniform'));
239+
}
240+
199241
ByteData float32(List<double> values) {
200242
return Float32List.fromList(values).buffer.asByteData();
201243
}

impeller/renderer/renderer_dart_unittests.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ DART_TEST_CASE(textureAsImageThrowsWhenNotShaderReadable);
145145

146146
DART_TEST_CASE(canCreateShaderLibrary);
147147
DART_TEST_CASE(canReflectUniformStructs);
148+
DART_TEST_CASE(uniformBindFailsForInvalidHostBufferOffset);
148149

149150
DART_TEST_CASE(canCreateRenderPassAndSubmit);
150151

lib/gpu/host_buffer.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ size_t HostBuffer::EmplaceBytes(const tonic::DartByteData& byte_data) {
2525
auto view =
2626
host_buffer_->Emplace(byte_data.data(), byte_data.length_in_bytes(),
2727
impeller::DefaultUniformAlignment());
28+
emplacements_[current_offset_] = view;
29+
current_offset_ += view.range.length;
2830
return view.range.offset;
2931
}
3032

33+
std::optional<impeller::BufferView> HostBuffer::GetBufferViewForOffset(
34+
size_t offset) {
35+
return emplacements_[offset];
36+
}
37+
3138
} // namespace gpu
3239
} // namespace flutter
3340

lib/gpu/host_buffer.h

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

88
#include "flutter/lib/gpu/export.h"
99
#include "flutter/lib/ui/dart_wrapper.h"
10+
#include "impeller/core/buffer_view.h"
1011
#include "impeller/core/host_buffer.h"
1112
#include "third_party/tonic/typed_data/dart_byte_data.h"
1213

@@ -26,8 +27,12 @@ class HostBuffer : public RefCountedDartWrappable<HostBuffer> {
2627

2728
size_t EmplaceBytes(const tonic::DartByteData& byte_data);
2829

30+
std::optional<impeller::BufferView> GetBufferViewForOffset(size_t offset);
31+
2932
private:
33+
size_t current_offset_ = 0;
3034
std::shared_ptr<impeller::HostBuffer> host_buffer_;
35+
std::unordered_map<size_t, impeller::BufferView> emplacements_;
3136

3237
FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer);
3338
};

lib/gpu/render_pass.cc

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,13 @@ void InternalFlutterGpu_RenderPass_BindPipeline(
230230

231231
template <typename TBuffer>
232232
static void BindVertexBuffer(flutter::gpu::RenderPass* wrapper,
233-
TBuffer* buffer,
233+
TBuffer buffer,
234234
int offset_in_bytes,
235235
int length_in_bytes,
236236
int vertex_count) {
237237
auto& vertex_buffer = wrapper->GetVertexBuffer();
238238
vertex_buffer.vertex_buffer = impeller::BufferView{
239-
.buffer = buffer->GetBuffer(),
239+
.buffer = buffer,
240240
.range = impeller::Range(offset_in_bytes, length_in_bytes),
241241
};
242242
// If the index type is set, then the `vertex_count` becomes the index
@@ -258,8 +258,8 @@ void InternalFlutterGpu_RenderPass_BindVertexBufferDevice(
258258
int offset_in_bytes,
259259
int length_in_bytes,
260260
int vertex_count) {
261-
BindVertexBuffer(wrapper, device_buffer, offset_in_bytes, length_in_bytes,
262-
vertex_count);
261+
BindVertexBuffer(wrapper, device_buffer->GetBuffer(), offset_in_bytes,
262+
length_in_bytes, vertex_count);
263263
}
264264

265265
void InternalFlutterGpu_RenderPass_BindVertexBufferHost(
@@ -268,20 +268,28 @@ void InternalFlutterGpu_RenderPass_BindVertexBufferHost(
268268
int offset_in_bytes,
269269
int length_in_bytes,
270270
int vertex_count) {
271-
BindVertexBuffer(wrapper, host_buffer, offset_in_bytes, length_in_bytes,
272-
vertex_count);
271+
std::optional<impeller::BufferView> view =
272+
host_buffer->GetBufferViewForOffset(offset_in_bytes);
273+
if (!view.has_value()) {
274+
FML_LOG(ERROR)
275+
<< "Failed to bind vertex buffer due to invalid HostBuffer offset: "
276+
<< offset_in_bytes;
277+
return;
278+
}
279+
BindVertexBuffer(wrapper, view->buffer, view->range.offset,
280+
view->range.length, vertex_count);
273281
}
274282

275283
template <typename TBuffer>
276284
static void BindIndexBuffer(flutter::gpu::RenderPass* wrapper,
277-
TBuffer* buffer,
285+
TBuffer buffer,
278286
int offset_in_bytes,
279287
int length_in_bytes,
280288
int index_type,
281289
int index_count) {
282290
auto& vertex_buffer = wrapper->GetVertexBuffer();
283291
vertex_buffer.index_buffer = impeller::BufferView{
284-
.buffer = buffer->GetBuffer(),
292+
.buffer = buffer,
285293
.range = impeller::Range(offset_in_bytes, length_in_bytes),
286294
};
287295
vertex_buffer.index_type = flutter::gpu::ToImpellerIndexType(index_type);
@@ -295,8 +303,8 @@ void InternalFlutterGpu_RenderPass_BindIndexBufferDevice(
295303
int length_in_bytes,
296304
int index_type,
297305
int index_count) {
298-
BindIndexBuffer(wrapper, device_buffer, offset_in_bytes, length_in_bytes,
299-
index_type, index_count);
306+
BindIndexBuffer(wrapper, device_buffer->GetBuffer(), offset_in_bytes,
307+
length_in_bytes, index_type, index_count);
300308
}
301309

302310
void InternalFlutterGpu_RenderPass_BindIndexBufferHost(
@@ -306,15 +314,22 @@ void InternalFlutterGpu_RenderPass_BindIndexBufferHost(
306314
int length_in_bytes,
307315
int index_type,
308316
int index_count) {
309-
BindIndexBuffer(wrapper, host_buffer, offset_in_bytes, length_in_bytes,
317+
auto view = host_buffer->GetBufferViewForOffset(offset_in_bytes);
318+
if (!view.has_value()) {
319+
FML_LOG(ERROR)
320+
<< "Failed to bind index buffer due to invalid HostBuffer offset: "
321+
<< offset_in_bytes;
322+
return;
323+
}
324+
BindIndexBuffer(wrapper, view->buffer, view->range.offset, view->range.length,
310325
index_type, index_count);
311326
}
312327

313328
template <typename TBuffer>
314329
static bool BindUniform(flutter::gpu::RenderPass* wrapper,
315330
flutter::gpu::Shader* shader,
316331
Dart_Handle uniform_name_handle,
317-
TBuffer* buffer,
332+
TBuffer buffer,
318333
int offset_in_bytes,
319334
int length_in_bytes) {
320335
auto& command = wrapper->GetCommand();
@@ -331,7 +346,7 @@ static bool BindUniform(flutter::gpu::RenderPass* wrapper,
331346
return command.BindResource(
332347
shader->GetShaderStage(), uniform_struct->slot, uniform_struct->metadata,
333348
impeller::BufferView{
334-
.buffer = buffer->GetBuffer(),
349+
.buffer = buffer,
335350
.range = impeller::Range(offset_in_bytes, length_in_bytes),
336351
});
337352
}
@@ -343,8 +358,9 @@ bool InternalFlutterGpu_RenderPass_BindUniformDevice(
343358
flutter::gpu::DeviceBuffer* device_buffer,
344359
int offset_in_bytes,
345360
int length_in_bytes) {
346-
return BindUniform(wrapper, shader, uniform_name_handle, device_buffer,
347-
offset_in_bytes, length_in_bytes);
361+
return BindUniform(wrapper, shader, uniform_name_handle,
362+
device_buffer->GetBuffer(), offset_in_bytes,
363+
length_in_bytes);
348364
}
349365

350366
bool InternalFlutterGpu_RenderPass_BindUniformHost(
@@ -354,8 +370,15 @@ bool InternalFlutterGpu_RenderPass_BindUniformHost(
354370
flutter::gpu::HostBuffer* host_buffer,
355371
int offset_in_bytes,
356372
int length_in_bytes) {
357-
return BindUniform(wrapper, shader, uniform_name_handle, host_buffer,
358-
offset_in_bytes, length_in_bytes);
373+
auto view = host_buffer->GetBufferViewForOffset(offset_in_bytes);
374+
if (!view.has_value()) {
375+
FML_LOG(ERROR)
376+
<< "Failed to bind index buffer due to invalid HostBuffer offset: "
377+
<< offset_in_bytes;
378+
return false;
379+
}
380+
return BindUniform(wrapper, shader, uniform_name_handle, view->buffer,
381+
view->range.offset, view->range.length);
359382
}
360383

361384
bool InternalFlutterGpu_RenderPass_BindTexture(

0 commit comments

Comments
 (0)