5#include "flutter/fml/synchronization/waitable_event.h"
6#include "flutter/testing/testing.h"
7#include "gmock/gmock.h"
9#include "impeller/fixtures/sample.comp.h"
10#include "impeller/fixtures/stage1.comp.h"
11#include "impeller/fixtures/stage2.comp.h"
16#include "impeller/renderer/prefix_sum_test.comp.h"
17#include "impeller/renderer/threadgroup_sizing_test.comp.h"
27 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
31 using CS = SampleComputeShader;
35 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
39 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
40 ASSERT_TRUE(pipeline_desc.has_value());
41 auto compute_pipeline =
42 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
43 ASSERT_TRUE(compute_pipeline);
45 auto cmd_buffer = context->CreateCommandBuffer();
46 auto pass = cmd_buffer->CreateComputePass();
47 ASSERT_TRUE(pass && pass->IsValid());
49 static constexpr size_t kCount = 5;
51 pass->SetPipeline(compute_pipeline);
53 CS::Info
info{.count = kCount};
54 CS::Input0<kCount> input_0;
55 CS::Input1<kCount> input_1;
56 for (
size_t i = 0;
i < kCount;
i++) {
57 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
58 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
61 input_0.fixed_array[1] =
IPoint32(2, 2);
64 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
66 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
67 context,
"Output Buffer");
69 CS::BindInfo(*pass, host_buffer->EmplaceUniform(
info));
70 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
71 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
74 ASSERT_TRUE(pass->Compute(
ISize(kCount, 1)).
ok());
75 ASSERT_TRUE(pass->EncodeCommands());
79 context->GetCommandQueue()
82 [&latch, output_buffer, &input_0,
84 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
86 auto view = DeviceBuffer::AsBufferView(output_buffer);
87 EXPECT_EQ(view.range.length, sizeof(CS::Output<kCount>));
89 CS::Output<kCount>* output =
90 reinterpret_cast<CS::Output<kCount>*>(
91 output_buffer->OnGetContents());
93 for (size_t i = 0; i < kCount; i++) {
94 Vector4 vector = output->elements[i];
95 Vector4 computed = input_0.elements[i] * input_1.elements[i];
97 Vector4(computed.x + 2 + input_1.some_struct.i,
98 computed.y + 3 + input_1.some_struct.vf.x,
99 computed.z + 5 + input_1.some_struct.vf.y,
110 using CS = PrefixSumTestComputeShader;
113 ASSERT_TRUE(context);
114 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
118 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
119 ASSERT_TRUE(pipeline_desc.has_value());
120 auto compute_pipeline =
121 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
122 ASSERT_TRUE(compute_pipeline);
124 auto cmd_buffer = context->CreateCommandBuffer();
125 auto pass = cmd_buffer->CreateComputePass();
126 ASSERT_TRUE(pass && pass->IsValid());
128 static constexpr size_t kCount = 5;
130 pass->SetPipeline(compute_pipeline);
132 CS::InputData<kCount> input_data;
133 input_data.count = kCount;
134 for (
size_t i = 0;
i < kCount;
i++) {
135 input_data.data[
i] = 1 +
i;
138 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
139 context,
"Output Buffer");
141 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
144 ASSERT_TRUE(pass->Compute(
ISize(kCount, 1)).
ok());
145 ASSERT_TRUE(pass->EncodeCommands());
149 context->GetCommandQueue()
150 ->Submit({cmd_buffer},
152 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
154 auto view = DeviceBuffer::AsBufferView(output_buffer);
155 EXPECT_EQ(view.range.length,
156 sizeof(CS::OutputData<kCount>));
158 CS::OutputData<kCount>* output =
159 reinterpret_cast<CS::OutputData<kCount>*>(
160 output_buffer->OnGetContents());
163 constexpr uint32_t expected[kCount] = {1, 3, 6, 10, 15};
164 for (
size_t i = 0;
i < kCount;
i++) {
165 auto computed_sum =
output->data[
i];
166 EXPECT_EQ(computed_sum, expected[
i]);
176 using CS = ThreadgroupSizingTestComputeShader;
178 ASSERT_TRUE(context);
179 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
183 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
184 ASSERT_TRUE(pipeline_desc.has_value());
185 auto compute_pipeline =
186 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
187 ASSERT_TRUE(compute_pipeline);
189 auto cmd_buffer = context->CreateCommandBuffer();
190 auto pass = cmd_buffer->CreateComputePass();
191 ASSERT_TRUE(pass && pass->IsValid());
193 static constexpr size_t kCount = 2048;
195 pass->SetPipeline(compute_pipeline);
197 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
198 context,
"Output Buffer");
200 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
202 ASSERT_TRUE(pass->Compute(
ISize(kCount, 1)).
ok());
203 ASSERT_TRUE(pass->EncodeCommands());
207 context->GetCommandQueue()
208 ->Submit({cmd_buffer},
210 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
212 auto view = DeviceBuffer::AsBufferView(output_buffer);
213 EXPECT_EQ(view.range.length,
214 sizeof(CS::OutputData<kCount>));
216 CS::OutputData<kCount>* output =
217 reinterpret_cast<CS::OutputData<kCount>*>(
218 output_buffer->OnGetContents());
220 EXPECT_EQ(output->data[kCount - 1], kCount - 1);
229 using CS = PrefixSumTestComputeShader;
234 ASSERT_TRUE(context);
235 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
240 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
241 auto compute_pipeline =
242 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
244 auto cmd_buffer = context->CreateCommandBuffer();
245 auto pass = cmd_buffer->CreateComputePass();
247 static constexpr size_t kCount = 1023;
249 pass->SetPipeline(compute_pipeline);
251 CS::InputData<kCount> input_data;
252 input_data.count = kCount;
253 for (
size_t i = 0;
i < kCount;
i++) {
254 input_data.data[
i] = 1 +
i;
257 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
258 context,
"Output Buffer");
260 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
261 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
263 pass->Compute(
ISize(kCount, 1));
264 pass->EncodeCommands();
265 host_buffer->Reset();
266 return context->GetCommandQueue()->Submit({cmd_buffer}).
ok();
268 ASSERT_TRUE(OpenPlaygroundHere(
callback));
272 using CS1 = Stage1ComputeShader;
274 using CS2 = Stage2ComputeShader;
279 ASSERT_TRUE(context);
280 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
282 auto pipeline_desc_1 =
283 Stage1PipelineBuilder::MakeDefaultPipelineDescriptor(*context);
284 ASSERT_TRUE(pipeline_desc_1.has_value());
285 auto compute_pipeline_1 =
286 context->GetPipelineLibrary()->GetPipeline(pipeline_desc_1).Get();
287 ASSERT_TRUE(compute_pipeline_1);
289 auto pipeline_desc_2 =
290 Stage2PipelineBuilder::MakeDefaultPipelineDescriptor(*context);
291 ASSERT_TRUE(pipeline_desc_2.has_value());
292 auto compute_pipeline_2 =
293 context->GetPipelineLibrary()->GetPipeline(pipeline_desc_2).Get();
294 ASSERT_TRUE(compute_pipeline_2);
296 auto cmd_buffer = context->CreateCommandBuffer();
297 auto pass = cmd_buffer->CreateComputePass();
298 ASSERT_TRUE(pass && pass->IsValid());
300 static constexpr size_t kCount1 = 5;
301 static constexpr size_t kCount2 =
kCount1 * 2;
303 CS1::Input<kCount1> input_1;
306 input_1.elements[
i] =
i;
309 CS2::Input<kCount2> input_2;
310 input_2.count = kCount2;
311 for (
size_t i = 0;
i < kCount2;
i++) {
312 input_2.elements[
i] =
i;
315 auto output_buffer_1 = CreateHostVisibleDeviceBuffer<CS1::Output<kCount2>>(
316 context,
"Output Buffer Stage 1");
317 auto output_buffer_2 = CreateHostVisibleDeviceBuffer<CS2::Output<kCount2>>(
318 context,
"Output Buffer Stage 2");
321 pass->SetPipeline(compute_pipeline_1);
323 CS1::BindInput(*pass, host_buffer->EmplaceStorageBuffer(input_1));
324 CS1::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
326 ASSERT_TRUE(pass->Compute(
ISize(512, 1)).
ok());
327 pass->AddBufferMemoryBarrier();
331 pass->SetPipeline(compute_pipeline_2);
333 CS1::BindInput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
334 CS2::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_2));
335 ASSERT_TRUE(pass->Compute(
ISize(512, 1)).
ok());
338 ASSERT_TRUE(pass->EncodeCommands());
342 context->GetCommandQueue()
343 ->Submit({cmd_buffer},
344 [&latch, &output_buffer_1,
346 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
348 CS1::Output<kCount2>* output_1 =
349 reinterpret_cast<CS1::Output<kCount2>*>(
350 output_buffer_1->OnGetContents());
351 EXPECT_TRUE(output_1);
352 EXPECT_EQ(output_1->count, 10u);
355 ::testing::ElementsAre(0, 0, 2, 3, 4, 6, 6, 9, 8, 12));
357 CS2::Output<kCount2>* output_2 =
358 reinterpret_cast<CS2::Output<kCount2>*>(
359 output_buffer_2->OnGetContents());
360 EXPECT_TRUE(output_2);
361 EXPECT_EQ(output_2->count, 10u);
362 EXPECT_THAT(output_2->elements,
363 ::testing::ElementsAre(0, 0, 4, 6, 8, 12, 12,
374 using CS = SampleComputeShader;
377 ASSERT_TRUE(context);
378 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
382 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
383 ASSERT_TRUE(pipeline_desc.has_value());
384 auto compute_pipeline =
385 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
386 ASSERT_TRUE(compute_pipeline);
388 auto cmd_buffer = context->CreateCommandBuffer();
389 auto pass = cmd_buffer->CreateComputePass();
390 ASSERT_TRUE(pass && pass->IsValid());
392 static constexpr size_t kCount = 5;
394 pass->SetPipeline(compute_pipeline);
396 CS::Info
info{.count = kCount};
397 CS::Input0<kCount> input_0;
398 CS::Input1<kCount> input_1;
399 for (
size_t i = 0;
i < kCount;
i++) {
400 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
401 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
404 input_0.fixed_array[1] =
IPoint32(2, 2);
406 input_0.some_int = 5;
407 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
409 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
410 context,
"Output Buffer");
412 CS::BindInfo(*pass, host_buffer->EmplaceUniform(
info));
413 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
414 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
415 CS::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer));
417 ASSERT_TRUE(pass->Compute(
ISize(kCount, 1)).
ok());
418 ASSERT_TRUE(pass->EncodeCommands());
422 context->GetCommandQueue()
425 [&latch, output_buffer, &input_0,
427 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
429 auto view = DeviceBuffer::AsBufferView(output_buffer);
430 EXPECT_EQ(view.range.length, sizeof(CS::Output<kCount>));
432 CS::Output<kCount>* output =
433 reinterpret_cast<CS::Output<kCount>*>(
434 output_buffer->OnGetContents());
436 for (size_t i = 0; i < kCount; i++) {
437 Vector4 vector = output->elements[i];
438 Vector4 computed = input_0.elements[i] * input_1.elements[i];
440 Vector4(computed.x + 2 + input_1.some_struct.i,
441 computed.y + 3 + input_1.some_struct.vf.x,
442 computed.z + 5 + input_1.some_struct.vf.y,
453 using CS = SampleComputeShader;
456 ASSERT_TRUE(context);
457 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
461 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
462 ASSERT_TRUE(pipeline_desc.has_value());
463 auto compute_pipeline =
464 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
465 ASSERT_TRUE(compute_pipeline);
467 auto cmd_buffer = context->CreateCommandBuffer();
468 auto pass = cmd_buffer->CreateComputePass();
469 ASSERT_TRUE(pass && pass->IsValid());
471 static constexpr size_t kCount = 5;
473 pass->SetPipeline(compute_pipeline);
475 CS::Info
info{.count = kCount};
476 CS::Input0<kCount> input_0;
477 CS::Input1<kCount> input_1;
478 for (
size_t i = 0;
i < kCount;
i++) {
479 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
480 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
483 input_0.fixed_array[1] =
IPoint32(2, 2);
485 input_0.some_int = 5;
486 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
488 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
489 context,
"Output Buffer");
491 CS::BindInfo(*pass, host_buffer->EmplaceUniform(
info));
492 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
493 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
494 CS::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer));
498 EXPECT_FALSE(pass->Compute(
ISize(0, 1)).
ok());
499 pass->EncodeCommands();
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
for(const auto glyph :glyphs)
static sk_sp< Effect > Create()
static bool ok(int result)
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator)
Render passes encode render commands directed as one specific render target into an underlying comman...
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
SK_API GrDirectContext * GetContext(const SkImage *src)
TEST_P(ComputeTest, ReturnsEarlyWhenAnyGridDimensionIsZero)
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
INSTANTIATE_COMPUTE_SUITE(ComputeTest)
TPoint< int32_t > IPoint32
TPoint< uint32_t > UintPoint32
An optional (but highly recommended) utility for creating pipelines from reflected shader information...