52 using CS = SampleComputeShader;
54 auto host_buffer = CreateHostBufferFromContext(
context);
56 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
60 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
61 ASSERT_TRUE(pipeline_desc.has_value());
62 auto compute_pipeline =
63 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
64 ASSERT_TRUE(compute_pipeline);
66 auto cmd_buffer =
context->CreateCommandBuffer();
67 auto pass = cmd_buffer->CreateComputePass();
68 ASSERT_TRUE(pass && pass->IsValid());
70 static constexpr size_t kCount = 5;
72 pass->SetPipeline(compute_pipeline);
74 CS::Info info{.count = kCount};
75 CS::Input0<kCount> input_0;
76 CS::Input1<kCount> input_1;
77 for (
size_t i = 0;
i < kCount;
i++) {
78 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
79 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
82 input_0.fixed_array[1] =
IPoint32(2, 2);
85 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
87 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
90 CS::BindInfo(*pass, host_buffer->EmplaceUniform(info));
91 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
92 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
96 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
98 ASSERT_TRUE(pass->EncodeCommands());
105 [&latch, output_buffer, &input_0,
107 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
109 auto view = DeviceBuffer::AsBufferView(output_buffer);
110 EXPECT_EQ(view.GetRange().length, sizeof(CS::Output<kCount>));
112 CS::Output<kCount>* output =
113 reinterpret_cast<CS::Output<kCount>*>(
114 output_buffer->OnGetContents());
116 for (size_t i = 0; i < kCount; i++) {
117 Vector4 vector = output->elements[i];
118 Vector4 computed = input_0.elements[i] * input_1.elements[i];
120 Vector4(computed.x + 2 + input_1.some_struct.i,
121 computed.y + 3 + input_1.some_struct.vf.x,
122 computed.z + 5 + input_1.some_struct.vf.y,
133 using CS = PrefixSumTestComputeShader;
135 auto host_buffer = CreateHostBufferFromContext(
context);
137 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
141 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
142 ASSERT_TRUE(pipeline_desc.has_value());
143 auto compute_pipeline =
144 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
145 ASSERT_TRUE(compute_pipeline);
147 auto cmd_buffer =
context->CreateCommandBuffer();
148 auto pass = cmd_buffer->CreateComputePass();
149 ASSERT_TRUE(pass && pass->IsValid());
151 static constexpr size_t kCount = 5;
153 pass->SetPipeline(compute_pipeline);
155 CS::InputData<kCount> input_data;
156 input_data.count = kCount;
157 for (
size_t i = 0;
i < kCount;
i++) {
158 input_data.data[
i] = 1 +
i;
161 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
164 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
169 ASSERT_TRUE(pass->Compute({1, 1, 1}).ok());
170 ASSERT_TRUE(pass->EncodeCommands());
175 ->Submit({cmd_buffer},
177 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
179 auto view = DeviceBuffer::AsBufferView(output_buffer);
180 EXPECT_EQ(view.GetRange().length,
181 sizeof(CS::OutputData<kCount>));
183 CS::OutputData<kCount>* output =
184 reinterpret_cast<CS::OutputData<kCount>*>(
185 output_buffer->OnGetContents());
188 constexpr uint32_t expected[kCount] = {1, 3, 6, 10, 15};
189 for (
size_t i = 0;
i < kCount;
i++) {
190 auto computed_sum = output->data[
i];
191 EXPECT_EQ(computed_sum, expected[
i]);
201 using CS = ThreadgroupSizingTestComputeShader;
204 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
208 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
209 ASSERT_TRUE(pipeline_desc.has_value());
210 auto compute_pipeline =
211 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
212 ASSERT_TRUE(compute_pipeline);
214 auto cmd_buffer =
context->CreateCommandBuffer();
215 auto pass = cmd_buffer->CreateComputePass();
216 ASSERT_TRUE(pass && pass->IsValid());
218 static constexpr size_t kCount = 2048;
220 pass->SetPipeline(compute_pipeline);
222 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
225 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
228 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
230 ASSERT_TRUE(pass->EncodeCommands());
235 ->Submit({cmd_buffer},
237 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
239 auto view = DeviceBuffer::AsBufferView(output_buffer);
240 EXPECT_EQ(view.GetRange().length,
241 sizeof(CS::OutputData<kCount>));
243 CS::OutputData<kCount>* output =
244 reinterpret_cast<CS::OutputData<kCount>*>(
245 output_buffer->OnGetContents());
247 EXPECT_EQ(output->data[kCount - 1], kCount - 1);
256 using CS = Compute3dTestComputeShader;
259 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
262 auto pipeline_desc = PipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
263 ASSERT_TRUE(pipeline_desc.has_value());
264 auto compute_pipeline =
265 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
266 ASSERT_TRUE(compute_pipeline);
268 auto cmd_buffer =
context->CreateCommandBuffer();
269 auto pass = cmd_buffer->CreateComputePass();
270 ASSERT_TRUE(pass && pass->IsValid());
275 static_assert(CS::kWorkgroupSize[0] == 2 && CS::kWorkgroupSize[1] == 3 &&
276 CS::kWorkgroupSize[2] == 4);
277 constexpr std::array<uint32_t, 3> kWorkgroups = {3, 2, 1};
278 constexpr uint32_t kWidth = kWorkgroups[0] * CS::kWorkgroupSize[0];
279 constexpr uint32_t kHeight = kWorkgroups[1] * CS::kWorkgroupSize[1];
280 constexpr uint32_t kDepth = kWorkgroups[2] * CS::kWorkgroupSize[2];
281 constexpr size_t kCount = kWidth * kHeight * kDepth;
283 pass->SetPipeline(compute_pipeline);
285 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
287 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
289 ASSERT_TRUE(pass->Compute(kWorkgroups).ok());
290 ASSERT_TRUE(pass->EncodeCommands());
295 ->Submit({cmd_buffer},
297 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
299 CS::OutputData<kCount>* output =
300 reinterpret_cast<CS::OutputData<kCount>*>(
301 output_buffer->OnGetContents());
303 for (uint32_t i = 0; i < kCount; i++) {
304 EXPECT_EQ(output->data[i], i);
314 using CS = PrefixSumTestComputeShader;
317 auto host_buffer = CreateHostBufferFromContext(
context);
320 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
325 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
326 auto compute_pipeline =
327 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
329 auto cmd_buffer =
context->CreateCommandBuffer();
330 auto pass = cmd_buffer->CreateComputePass();
332 static constexpr size_t kCount = 1023;
334 pass->SetPipeline(compute_pipeline);
336 CS::InputData<kCount> input_data;
337 input_data.count = kCount;
338 for (
size_t i = 0;
i < kCount;
i++) {
339 input_data.data[
i] = 1 +
i;
342 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
345 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
346 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
349 pass->Compute({1, 1, 1});
350 pass->EncodeCommands();
351 host_buffer->Reset();
352 return context->GetCommandQueue()->Submit({cmd_buffer}).ok();
354 ASSERT_TRUE(OpenPlaygroundHere(
callback));
358 using CS1 = Stage1ComputeShader;
360 using CS2 = Stage2ComputeShader;
364 auto host_buffer = CreateHostBufferFromContext(
context);
366 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
368 auto pipeline_desc_1 =
369 Stage1PipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
370 ASSERT_TRUE(pipeline_desc_1.has_value());
371 auto compute_pipeline_1 =
372 context->GetPipelineLibrary()->GetPipeline(pipeline_desc_1).Get();
373 ASSERT_TRUE(compute_pipeline_1);
375 auto pipeline_desc_2 =
376 Stage2PipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
377 ASSERT_TRUE(pipeline_desc_2.has_value());
378 auto compute_pipeline_2 =
379 context->GetPipelineLibrary()->GetPipeline(pipeline_desc_2).Get();
380 ASSERT_TRUE(compute_pipeline_2);
382 auto cmd_buffer =
context->CreateCommandBuffer();
383 auto pass = cmd_buffer->CreateComputePass();
384 ASSERT_TRUE(pass && pass->IsValid());
386 static constexpr size_t kCount1 = 5;
387 static constexpr size_t kCount2 =
kCount1 * 2;
389 CS1::Input<kCount1> input_1;
392 input_1.elements[
i] =
i;
395 CS2::Input<kCount2> input_2;
396 input_2.count = kCount2;
397 for (
size_t i = 0;
i < kCount2;
i++) {
398 input_2.elements[
i] =
i;
401 auto output_buffer_1 = CreateHostVisibleDeviceBuffer<CS1::Output<kCount2>>(
402 context,
"Output Buffer Stage 1");
403 auto output_buffer_2 = CreateHostVisibleDeviceBuffer<CS2::Output<kCount2>>(
404 context,
"Output Buffer Stage 2");
407 pass->SetPipeline(compute_pipeline_1);
409 CS1::BindInput(*pass, host_buffer->EmplaceStorageBuffer(input_1));
410 CS1::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
413 pass->Compute({WorkgroupCount(kCount1, CS1::kWorkgroupSize[0]), 1, 1})
415 pass->AddBufferMemoryBarrier();
419 pass->SetPipeline(compute_pipeline_2);
421 CS1::BindInput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
422 CS2::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_2));
424 pass->Compute({WorkgroupCount(kCount2, CS2::kWorkgroupSize[0]), 1, 1})
428 ASSERT_TRUE(pass->EncodeCommands());
433 ->Submit({cmd_buffer},
434 [&latch, &output_buffer_1,
436 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
438 CS1::Output<kCount2>* output_1 =
439 reinterpret_cast<CS1::Output<kCount2>*>(
440 output_buffer_1->OnGetContents());
441 EXPECT_TRUE(output_1);
442 EXPECT_EQ(output_1->count, 10u);
445 ::testing::ElementsAre(0, 0, 2, 3, 4, 6, 6, 9, 8, 12));
447 CS2::Output<kCount2>* output_2 =
448 reinterpret_cast<CS2::Output<kCount2>*>(
449 output_buffer_2->OnGetContents());
450 EXPECT_TRUE(output_2);
451 EXPECT_EQ(output_2->count, 10u);
452 EXPECT_THAT(output_2->elements,
453 ::testing::ElementsAre(0, 0, 4, 6, 8, 12, 12,
464 using CS = SampleComputeShader;
466 auto host_buffer = CreateHostBufferFromContext(
context);
468 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
472 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
473 ASSERT_TRUE(pipeline_desc.has_value());
474 auto compute_pipeline =
475 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
476 ASSERT_TRUE(compute_pipeline);
478 auto cmd_buffer =
context->CreateCommandBuffer();
479 auto pass = cmd_buffer->CreateComputePass();
480 ASSERT_TRUE(pass && pass->IsValid());
482 static constexpr size_t kCount = 5;
484 pass->SetPipeline(compute_pipeline);
486 CS::Info info{.count = kCount};
487 CS::Input0<kCount> input_0;
488 CS::Input1<kCount> input_1;
489 for (
size_t i = 0;
i < kCount;
i++) {
490 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
491 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
494 input_0.fixed_array[1] =
IPoint32(2, 2);
496 input_0.some_int = 5;
497 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
499 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
502 CS::BindInfo(*pass, host_buffer->EmplaceUniform(info));
503 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
504 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
505 CS::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer));
508 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
510 ASSERT_TRUE(pass->EncodeCommands());
517 [&latch, output_buffer, &input_0,
519 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
521 auto view = DeviceBuffer::AsBufferView(output_buffer);
522 EXPECT_EQ(view.GetRange().length, sizeof(CS::Output<kCount>));
524 CS::Output<kCount>* output =
525 reinterpret_cast<CS::Output<kCount>*>(
526 output_buffer->OnGetContents());
528 for (size_t i = 0; i < kCount; i++) {
529 Vector4 vector = output->elements[i];
530 Vector4 computed = input_0.elements[i] * input_1.elements[i];
532 Vector4(computed.x + 2 + input_1.some_struct.i,
533 computed.y + 3 + input_1.some_struct.vf.x,
534 computed.z + 5 + input_1.some_struct.vf.y,
545 using CS = SampleComputeShader;
547 auto host_buffer = CreateHostBufferFromContext(
context);
549 ASSERT_TRUE(
context->GetCapabilities()->SupportsCompute());
553 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*
context);
554 ASSERT_TRUE(pipeline_desc.has_value());
555 auto compute_pipeline =
556 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
557 ASSERT_TRUE(compute_pipeline);
559 auto cmd_buffer =
context->CreateCommandBuffer();
560 auto pass = cmd_buffer->CreateComputePass();
561 ASSERT_TRUE(pass && pass->IsValid());
563 static constexpr size_t kCount = 5;
565 pass->SetPipeline(compute_pipeline);
567 CS::Info info{.count = kCount};
568 CS::Input0<kCount> input_0;
569 CS::Input1<kCount> input_1;
570 for (
size_t i = 0;
i < kCount;
i++) {
571 input_0.elements[
i] =
Vector4(2.0 +
i, 3.0 +
i, 4.0 +
i, 5.0 *
i);
572 input_1.elements[
i] =
Vector4(6.0, 7.0, 8.0, 9.0);
575 input_0.fixed_array[1] =
IPoint32(2, 2);
577 input_0.some_int = 5;
578 input_1.some_struct = CS::SomeStruct{.vf =
Point(3, 4), .i = 42};
580 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
583 CS::BindInfo(*pass, host_buffer->EmplaceUniform(info));
584 CS::BindInput0(*pass, host_buffer->EmplaceStorageBuffer(input_0));
585 CS::BindInput1(*pass, host_buffer->EmplaceStorageBuffer(input_1));
586 CS::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer));
590 auto status = pass->Compute({0, 1, 1});
591 EXPECT_FALSE(status.ok());
593 pass->EncodeCommands();