Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
compute_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
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"
14#include "impeller/renderer/compute_3d_test.comp.h"
17#include "impeller/renderer/prefix_sum_test.comp.h"
18#include "impeller/renderer/threadgroup_sizing_test.comp.h"
19
20namespace {
21std::shared_ptr<impeller::HostBuffer> CreateHostBufferFromContext(
22 const std::shared_ptr<impeller::Context>& context) {
24 context->GetResourceAllocator(), context->GetIdleWaiter(),
25 context->GetCapabilities()->GetMinimumUniformAlignment());
26}
27
28// The number of workgroups needed to cover `invocations` invocations given a
29// per-workgroup `local_size`. A `local_size` of 0 means the shader sizes its
30// workgroup with a specialization constant, in which case the caller should
31// dispatch an explicit count rather than derive one here.
32constexpr uint32_t WorkgroupCount(size_t invocations, uint32_t local_size) {
33 if (local_size == 0u) {
34 return 0u;
35 }
36 return static_cast<uint32_t>((invocations + local_size - 1) / local_size);
37}
38} // namespace
39
40namespace impeller {
41namespace testing {
44
45TEST_P(ComputeTest, CapabilitiesReportSupport) {
46 auto context = GetContext();
47 ASSERT_TRUE(context);
48 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
49}
50
51TEST_P(ComputeTest, CanCreateComputePass) {
52 using CS = SampleComputeShader;
53 auto context = GetContext();
54 auto host_buffer = CreateHostBufferFromContext(context);
55 ASSERT_TRUE(context);
56 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
57
58 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
59 auto pipeline_desc =
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);
65
66 auto cmd_buffer = context->CreateCommandBuffer();
67 auto pass = cmd_buffer->CreateComputePass();
68 ASSERT_TRUE(pass && pass->IsValid());
69
70 static constexpr size_t kCount = 5;
71
72 pass->SetPipeline(compute_pipeline);
73
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);
80 }
81
82 input_0.fixed_array[1] = IPoint32(2, 2);
83 input_1.fixed_array[0] = UintPoint32(3, 3);
84 input_0.some_int = 5;
85 input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
86
87 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
88 context, "Output Buffer");
89
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));
93 CS::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer));
94
95 ASSERT_TRUE(
96 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
97 .ok());
98 ASSERT_TRUE(pass->EncodeCommands());
99
101 ASSERT_TRUE(
102 context->GetCommandQueue()
103 ->Submit(
104 {cmd_buffer},
105 [&latch, output_buffer, &input_0,
106 &input_1](CommandBuffer::Status status) {
107 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
108
109 auto view = DeviceBuffer::AsBufferView(output_buffer);
110 EXPECT_EQ(view.GetRange().length, sizeof(CS::Output<kCount>));
111
112 CS::Output<kCount>* output =
113 reinterpret_cast<CS::Output<kCount>*>(
114 output_buffer->OnGetContents());
115 EXPECT_TRUE(output);
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];
119 EXPECT_EQ(vector,
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,
123 computed.w));
124 }
125 latch.Signal();
126 })
127 .ok());
128
129 latch.Wait();
130}
131
132TEST_P(ComputeTest, CanComputePrefixSum) {
133 using CS = PrefixSumTestComputeShader;
134 auto context = GetContext();
135 auto host_buffer = CreateHostBufferFromContext(context);
136 ASSERT_TRUE(context);
137 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
138
139 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
140 auto pipeline_desc =
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);
146
147 auto cmd_buffer = context->CreateCommandBuffer();
148 auto pass = cmd_buffer->CreateComputePass();
149 ASSERT_TRUE(pass && pass->IsValid());
150
151 static constexpr size_t kCount = 5;
152
153 pass->SetPipeline(compute_pipeline);
154
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;
159 }
160
161 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
162 context, "Output Buffer");
163
164 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
165 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
166
167 // The prefix sum is computed within a single workgroup whose size is sized to
168 // the device (a specialization constant), so dispatch exactly one.
169 ASSERT_TRUE(pass->Compute({1, 1, 1}).ok());
170 ASSERT_TRUE(pass->EncodeCommands());
171
173 ASSERT_TRUE(
174 context->GetCommandQueue()
175 ->Submit({cmd_buffer},
176 [&latch, output_buffer](CommandBuffer::Status status) {
177 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
178
179 auto view = DeviceBuffer::AsBufferView(output_buffer);
180 EXPECT_EQ(view.GetRange().length,
181 sizeof(CS::OutputData<kCount>));
182
183 CS::OutputData<kCount>* output =
184 reinterpret_cast<CS::OutputData<kCount>*>(
185 output_buffer->OnGetContents());
186 EXPECT_TRUE(output);
187
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]);
192 }
193 latch.Signal();
194 })
195 .ok());
196
197 latch.Wait();
198}
199
200TEST_P(ComputeTest, 1DThreadgroupSizingIsCorrect) {
201 using CS = ThreadgroupSizingTestComputeShader;
202 auto context = GetContext();
203 ASSERT_TRUE(context);
204 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
205
206 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
207 auto pipeline_desc =
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);
213
214 auto cmd_buffer = context->CreateCommandBuffer();
215 auto pass = cmd_buffer->CreateComputePass();
216 ASSERT_TRUE(pass && pass->IsValid());
217
218 static constexpr size_t kCount = 2048;
219
220 pass->SetPipeline(compute_pipeline);
221
222 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
223 context, "Output Buffer");
224
225 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
226
227 ASSERT_TRUE(
228 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
229 .ok());
230 ASSERT_TRUE(pass->EncodeCommands());
231
233 ASSERT_TRUE(
234 context->GetCommandQueue()
235 ->Submit({cmd_buffer},
236 [&latch, output_buffer](CommandBuffer::Status status) {
237 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
238
239 auto view = DeviceBuffer::AsBufferView(output_buffer);
240 EXPECT_EQ(view.GetRange().length,
241 sizeof(CS::OutputData<kCount>));
242
243 CS::OutputData<kCount>* output =
244 reinterpret_cast<CS::OutputData<kCount>*>(
245 output_buffer->OnGetContents());
246 EXPECT_TRUE(output);
247 EXPECT_EQ(output->data[kCount - 1], kCount - 1);
248 latch.Signal();
249 })
250 .ok());
251
252 latch.Wait();
253}
254
255TEST_P(ComputeTest, 3DWorkgroupDispatchIsCorrect) {
256 using CS = Compute3dTestComputeShader;
257 auto context = GetContext();
258 ASSERT_TRUE(context);
259 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
260
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);
267
268 auto cmd_buffer = context->CreateCommandBuffer();
269 auto pass = cmd_buffer->CreateComputePass();
270 ASSERT_TRUE(pass && pass->IsValid());
271
272 // The shader's local size is (2, 3, 4). Dispatching (3, 2, 1) workgroups
273 // covers a (6, 6, 4) invocation grid, which exercises all three dimensions
274 // and confirms the reflected local size is honored on every axis.
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;
282
283 pass->SetPipeline(compute_pipeline);
284
285 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
286 context, "Output Buffer");
287 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
288
289 ASSERT_TRUE(pass->Compute(kWorkgroups).ok());
290 ASSERT_TRUE(pass->EncodeCommands());
291
293 ASSERT_TRUE(
294 context->GetCommandQueue()
295 ->Submit({cmd_buffer},
296 [&latch, output_buffer](CommandBuffer::Status status) {
297 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
298
299 CS::OutputData<kCount>* output =
300 reinterpret_cast<CS::OutputData<kCount>*>(
301 output_buffer->OnGetContents());
302 EXPECT_TRUE(output);
303 for (uint32_t i = 0; i < kCount; i++) {
304 EXPECT_EQ(output->data[i], i);
305 }
306 latch.Signal();
307 })
308 .ok());
309
310 latch.Wait();
311}
312
313TEST_P(ComputeTest, CanComputePrefixSumLargeInteractive) {
314 using CS = PrefixSumTestComputeShader;
315
316 auto context = GetContext();
317 auto host_buffer = CreateHostBufferFromContext(context);
318
319 ASSERT_TRUE(context);
320 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
321
322 auto callback = [&](RenderPass& render_pass) -> bool {
323 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
324 auto pipeline_desc =
325 SamplePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
326 auto compute_pipeline =
327 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
328
329 auto cmd_buffer = context->CreateCommandBuffer();
330 auto pass = cmd_buffer->CreateComputePass();
331
332 static constexpr size_t kCount = 1023;
333
334 pass->SetPipeline(compute_pipeline);
335
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;
340 }
341
342 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::OutputData<kCount>>(
343 context, "Output Buffer");
344
345 CS::BindInputData(*pass, host_buffer->EmplaceStorageBuffer(input_data));
346 CS::BindOutputData(*pass, DeviceBuffer::AsBufferView(output_buffer));
347
348 // Single workgroup; see CanComputePrefixSum.
349 pass->Compute({1, 1, 1});
350 pass->EncodeCommands();
351 host_buffer->Reset();
352 return context->GetCommandQueue()->Submit({cmd_buffer}).ok();
353 };
354 ASSERT_TRUE(OpenPlaygroundHere(callback));
355}
356
357TEST_P(ComputeTest, MultiStageInputAndOutput) {
358 using CS1 = Stage1ComputeShader;
359 using Stage1PipelineBuilder = ComputePipelineBuilder<CS1>;
360 using CS2 = Stage2ComputeShader;
361 using Stage2PipelineBuilder = ComputePipelineBuilder<CS2>;
362
363 auto context = GetContext();
364 auto host_buffer = CreateHostBufferFromContext(context);
365 ASSERT_TRUE(context);
366 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
367
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);
374
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);
381
382 auto cmd_buffer = context->CreateCommandBuffer();
383 auto pass = cmd_buffer->CreateComputePass();
384 ASSERT_TRUE(pass && pass->IsValid());
385
386 static constexpr size_t kCount1 = 5;
387 static constexpr size_t kCount2 = kCount1 * 2;
388
389 CS1::Input<kCount1> input_1;
390 input_1.count = kCount1;
391 for (size_t i = 0; i < kCount1; i++) {
392 input_1.elements[i] = i;
393 }
394
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;
399 }
400
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");
405
406 {
407 pass->SetPipeline(compute_pipeline_1);
408
409 CS1::BindInput(*pass, host_buffer->EmplaceStorageBuffer(input_1));
410 CS1::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
411
412 ASSERT_TRUE(
413 pass->Compute({WorkgroupCount(kCount1, CS1::kWorkgroupSize[0]), 1, 1})
414 .ok());
415 pass->AddBufferMemoryBarrier();
416 }
417
418 {
419 pass->SetPipeline(compute_pipeline_2);
420
421 CS1::BindInput(*pass, DeviceBuffer::AsBufferView(output_buffer_1));
422 CS2::BindOutput(*pass, DeviceBuffer::AsBufferView(output_buffer_2));
423 ASSERT_TRUE(
424 pass->Compute({WorkgroupCount(kCount2, CS2::kWorkgroupSize[0]), 1, 1})
425 .ok());
426 }
427
428 ASSERT_TRUE(pass->EncodeCommands());
429
431 ASSERT_TRUE(
432 context->GetCommandQueue()
433 ->Submit({cmd_buffer},
434 [&latch, &output_buffer_1,
435 &output_buffer_2](CommandBuffer::Status status) {
436 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
437
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);
443 EXPECT_THAT(
444 output_1->elements,
445 ::testing::ElementsAre(0, 0, 2, 3, 4, 6, 6, 9, 8, 12));
446
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,
454 18, 16, 24));
455
456 latch.Signal();
457 })
458 .ok());
459
460 latch.Wait();
461}
462
463TEST_P(ComputeTest, CanCompute1DimensionalData) {
464 using CS = SampleComputeShader;
465 auto context = GetContext();
466 auto host_buffer = CreateHostBufferFromContext(context);
467 ASSERT_TRUE(context);
468 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
469
470 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
471 auto pipeline_desc =
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);
477
478 auto cmd_buffer = context->CreateCommandBuffer();
479 auto pass = cmd_buffer->CreateComputePass();
480 ASSERT_TRUE(pass && pass->IsValid());
481
482 static constexpr size_t kCount = 5;
483
484 pass->SetPipeline(compute_pipeline);
485
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);
492 }
493
494 input_0.fixed_array[1] = IPoint32(2, 2);
495 input_1.fixed_array[0] = UintPoint32(3, 3);
496 input_0.some_int = 5;
497 input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
498
499 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
500 context, "Output Buffer");
501
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));
506
507 ASSERT_TRUE(
508 pass->Compute({WorkgroupCount(kCount, CS::kWorkgroupSize[0]), 1, 1})
509 .ok());
510 ASSERT_TRUE(pass->EncodeCommands());
511
513 ASSERT_TRUE(
514 context->GetCommandQueue()
515 ->Submit(
516 {cmd_buffer},
517 [&latch, output_buffer, &input_0,
518 &input_1](CommandBuffer::Status status) {
519 EXPECT_EQ(status, CommandBuffer::Status::kCompleted);
520
521 auto view = DeviceBuffer::AsBufferView(output_buffer);
522 EXPECT_EQ(view.GetRange().length, sizeof(CS::Output<kCount>));
523
524 CS::Output<kCount>* output =
525 reinterpret_cast<CS::Output<kCount>*>(
526 output_buffer->OnGetContents());
527 EXPECT_TRUE(output);
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];
531 EXPECT_EQ(vector,
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,
535 computed.w));
536 }
537 latch.Signal();
538 })
539 .ok());
540
541 latch.Wait();
542}
543
544TEST_P(ComputeTest, ReturnsEarlyWhenAnyGridDimensionIsZero) {
545 using CS = SampleComputeShader;
546 auto context = GetContext();
547 auto host_buffer = CreateHostBufferFromContext(context);
548 ASSERT_TRUE(context);
549 ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
550
551 using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
552 auto pipeline_desc =
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);
558
559 auto cmd_buffer = context->CreateCommandBuffer();
560 auto pass = cmd_buffer->CreateComputePass();
561 ASSERT_TRUE(pass && pass->IsValid());
562
563 static constexpr size_t kCount = 5;
564
565 pass->SetPipeline(compute_pipeline);
566
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);
573 }
574
575 input_0.fixed_array[1] = IPoint32(2, 2);
576 input_1.fixed_array[0] = UintPoint32(3, 3);
577 input_0.some_int = 5;
578 input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
579
580 auto output_buffer = CreateHostVisibleDeviceBuffer<CS::Output<kCount>>(
581 context, "Output Buffer");
582
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));
587
588 // Intentionally making the workgroup count zero in one dimension. No GPU will
589 // tolerate this.
590 auto status = pass->Compute({0, 1, 1});
591 EXPECT_FALSE(status.ok());
592 EXPECT_EQ(status.code(), fml::StatusCode::kCancelled);
593 pass->EncodeCommands();
594}
595
596} // namespace testing
597} // namespace impeller
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, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment)
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition render_pass.h:30
#define INSTANTIATE_COMPUTE_SUITE(playground)
FlutterDesktopBinaryReply callback
TEST_P(AiksTest, DrawAtlasNoColor)
TPoint< int32_t > IPoint32
Definition point.h:428
TPoint< uint32_t > UintPoint32
Definition point.h:429
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
An optional (but highly recommended) utility for creating pipelines from reflected shader information...