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

Commit 852b52c

Browse files
authored
Render a compute generated stroke (#40184)
[Impeller] Render a compute generated stroke
1 parent fdaac76 commit 852b52c

File tree

6 files changed

+107
-49
lines changed

6 files changed

+107
-49
lines changed

impeller/fixtures/stroke.comp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ layout(binding = 0) buffer Polyline {
1717
polyline;
1818

1919
layout(binding = 1) buffer VertexBuffer {
20-
uint count;
2120
vec2 position[];
2221
}
2322
vertex_buffer;
2423

24+
layout(binding = 2) buffer VertexBufferCount {
25+
uint count;
26+
}
27+
vertex_buffer_count;
28+
2529
uniform Config {
2630
float width;
2731
uint cap;
@@ -41,7 +45,7 @@ void main() {
4145
return;
4246
}
4347

44-
atomicAdd(vertex_buffer.count, 4);
48+
atomicAdd(vertex_buffer_count.count, 4);
4549

4650
vec2 offset = compute_offset(ident);
4751
uint index = ident - 1;

impeller/playground/compute_playground_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ void ComputePlaygroundTest::SetUp() {
2424
}
2525

2626
SetupContext(GetParam());
27+
SetupWindow();
2728

2829
start_time_ = fml::TimePoint::Now().ToEpochDelta();
2930
}

impeller/playground/compute_playground_test.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "flutter/testing/testing.h"
1212
#include "impeller/geometry/scalar.h"
1313
#include "impeller/playground/playground.h"
14+
#include "impeller/renderer/device_buffer.h"
1415

1516
namespace impeller {
1617

@@ -36,6 +37,18 @@ class ComputePlaygroundTest
3637
// |Playground|
3738
std::string GetWindowTitle() const override;
3839

40+
template <typename T>
41+
std::shared_ptr<DeviceBuffer> CreateHostVisibleDeviceBuffer(
42+
std::shared_ptr<Context> context,
43+
const std::string& label) {
44+
DeviceBufferDescriptor desc;
45+
desc.storage_mode = StorageMode::kHostVisible;
46+
desc.size = sizeof(T);
47+
auto buffer = context->GetResourceAllocator()->CreateBuffer(desc);
48+
buffer->SetLabel(label);
49+
return buffer;
50+
}
51+
3952
private:
4053
fml::TimeDelta start_time_;
4154

impeller/renderer/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ impeller_component("renderer_unittests") {
121121

122122
deps = [
123123
":renderer",
124+
"../entity",
124125
"../fixtures",
125126
"../playground:playground_test",
126127
"//flutter/testing:testing_lib",

impeller/renderer/compute_subgroup_unittests.cc

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <numeric>
6+
57
#include "flutter/fml/synchronization/waitable_event.h"
68
#include "flutter/fml/time/time_point.h"
79
#include "flutter/testing/testing.h"
810
#include "gmock/gmock.h"
911
#include "impeller/base/strings.h"
12+
#include "impeller/entity/contents/content_context.h"
1013
#include "impeller/fixtures/cubic_to_quads.comp.h"
1114
#include "impeller/fixtures/golden_heart.h"
1215
#include "impeller/fixtures/quad_polyline.comp.h"
@@ -22,6 +25,7 @@
2225
#include "impeller/renderer/compute_pipeline_builder.h"
2326
#include "impeller/renderer/formats.h"
2427
#include "impeller/renderer/pipeline_library.h"
28+
#include "impeller/renderer/render_pass.h"
2529

2630
namespace impeller {
2731
namespace testing {
@@ -44,27 +48,21 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
4448
static constexpr size_t kCubicCount = 6;
4549
static constexpr Scalar kAccuracy = .1;
4650

47-
DeviceBufferDescriptor quad_buffer_desc;
48-
quad_buffer_desc.storage_mode = StorageMode::kHostVisible;
49-
quad_buffer_desc.size = sizeof(CS::Quads<kCubicCount * 10>);
50-
auto quads = context->GetResourceAllocator()->CreateBuffer(quad_buffer_desc);
51-
quads->SetLabel("Quads");
51+
auto quads = CreateHostVisibleDeviceBuffer<CS::Quads<kCubicCount * 10>>(
52+
context, "Quads");
5253

53-
DeviceBufferDescriptor point_buffer_desc;
54-
point_buffer_desc.storage_mode = StorageMode::kHostVisible;
5554
// TODO(dnfield): Size this buffer more accurately.
56-
point_buffer_desc.size = sizeof(QS::Polyline<kCubicCount * 10 * 10>);
5755
auto polyline =
58-
context->GetResourceAllocator()->CreateBuffer(point_buffer_desc);
59-
polyline->SetLabel("polyline");
56+
CreateHostVisibleDeviceBuffer<QS::Polyline<kCubicCount * 10 * 10>>(
57+
context, "polyline");
58+
59+
auto vertex_buffer_count =
60+
CreateHostVisibleDeviceBuffer<SS::VertexBufferCount>(context,
61+
"VertexBufferCount");
6062

61-
DeviceBufferDescriptor vertex_buffer_desc;
62-
vertex_buffer_desc.storage_mode = StorageMode::kHostVisible;
6363
// TODO(dnfield): Size this buffer more accurately.
64-
vertex_buffer_desc.size = sizeof(SS::VertexBuffer<kCubicCount * 10 * 10 * 4>);
65-
auto vertex_buffer =
66-
context->GetResourceAllocator()->CreateBuffer(vertex_buffer_desc);
67-
vertex_buffer->SetLabel("VertexBuffer");
64+
auto vertex_buffer = CreateHostVisibleDeviceBuffer<
65+
SS::VertexBuffer<kCubicCount * 10 * 10 * 4>>(context, "VertexBuffer");
6866

6967
{
7068
using CubicPipelineBuilder = ComputePipelineBuilder<CS>;
@@ -138,13 +136,14 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
138136
pass->SetThreadGroupSize(ISize(1024, 1));
139137

140138
ComputeCommand cmd;
141-
cmd.label = "Stroke";
139+
cmd.label = "Draw Stroke";
142140
cmd.pipeline = compute_pipeline;
143141

144142
SS::Config config{.width = 1.0f, .cap = 1, .join = 1, .miter_limit = 4.0f};
145143
SS::BindConfig(cmd, pass->GetTransientsBuffer().EmplaceUniform(config));
146144

147145
SS::BindPolyline(cmd, polyline->AsBufferView());
146+
SS::BindVertexBufferCount(cmd, vertex_buffer_count->AsBufferView());
148147
SS::BindVertexBuffer(cmd, vertex_buffer->AsBufferView());
149148

150149
ASSERT_TRUE(pass->AddCommand(std::move(cmd)));
@@ -154,7 +153,7 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
154153

155154
fml::AutoResetWaitableEvent latch;
156155
ASSERT_TRUE(cmd_buffer->SubmitCommands([&latch, quads, polyline,
157-
vertex_buffer](
156+
vertex_buffer_count, vertex_buffer](
158157
CommandBuffer::Status status) {
159158
EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
160159

@@ -183,7 +182,9 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
183182

184183
auto* v = reinterpret_cast<SS::VertexBuffer<kCubicCount * 10 * 10 * 4>*>(
185184
vertex_buffer->AsBufferView().contents);
186-
EXPECT_EQ(v->count, golden_heart_vertices.size());
185+
auto* v_count = reinterpret_cast<SS::VertexBufferCount*>(
186+
vertex_buffer_count->AsBufferView().contents);
187+
EXPECT_EQ(v_count->count, golden_heart_vertices.size());
187188
for (size_t i = 0; i < golden_heart_vertices.size(); i += 1) {
188189
EXPECT_LT(std::abs(golden_heart_vertices[i].x - v->position[i].x), 1e-3);
189190
EXPECT_LT(std::abs(golden_heart_vertices[i].y - v->position[i].y), 1e-3);
@@ -193,6 +194,64 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
193194
}));
194195

195196
latch.Wait();
197+
198+
auto callback = [&](RenderPass& pass) -> bool {
199+
ContentContext renderer(context);
200+
if (!renderer.IsValid()) {
201+
return false;
202+
}
203+
204+
using VS = SolidFillPipeline::VertexShader;
205+
using FS = SolidFillPipeline::FragmentShader;
206+
207+
Command cmd;
208+
cmd.label = "Draw Stroke";
209+
cmd.stencil_reference = 0; // entity.GetStencilDepth();
210+
211+
ContentContextOptions options;
212+
options.sample_count = pass.GetRenderTarget().GetSampleCount();
213+
options.color_attachment_pixel_format =
214+
pass.GetRenderTarget().GetRenderTargetPixelFormat();
215+
options.has_stencil_attachment =
216+
pass.GetRenderTarget().GetStencilAttachment().has_value();
217+
options.blend_mode = BlendMode::kSourceIn; // entity.GetBlendMode();
218+
options.primitive_type = PrimitiveType::kTriangleStrip;
219+
options.stencil_compare = CompareFunction::kEqual;
220+
options.stencil_operation = StencilOperation::kIncrementClamp;
221+
222+
cmd.pipeline = renderer.GetSolidFillPipeline(options);
223+
224+
auto count = golden_heart_vertices.size();
225+
auto& host_buffer = pass.GetTransientsBuffer();
226+
std::vector<uint16_t> indices(count);
227+
std::iota(std::begin(indices), std::end(indices), 0);
228+
229+
VertexBuffer render_vertex_buffer{
230+
.vertex_buffer = vertex_buffer->AsBufferView(),
231+
.index_buffer = host_buffer.Emplace(
232+
indices.data(), count * sizeof(uint16_t), alignof(uint16_t)),
233+
.index_count = count,
234+
.index_type = IndexType::k16bit};
235+
cmd.BindVertices(render_vertex_buffer);
236+
237+
VS::FrameInfo frame_info;
238+
auto world_matrix = Matrix::MakeScale(GetContentScale());
239+
frame_info.mvp =
240+
Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * world_matrix;
241+
VS::BindFrameInfo(cmd,
242+
pass.GetTransientsBuffer().EmplaceUniform(frame_info));
243+
244+
FS::FragInfo frag_info;
245+
frag_info.color = Color::Red().Premultiply();
246+
FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info));
247+
248+
if (!pass.AddCommand(std::move(cmd))) {
249+
return false;
250+
}
251+
252+
return true;
253+
};
254+
ASSERT_TRUE(OpenPlaygroundHere(callback));
196255
}
197256

198257
TEST_P(ComputeTest, QuadsToPolyline) {
@@ -215,12 +274,8 @@ TEST_P(ComputeTest, QuadsToPolyline) {
215274
golden_heart_quads[i].p2};
216275
}
217276

218-
DeviceBufferDescriptor point_buffer_desc;
219-
point_buffer_desc.storage_mode = StorageMode::kHostVisible;
220-
point_buffer_desc.size = sizeof(QS::Polyline<kPolylineCount>);
221-
auto polyline =
222-
context->GetResourceAllocator()->CreateBuffer(point_buffer_desc);
223-
polyline->SetLabel("polyline");
277+
auto polyline = CreateHostVisibleDeviceBuffer<QS::Polyline<kPolylineCount>>(
278+
context, "polyline");
224279

225280
{
226281
using QuadPipelineBuilder = ComputePipelineBuilder<QS>;

impeller/renderer/compute_unittests.cc

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,8 @@ TEST_P(ComputeTest, CanCreateComputePass) {
6464
input_0.some_int = 5;
6565
input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
6666

67-
DeviceBufferDescriptor buffer_desc;
68-
buffer_desc.storage_mode = StorageMode::kHostVisible;
69-
buffer_desc.size = sizeof(CS::Output<kCount>);
70-
71-
auto output_buffer =
72-
context->GetResourceAllocator()->CreateBuffer(buffer_desc);
73-
output_buffer->SetLabel("Output Buffer");
67+
auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
68+
context, "Output Buffer");
7469

7570
CS::BindInfo(cmd, pass->GetTransientsBuffer().EmplaceUniform(info));
7671
CS::BindInput0(cmd,
@@ -154,21 +149,10 @@ TEST_P(ComputeTest, MultiStageInputAndOutput) {
154149
input_2.elements[i] = i;
155150
}
156151

157-
DeviceBufferDescriptor output_desc_1;
158-
output_desc_1.storage_mode = StorageMode::kHostVisible;
159-
output_desc_1.size = sizeof(CS1::Output<kCount2>);
160-
161-
auto output_buffer_1 =
162-
context->GetResourceAllocator()->CreateBuffer(output_desc_1);
163-
output_buffer_1->SetLabel("Output Buffer Stage 1");
164-
165-
DeviceBufferDescriptor output_desc_2;
166-
output_desc_2.storage_mode = StorageMode::kHostVisible;
167-
output_desc_2.size = sizeof(CS2::Output<kCount2>);
168-
169-
auto output_buffer_2 =
170-
context->GetResourceAllocator()->CreateBuffer(output_desc_2);
171-
output_buffer_2->SetLabel("Output Buffer Stage 2");
152+
auto output_buffer_1 = CreateHostVisibleDeviceBuffer<CS1::Output<kCount2>>(
153+
context, "Output Buffer Stage 1");
154+
auto output_buffer_2 = CreateHostVisibleDeviceBuffer<CS2::Output<kCount2>>(
155+
context, "Output Buffer Stage 2");
172156

173157
{
174158
ComputeCommand cmd;

0 commit comments

Comments
 (0)