| Flutter Impeller |

renderer_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
5 #include "flutter/fml/logging.h"
6 #include "impeller/core/device_buffer_descriptor.h"
7 #include "impeller/core/formats.h"
8 #include "impeller/core/host_buffer.h"
9 #include "impeller/core/sampler_descriptor.h"
10 #include "impeller/fixtures/array.frag.h"
11 #include "impeller/fixtures/array.vert.h"
12 #include "impeller/fixtures/box_fade.frag.h"
13 #include "impeller/fixtures/box_fade.vert.h"
14 #include "impeller/fixtures/colors.frag.h"
15 #include "impeller/fixtures/colors.vert.h"
16 #include "impeller/fixtures/impeller.frag.h"
17 #include "impeller/fixtures/impeller.vert.h"
18 #include "impeller/fixtures/inactive_uniforms.frag.h"
19 #include "impeller/fixtures/inactive_uniforms.vert.h"
20 #include "impeller/fixtures/instanced_draw.frag.h"
21 #include "impeller/fixtures/instanced_draw.vert.h"
22 #include "impeller/fixtures/mipmaps.frag.h"
23 #include "impeller/fixtures/mipmaps.vert.h"
24 #include "impeller/fixtures/sepia.frag.h"
25 #include "impeller/fixtures/sepia.vert.h"
26 #include "impeller/fixtures/swizzle.frag.h"
27 #include "impeller/fixtures/test_texture.frag.h"
28 #include "impeller/fixtures/test_texture.vert.h"
29 #include "impeller/fixtures/texture.frag.h"
30 #include "impeller/fixtures/texture.vert.h"
31 #include "impeller/geometry/path_builder.h"
32 #include "impeller/playground/playground_test.h"
33 #include "impeller/renderer/command.h"
34 #include "impeller/renderer/command_buffer.h"
35 #include "impeller/renderer/pipeline_builder.h"
36 #include "impeller/renderer/pipeline_library.h"
37 #include "impeller/renderer/render_pass.h"
38 #include "impeller/renderer/render_target.h"
39 #include "impeller/renderer/renderer.h"
40 #include "impeller/renderer/vertex_buffer_builder.h"
41 #include "impeller/tessellator/tessellator.h"
42 #include "third_party/imgui/imgui.h"
43
44 // TODO(zanderso): https://github.com/flutter/flutter/issues/127701
45 // NOLINTBEGIN(bugprone-unchecked-optional-access)
46
47 namespace impeller {
48 namespace testing {
49
50 using RendererTest = PlaygroundTest;
51 INSTANTIATE_PLAYGROUND_SUITE(RendererTest);
52
53 TEST_P(RendererTest, CanCreateBoxPrimitive) {
54 using VS = BoxFadeVertexShader;
55 using FS = BoxFadeFragmentShader;
56 auto context = GetContext();
57 ASSERT_TRUE(context);
58 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
59 auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
60 ASSERT_TRUE(desc.has_value());
61 desc->SetSampleCount(SampleCount::kCount4);
62 desc->SetStencilAttachmentDescriptors(std::nullopt);
63
64 // Vertex buffer.
65 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
66 vertex_builder.SetLabel("Box");
67 vertex_builder.AddVertices({
68 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
69 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
70 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
71 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
72 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
73 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
74 });
75 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
76 auto boston = CreateTextureForFixture("boston.jpg");
77 ASSERT_TRUE(bridge && boston);
78 const std::unique_ptr<const Sampler>& sampler =
79 context->GetSamplerLibrary()->GetSampler({});
80 ASSERT_TRUE(sampler);
81
82 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
83 SinglePassCallback callback = [&](RenderPass& pass) {
84 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
85 static bool wireframe;
86 ImGui::Checkbox("Wireframe", &wireframe);
87 ImGui::End();
88
89 desc->SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill);
90 auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
91
92 assert(pipeline && pipeline->IsValid());
93
94 pass.SetCommandLabel("Box");
95 pass.SetPipeline(pipeline);
96 pass.SetVertexBuffer(
97 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()));
98
99 VS::UniformBuffer uniforms;
100 EXPECT_EQ(pass.GetOrthographicTransform(),
101 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
102 uniforms.mvp =
103 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
104 VS::BindUniformBuffer(pass, host_buffer->EmplaceUniform(uniforms));
105
106 FS::FrameInfo frame_info;
107 frame_info.current_time = GetSecondsElapsed();
108 frame_info.cursor_position = GetCursorPosition();
109 frame_info.window_size.x = GetWindowSize().width;
110 frame_info.window_size.y = GetWindowSize().height;
111
112 FS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
113 FS::BindContents1(pass, boston, sampler);
114 FS::BindContents2(pass, bridge, sampler);
115
116 host_buffer->Reset();
117 return pass.Draw().ok();
118 };
119 OpenPlaygroundHere(callback);
120 }
121
122 TEST_P(RendererTest, CanRenderPerspectiveCube) {
123 using VS = ColorsVertexShader;
124 using FS = ColorsFragmentShader;
125 auto context = GetContext();
126 ASSERT_TRUE(context);
127 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
128 ASSERT_TRUE(desc.has_value());
129 desc->SetCullMode(CullMode::kBackFace);
130 desc->SetWindingOrder(WindingOrder::kCounterClockwise);
131 desc->SetSampleCount(SampleCount::kCount4);
132 desc->SetStencilAttachmentDescriptors(std::nullopt);
133 auto pipeline =
134 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
135 ASSERT_TRUE(pipeline);
136
137 struct Cube {
138 VS::PerVertexData vertices[8] = {
139 // -Z
140 {{-1, -1, -1}, Color::Red()},
141 {{1, -1, -1}, Color::Yellow()},
142 {{1, 1, -1}, Color::Green()},
143 {{-1, 1, -1}, Color::Blue()},
144 // +Z
145 {{-1, -1, 1}, Color::Green()},
146 {{1, -1, 1}, Color::Blue()},
147 {{1, 1, 1}, Color::Red()},
148 {{-1, 1, 1}, Color::Yellow()},
149 };
150 uint16_t indices[36] = {
151 1, 5, 2, 2, 5, 6, // +X
152 4, 0, 7, 7, 0, 3, // -X
153 4, 5, 0, 0, 5, 1, // +Y
154 3, 2, 7, 7, 2, 6, // -Y
155 5, 4, 6, 6, 4, 7, // +Z
156 0, 1, 3, 3, 1, 2, // -Z
157 };
158 } cube;
159
160 VertexBuffer vertex_buffer;
161 {
162 auto device_buffer = context->GetResourceAllocator()->CreateBufferWithCopy(
163 reinterpret_cast<uint8_t*>(&cube), sizeof(cube));
164 vertex_buffer.vertex_buffer = {
165 .buffer = device_buffer,
166 .range = Range(offsetof(Cube, vertices), sizeof(Cube::vertices))};
167 vertex_buffer.index_buffer = {
168 .buffer = device_buffer,
169 .range = Range(offsetof(Cube, indices), sizeof(Cube::indices))};
170 vertex_buffer.vertex_count = 36;
171 vertex_buffer.index_type = IndexType::k16bit;
172 }
173
174 const std::unique_ptr<const Sampler>& sampler =
175 context->GetSamplerLibrary()->GetSampler({});
176 ASSERT_TRUE(sampler);
177
178 Vector3 euler_angles;
179 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
180 SinglePassCallback callback = [&](RenderPass& pass) {
181 static Degrees fov_y(60);
182 static Scalar distance = 10;
183
184 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
185 ImGui::SliderFloat("Field of view", &fov_y.degrees, 0, 180);
186 ImGui::SliderFloat("Camera distance", &distance, 0, 30);
187 ImGui::End();
188
189 pass.SetCommandLabel("Perspective Cube");
190 pass.SetPipeline(pipeline);
191 pass.SetVertexBuffer(vertex_buffer);
192
193 VS::UniformBuffer uniforms;
194 Scalar time = GetSecondsElapsed();
195 euler_angles = Vector3(0.19 * time, 0.7 * time, 0.43 * time);
196
197 uniforms.mvp =
198 Matrix::MakePerspective(fov_y, pass.GetRenderTargetSize(), 0, 10) *
199 Matrix::MakeTranslation({0, 0, distance}) *
200 Matrix::MakeRotationX(Radians(euler_angles.x)) *
201 Matrix::MakeRotationY(Radians(euler_angles.y)) *
202 Matrix::MakeRotationZ(Radians(euler_angles.z));
203 VS::BindUniformBuffer(pass, host_buffer->EmplaceUniform(uniforms));
204
205 host_buffer->Reset();
206 return pass.Draw().ok();
207 };
208 OpenPlaygroundHere(callback);
209 }
210
211 TEST_P(RendererTest, CanRenderMultiplePrimitives) {
212 using VS = BoxFadeVertexShader;
213 using FS = BoxFadeFragmentShader;
214 auto context = GetContext();
215 ASSERT_TRUE(context);
216 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
217 auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
218 ASSERT_TRUE(desc.has_value());
219 desc->SetSampleCount(SampleCount::kCount4);
220 desc->SetStencilAttachmentDescriptors(std::nullopt);
221 auto box_pipeline =
222 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
223 ASSERT_TRUE(box_pipeline);
224
225 // Vertex buffer.
226 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
227 vertex_builder.SetLabel("Box");
228 vertex_builder.AddVertices({
229 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
230 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
231 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
232 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
233 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
234 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
235 });
236 auto vertex_buffer =
237 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
238 ASSERT_TRUE(vertex_buffer);
239
240 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
241 auto boston = CreateTextureForFixture("boston.jpg");
242 ASSERT_TRUE(bridge && boston);
243 const std::unique_ptr<const Sampler>& sampler =
244 context->GetSamplerLibrary()->GetSampler({});
245 ASSERT_TRUE(sampler);
246
247 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
248 SinglePassCallback callback = [&](RenderPass& pass) {
249 for (size_t i = 0; i < 1; i++) {
250 for (size_t j = 0; j < 1; j++) {
251 pass.SetCommandLabel("Box");
252 pass.SetPipeline(box_pipeline);
253 pass.SetVertexBuffer(vertex_buffer);
254
255 FS::FrameInfo frame_info;
256 frame_info.current_time = GetSecondsElapsed();
257 frame_info.cursor_position = GetCursorPosition();
258 frame_info.window_size.x = GetWindowSize().width;
259 frame_info.window_size.y = GetWindowSize().height;
260
261 FS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
262 FS::BindContents1(pass, boston, sampler);
263 FS::BindContents2(pass, bridge, sampler);
264
265 VS::UniformBuffer uniforms;
266 EXPECT_EQ(pass.GetOrthographicTransform(),
267 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
268 uniforms.mvp = pass.GetOrthographicTransform() *
269 Matrix::MakeScale(GetContentScale()) *
270 Matrix::MakeTranslation({i * 50.0f, j * 50.0f, 0.0f});
271 VS::BindUniformBuffer(pass, host_buffer->EmplaceUniform(uniforms));
272 if (!pass.Draw().ok()) {
273 return false;
274 }
275 }
276 }
277
278 host_buffer->Reset();
279 return true;
280 };
281 OpenPlaygroundHere(callback);
282 }
283
284 TEST_P(RendererTest, CanRenderToTexture) {
285 using VS = BoxFadeVertexShader;
286 using FS = BoxFadeFragmentShader;
287 auto context = GetContext();
288 ASSERT_TRUE(context);
289 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
290 auto pipeline_desc =
291 BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
292 pipeline_desc->SetSampleCount(SampleCount::kCount1);
293 pipeline_desc->ClearDepthAttachment();
294 pipeline_desc->SetStencilPixelFormat(PixelFormat::kS8UInt);
295
296 ASSERT_TRUE(pipeline_desc.has_value());
297 auto box_pipeline =
298 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
299 ASSERT_TRUE(box_pipeline);
300 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
301
302 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
303 vertex_builder.SetLabel("Box");
304 vertex_builder.AddVertices({
305 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
306 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
307 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
308 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
309 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
310 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
311 });
312 auto vertex_buffer =
313 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
314 ASSERT_TRUE(vertex_buffer);
315
316 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
317 auto boston = CreateTextureForFixture("boston.jpg");
318 ASSERT_TRUE(bridge && boston);
319 const std::unique_ptr<const Sampler>& sampler =
320 context->GetSamplerLibrary()->GetSampler({});
321 ASSERT_TRUE(sampler);
322
323 std::shared_ptr<RenderPass> r2t_pass;
324 auto cmd_buffer = context->CreateCommandBuffer();
325 ASSERT_TRUE(cmd_buffer);
326 {
327 ColorAttachment color0;
328 color0.load_action = LoadAction::kClear;
329 color0.store_action = StoreAction::kStore;
330
331 TextureDescriptor texture_descriptor;
332 ASSERT_NE(pipeline_desc->GetColorAttachmentDescriptor(0u), nullptr);
333 texture_descriptor.format =
334 pipeline_desc->GetColorAttachmentDescriptor(0u)->format;
335 texture_descriptor.storage_mode = StorageMode::kHostVisible;
336 texture_descriptor.size = {400, 400};
337 texture_descriptor.mip_count = 1u;
338 texture_descriptor.usage = TextureUsage::kRenderTarget;
339
340 color0.texture =
341 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
342
343 ASSERT_TRUE(color0.IsValid());
344
345 color0.texture->SetLabel("r2t_target");
346
347 StencilAttachment stencil0;
348 stencil0.load_action = LoadAction::kClear;
349 stencil0.store_action = StoreAction::kDontCare;
350 TextureDescriptor stencil_texture_desc;
351 stencil_texture_desc.storage_mode = StorageMode::kDeviceTransient;
352 stencil_texture_desc.size = texture_descriptor.size;
353 stencil_texture_desc.format = PixelFormat::kS8UInt;
354 stencil_texture_desc.usage = TextureUsage::kRenderTarget;
355 stencil0.texture =
356 context->GetResourceAllocator()->CreateTexture(stencil_texture_desc);
357
358 RenderTarget r2t_desc;
359 r2t_desc.SetColorAttachment(color0, 0u);
360 r2t_desc.SetStencilAttachment(stencil0);
361 r2t_pass = cmd_buffer->CreateRenderPass(r2t_desc);
362 ASSERT_TRUE(r2t_pass && r2t_pass->IsValid());
363 }
364
365 r2t_pass->SetCommandLabel("Box");
366 r2t_pass->SetPipeline(box_pipeline);
367 r2t_pass->SetVertexBuffer(vertex_buffer);
368
369 FS::FrameInfo frame_info;
370 frame_info.current_time = GetSecondsElapsed();
371 frame_info.cursor_position = GetCursorPosition();
372 frame_info.window_size.x = GetWindowSize().width;
373 frame_info.window_size.y = GetWindowSize().height;
374
375 FS::BindFrameInfo(*r2t_pass, host_buffer->EmplaceUniform(frame_info));
376 FS::BindContents1(*r2t_pass, boston, sampler);
377 FS::BindContents2(*r2t_pass, bridge, sampler);
378
379 VS::UniformBuffer uniforms;
380 uniforms.mvp = Matrix::MakeOrthographic(ISize{1024, 768}) *
381 Matrix::MakeTranslation({50.0f, 50.0f, 0.0f});
382 VS::BindUniformBuffer(*r2t_pass, host_buffer->EmplaceUniform(uniforms));
383 ASSERT_TRUE(r2t_pass->Draw().ok());
384 ASSERT_TRUE(r2t_pass->EncodeCommands());
385 }
386
387 TEST_P(RendererTest, CanRenderInstanced) {
388 if (GetParam() == PlaygroundBackend::kOpenGLES) {
389 GTEST_SKIP_("Instancing is not supported on OpenGL.");
390 }
391 using VS = InstancedDrawVertexShader;
392 using FS = InstancedDrawFragmentShader;
393
394 VertexBufferBuilder<VS::PerVertexData> builder;
395
396 ASSERT_EQ(Tessellator::Result::kSuccess,
397 Tessellator{}.Tessellate(
398 PathBuilder{}
399 .AddRect(Rect::MakeXYWH(10, 10, 100, 100))
400 .TakePath(FillType::kOdd),
401 1.0f,
402 [&builder](const float* vertices, size_t vertices_count,
403 const uint16_t* indices, size_t indices_count) {
404 for (auto i = 0u; i < vertices_count * 2; i += 2) {
405 VS::PerVertexData data;
406 data.vtx = {vertices[i], vertices[i + 1]};
407 builder.AppendVertex(data);
408 }
409 for (auto i = 0u; i < indices_count; i++) {
410 builder.AppendIndex(indices[i]);
411 }
412 return true;
413 }));
414
415 ASSERT_NE(GetContext(), nullptr);
416 auto pipeline =
417 GetContext()
418 ->GetPipelineLibrary()
419 ->GetPipeline(PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(
420 *GetContext())
421 ->SetSampleCount(SampleCount::kCount4)
422 .SetStencilAttachmentDescriptors(std::nullopt))
423
424 .Get();
425 ASSERT_TRUE(pipeline && pipeline->IsValid());
426
427 static constexpr size_t kInstancesCount = 5u;
428 VS::InstanceInfo<kInstancesCount> instances;
429 for (size_t i = 0; i < kInstancesCount; i++) {
430 instances.colors[i] = Color::Random();
431 }
432
433 auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator());
434 ASSERT_TRUE(OpenPlaygroundHere([&](RenderPass& pass) -> bool {
435 pass.SetPipeline(pipeline);
436 pass.SetCommandLabel("InstancedDraw");
437
438 VS::FrameInfo frame_info;
439 EXPECT_EQ(pass.GetOrthographicTransform(),
440 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
441 frame_info.mvp =
442 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
443 VS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
444 VS::BindInstanceInfo(pass, host_buffer->EmplaceStorageBuffer(instances));
445 pass.SetVertexBuffer(builder.CreateVertexBuffer(*host_buffer));
446
447 pass.SetInstanceCount(kInstancesCount);
448 pass.Draw();
449
450 host_buffer->Reset();
451 return true;
452 }));
453 }
454
455 TEST_P(RendererTest, CanBlitTextureToTexture) {
456 if (GetBackend() == PlaygroundBackend::kOpenGLES) {
457 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
458 }
459 auto context = GetContext();
460 ASSERT_TRUE(context);
461
462 using VS = MipmapsVertexShader;
463 using FS = MipmapsFragmentShader;
464 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
465 ASSERT_TRUE(desc.has_value());
466 desc->SetSampleCount(SampleCount::kCount4);
467 desc->SetStencilAttachmentDescriptors(std::nullopt);
468 auto mipmaps_pipeline =
469 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
470 ASSERT_TRUE(mipmaps_pipeline);
471
472 TextureDescriptor texture_desc;
473 texture_desc.storage_mode = StorageMode::kHostVisible;
474 texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
475 texture_desc.size = {800, 600};
476 texture_desc.mip_count = 1u;
477 texture_desc.usage = TextureUsage::kRenderTarget | TextureUsage::kShaderRead;
478 auto texture = context->GetResourceAllocator()->CreateTexture(texture_desc);
479 ASSERT_TRUE(texture);
480
481 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
482 auto boston = CreateTextureForFixture("boston.jpg");
483 ASSERT_TRUE(bridge && boston);
484 const std::unique_ptr<const Sampler>& sampler =
485 context->GetSamplerLibrary()->GetSampler({});
486 ASSERT_TRUE(sampler);
487
488 // Vertex buffer.
489 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
490 vertex_builder.SetLabel("Box");
491 auto size = Point(boston->GetSize());
492 vertex_builder.AddVertices({
493 {{0, 0}, {0.0, 0.0}}, // 1
494 {{size.x, 0}, {1.0, 0.0}}, // 2
495 {{size.x, size.y}, {1.0, 1.0}}, // 3
496 {{0, 0}, {0.0, 0.0}}, // 1
497 {{size.x, size.y}, {1.0, 1.0}}, // 3
498 {{0, size.y}, {0.0, 1.0}}, // 4
499 });
500 auto vertex_buffer =
501 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
502 ASSERT_TRUE(vertex_buffer);
503
504 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
505 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
506 auto buffer = context->CreateCommandBuffer();
507 if (!buffer) {
508 return false;
509 }
510 buffer->SetLabel("Playground Command Buffer");
511
512 {
513 auto pass = buffer->CreateBlitPass();
514 if (!pass) {
515 return false;
516 }
517 pass->SetLabel("Playground Blit Pass");
518
519 if (render_target.GetColorAttachments().empty()) {
520 return false;
521 }
522
523 // Blit `bridge` to the top left corner of the texture.
524 pass->AddCopy(bridge, texture);
525
526 if (!pass->EncodeCommands(context->GetResourceAllocator())) {
527 return false;
528 }
529 }
530
531 {
532 auto pass = buffer->CreateRenderPass(render_target);
533 if (!pass) {
534 return false;
535 }
536 pass->SetLabel("Playground Render Pass");
537 {
538 pass->SetCommandLabel("Image");
539 pass->SetPipeline(mipmaps_pipeline);
540 pass->SetVertexBuffer(vertex_buffer);
541
542 VS::FrameInfo frame_info;
543 EXPECT_EQ(pass->GetOrthographicTransform(),
544 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
545 frame_info.mvp = pass->GetOrthographicTransform() *
546 Matrix::MakeScale(GetContentScale());
547 VS::BindFrameInfo(*pass, host_buffer->EmplaceUniform(frame_info));
548
549 FS::FragInfo frag_info;
550 frag_info.lod = 0;
551 FS::BindFragInfo(*pass, host_buffer->EmplaceUniform(frag_info));
552
553 auto& sampler = context->GetSamplerLibrary()->GetSampler({});
554 FS::BindTex(*pass, texture, sampler);
555
556 pass->Draw();
557 }
558 pass->EncodeCommands();
559 }
560
561 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
562 return false;
563 }
564 host_buffer->Reset();
565 return true;
566 };
567 OpenPlaygroundHere(callback);
568 }
569
570 TEST_P(RendererTest, CanBlitTextureToBuffer) {
571 if (GetBackend() == PlaygroundBackend::kOpenGLES) {
572 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
573 }
574 auto context = GetContext();
575 ASSERT_TRUE(context);
576
577 using VS = MipmapsVertexShader;
578 using FS = MipmapsFragmentShader;
579 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
580 ASSERT_TRUE(desc.has_value());
581 desc->SetSampleCount(SampleCount::kCount4);
582 desc->SetStencilAttachmentDescriptors(std::nullopt);
583 auto mipmaps_pipeline =
584 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
585 ASSERT_TRUE(mipmaps_pipeline);
586
587 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
588 auto boston = CreateTextureForFixture("boston.jpg");
589 ASSERT_TRUE(bridge && boston);
590 const std::unique_ptr<const Sampler>& sampler =
591 context->GetSamplerLibrary()->GetSampler({});
592 ASSERT_TRUE(sampler);
593
594 TextureDescriptor texture_desc;
595 texture_desc.storage_mode = StorageMode::kHostVisible;
596 texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
597 texture_desc.size = bridge->GetTextureDescriptor().size;
598 texture_desc.mip_count = 1u;
599 texture_desc.usage = TextureUsage::kRenderTarget |
600 TextureUsage::kShaderWrite | TextureUsage::kShaderRead;
601 DeviceBufferDescriptor device_buffer_desc;
602 device_buffer_desc.storage_mode = StorageMode::kHostVisible;
603 device_buffer_desc.size =
604 bridge->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
605 auto device_buffer =
606 context->GetResourceAllocator()->CreateBuffer(device_buffer_desc);
607
608 // Vertex buffer.
609 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
610 vertex_builder.SetLabel("Box");
611 auto size = Point(boston->GetSize());
612 vertex_builder.AddVertices({
613 {{0, 0}, {0.0, 0.0}}, // 1
614 {{size.x, 0}, {1.0, 0.0}}, // 2
615 {{size.x, size.y}, {1.0, 1.0}}, // 3
616 {{0, 0}, {0.0, 0.0}}, // 1
617 {{size.x, size.y}, {1.0, 1.0}}, // 3
618 {{0, size.y}, {0.0, 1.0}}, // 4
619 });
620 auto vertex_buffer =
621 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
622 ASSERT_TRUE(vertex_buffer);
623
624 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
625 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
626 {
627 auto buffer = context->CreateCommandBuffer();
628 if (!buffer) {
629 return false;
630 }
631 buffer->SetLabel("Playground Command Buffer");
632 auto pass = buffer->CreateBlitPass();
633 if (!pass) {
634 return false;
635 }
636 pass->SetLabel("Playground Blit Pass");
637
638 if (render_target.GetColorAttachments().empty()) {
639 return false;
640 }
641
642 // Blit `bridge` to the top left corner of the texture.
643 pass->AddCopy(bridge, device_buffer);
644 pass->EncodeCommands(context->GetResourceAllocator());
645
646 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
647 return false;
648 }
649 }
650
651 {
652 auto buffer = context->CreateCommandBuffer();
653 if (!buffer) {
654 return false;
655 }
656 buffer->SetLabel("Playground Command Buffer");
657
658 auto pass = buffer->CreateRenderPass(render_target);
659 if (!pass) {
660 return false;
661 }
662 pass->SetLabel("Playground Render Pass");
663 {
664 pass->SetCommandLabel("Image");
665 pass->SetPipeline(mipmaps_pipeline);
666 pass->SetVertexBuffer(vertex_buffer);
667
668 VS::FrameInfo frame_info;
669 EXPECT_EQ(pass->GetOrthographicTransform(),
670 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
671 frame_info.mvp = pass->GetOrthographicTransform() *
672 Matrix::MakeScale(GetContentScale());
673 VS::BindFrameInfo(*pass, host_buffer->EmplaceUniform(frame_info));
674
675 FS::FragInfo frag_info;
676 frag_info.lod = 0;
677 FS::BindFragInfo(*pass, host_buffer->EmplaceUniform(frag_info));
678
679 const std::unique_ptr<const Sampler>& sampler =
680 context->GetSamplerLibrary()->GetSampler({});
681 auto buffer_view = DeviceBuffer::AsBufferView(device_buffer);
682 auto texture =
683 context->GetResourceAllocator()->CreateTexture(texture_desc);
684 if (!texture->SetContents(device_buffer->OnGetContents(),
685 buffer_view.range.length)) {
686 VALIDATION_LOG << "Could not upload texture to device memory";
687 return false;
688 }
689 FS::BindTex(*pass, texture, sampler);
690
691 pass->Draw().ok();
692 }
693 pass->EncodeCommands();
694 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
695 return false;
696 }
697 }
698 host_buffer->Reset();
699 return true;
700 };
701 OpenPlaygroundHere(callback);
702 }
703
704 TEST_P(RendererTest, CanGenerateMipmaps) {
705 if (GetBackend() == PlaygroundBackend::kOpenGLES) {
706 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
707 }
708 auto context = GetContext();
709 ASSERT_TRUE(context);
710
711 using VS = MipmapsVertexShader;
712 using FS = MipmapsFragmentShader;
713 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
714 ASSERT_TRUE(desc.has_value());
715 desc->SetSampleCount(SampleCount::kCount4);
716 desc->SetStencilAttachmentDescriptors(std::nullopt);
717 auto mipmaps_pipeline =
718 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
719 ASSERT_TRUE(mipmaps_pipeline);
720
721 auto boston = CreateTextureForFixture("boston.jpg", true);
722 ASSERT_TRUE(boston);
723
724 // Vertex buffer.
725 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
726 vertex_builder.SetLabel("Box");
727 auto size = Point(boston->GetSize());
728 vertex_builder.AddVertices({
729 {{0, 0}, {0.0, 0.0}}, // 1
730 {{size.x, 0}, {1.0, 0.0}}, // 2
731 {{size.x, size.y}, {1.0, 1.0}}, // 3
732 {{0, 0}, {0.0, 0.0}}, // 1
733 {{size.x, size.y}, {1.0, 1.0}}, // 3
734 {{0, size.y}, {0.0, 1.0}}, // 4
735 });
736 auto vertex_buffer =
737 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
738 ASSERT_TRUE(vertex_buffer);
739
740 bool first_frame = true;
741 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
742 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
743 const char* mip_filter_names[] = {"Nearest", "Linear"};
744 const MipFilter mip_filters[] = {MipFilter::kNearest, MipFilter::kLinear};
745 const char* min_filter_names[] = {"Nearest", "Linear"};
746 const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
747 MinMagFilter::kLinear};
748
749 // UI state.
750 static int selected_mip_filter = 1;
751 static int selected_min_filter = 0;
752 static float lod = 4.5;
753
754 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
755 ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names,
756 sizeof(mip_filter_names) / sizeof(char*));
757 ImGui::Combo("Min filter", &selected_min_filter, min_filter_names,
758 sizeof(min_filter_names) / sizeof(char*));
759 ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1);
760 ImGui::End();
761
762 auto buffer = context->CreateCommandBuffer();
763 if (!buffer) {
764 return false;
765 }
766 buffer->SetLabel("Playground Command Buffer");
767
768 if (first_frame) {
769 auto pass = buffer->CreateBlitPass();
770 if (!pass) {
771 return false;
772 }
773 pass->SetLabel("Playground Blit Pass");
774
775 pass->GenerateMipmap(boston, "Boston Mipmap");
776
777 pass->EncodeCommands(context->GetResourceAllocator());
778 }
779
780 first_frame = false;
781
782 {
783 auto pass = buffer->CreateRenderPass(render_target);
784 if (!pass) {
785 return false;
786 }
787 pass->SetLabel("Playground Render Pass");
788 {
789 pass->SetCommandLabel("Image LOD");
790 pass->SetPipeline(mipmaps_pipeline);
791 pass->SetVertexBuffer(vertex_buffer);
792
793 VS::FrameInfo frame_info;
794 EXPECT_EQ(pass->GetOrthographicTransform(),
795 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
796 frame_info.mvp = pass->GetOrthographicTransform() *
797 Matrix::MakeScale(GetContentScale());
798 VS::BindFrameInfo(*pass, host_buffer->EmplaceUniform(frame_info));
799
800 FS::FragInfo frag_info;
801 frag_info.lod = lod;
802 FS::BindFragInfo(*pass, host_buffer->EmplaceUniform(frag_info));
803
804 SamplerDescriptor sampler_desc;
805 sampler_desc.mip_filter = mip_filters[selected_mip_filter];
806 sampler_desc.min_filter = min_filters[selected_min_filter];
807 const std::unique_ptr<const Sampler>& sampler =
808 context->GetSamplerLibrary()->GetSampler(sampler_desc);
809 FS::BindTex(*pass, boston, sampler);
810
811 pass->Draw();
812 }
813 pass->EncodeCommands();
814 }
815
816 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
817 return false;
818 }
819 host_buffer->Reset();
820 return true;
821 };
822 OpenPlaygroundHere(callback);
823 }
824
825 TEST_P(RendererTest, TheImpeller) {
826 using VS = ImpellerVertexShader;
827 using FS = ImpellerFragmentShader;
828
829 auto context = GetContext();
830 auto pipeline_descriptor =
831 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
832 ASSERT_TRUE(pipeline_descriptor.has_value());
833 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
834 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
835 auto pipeline =
836 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
837 ASSERT_TRUE(pipeline && pipeline->IsValid());
838
839 auto blue_noise = CreateTextureForFixture("blue_noise.png");
840 SamplerDescriptor noise_sampler_desc;
841 noise_sampler_desc.width_address_mode = SamplerAddressMode::kRepeat;
842 noise_sampler_desc.height_address_mode = SamplerAddressMode::kRepeat;
843 const std::unique_ptr<const Sampler>& noise_sampler =
844 context->GetSamplerLibrary()->GetSampler(noise_sampler_desc);
845
846 auto cube_map = CreateTextureCubeForFixture(
847 {"table_mountain_px.png", "table_mountain_nx.png",
848 "table_mountain_py.png", "table_mountain_ny.png",
849 "table_mountain_pz.png", "table_mountain_nz.png"});
850 const std::unique_ptr<const Sampler>& cube_map_sampler =
851 context->GetSamplerLibrary()->GetSampler({});
852 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
853
854 SinglePassCallback callback = [&](RenderPass& pass) {
855 auto size = pass.GetRenderTargetSize();
856
857 pass.SetPipeline(pipeline);
858 pass.SetCommandLabel("Impeller SDF scene");
859 VertexBufferBuilder<VS::PerVertexData> builder;
860 builder.AddVertices({{Point()},
861 {Point(0, size.height)},
862 {Point(size.width, 0)},
863 {Point(size.width, 0)},
864 {Point(0, size.height)},
865 {Point(size.width, size.height)}});
866 pass.SetVertexBuffer(builder.CreateVertexBuffer(*host_buffer));
867
868 VS::FrameInfo frame_info;
869 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
870 frame_info.mvp = pass.GetOrthographicTransform();
871 VS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
872
873 FS::FragInfo fs_uniform;
874 fs_uniform.texture_size = Point(size);
875 fs_uniform.time = GetSecondsElapsed();
876 FS::BindFragInfo(pass, host_buffer->EmplaceUniform(fs_uniform));
877 FS::BindBlueNoise(pass, blue_noise, noise_sampler);
878 FS::BindCubeMap(pass, cube_map, cube_map_sampler);
879
880 pass.Draw().ok();
881 host_buffer->Reset();
882 return true;
883 };
884 OpenPlaygroundHere(callback);
885 }
886
887 TEST_P(RendererTest, ArrayUniforms) {
888 using VS = ArrayVertexShader;
889 using FS = ArrayFragmentShader;
890
891 auto context = GetContext();
892 auto pipeline_descriptor =
893 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
894 ASSERT_TRUE(pipeline_descriptor.has_value());
895 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
896 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
897 auto pipeline =
898 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
899 ASSERT_TRUE(pipeline && pipeline->IsValid());
900
901 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
902 SinglePassCallback callback = [&](RenderPass& pass) {
903 auto size = pass.GetRenderTargetSize();
904
905 pass.SetPipeline(pipeline);
906 pass.SetCommandLabel("Google Dots");
907 VertexBufferBuilder<VS::PerVertexData> builder;
908 builder.AddVertices({{Point()},
909 {Point(0, size.height)},
910 {Point(size.width, 0)},
911 {Point(size.width, 0)},
912 {Point(0, size.height)},
913 {Point(size.width, size.height)}});
914 pass.SetVertexBuffer(builder.CreateVertexBuffer(*host_buffer));
915
916 VS::FrameInfo frame_info;
917 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
918 frame_info.mvp =
919 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
920 VS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
921
922 auto time = GetSecondsElapsed();
923 auto y_pos = [&time](float x) {
924 return 400 + 10 * std::cos(time * 5 + x / 6);
925 };
926
927 FS::FragInfo fs_uniform = {
928 .circle_positions = {Point(430, y_pos(0)), Point(480, y_pos(1)),
929 Point(530, y_pos(2)), Point(580, y_pos(3))},
930 .colors = {Color::MakeRGBA8(66, 133, 244, 255),
931 Color::MakeRGBA8(219, 68, 55, 255),
932 Color::MakeRGBA8(244, 180, 0, 255),
933 Color::MakeRGBA8(15, 157, 88, 255)},
934 };
935 FS::BindFragInfo(pass, host_buffer->EmplaceUniform(fs_uniform));
936
937 pass.Draw();
938 host_buffer->Reset();
939 return true;
940 };
941 OpenPlaygroundHere(callback);
942 }
943
944 TEST_P(RendererTest, InactiveUniforms) {
945 using VS = InactiveUniformsVertexShader;
946 using FS = InactiveUniformsFragmentShader;
947
948 auto context = GetContext();
949 auto pipeline_descriptor =
950 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
951 ASSERT_TRUE(pipeline_descriptor.has_value());
952 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
953 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
954 auto pipeline =
955 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
956 ASSERT_TRUE(pipeline && pipeline->IsValid());
957
958 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
959 SinglePassCallback callback = [&](RenderPass& pass) {
960 auto size = pass.GetRenderTargetSize();
961
962 pass.SetPipeline(pipeline);
963 pass.SetCommandLabel("Inactive Uniform");
964
965 VertexBufferBuilder<VS::PerVertexData> builder;
966 builder.AddVertices({{Point()},
967 {Point(0, size.height)},
968 {Point(size.width, 0)},
969 {Point(size.width, 0)},
970 {Point(0, size.height)},
971 {Point(size.width, size.height)}});
972 pass.SetVertexBuffer(builder.CreateVertexBuffer(*host_buffer));
973
974 VS::FrameInfo frame_info;
975 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
976 frame_info.mvp =
977 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
978 VS::BindFrameInfo(pass, host_buffer->EmplaceUniform(frame_info));
979
980 FS::FragInfo fs_uniform = {.unused_color = Color::Red(),
981 .color = Color::Green()};
982 FS::BindFragInfo(pass, host_buffer->EmplaceUniform(fs_uniform));
983
984 pass.Draw().ok();
985 host_buffer->Reset();
986 return true;
987 };
988 OpenPlaygroundHere(callback);
989 }
990
991 TEST_P(RendererTest, CanCreateCPUBackedTexture) {
992 if (GetParam() == PlaygroundBackend::kOpenGLES) {
993 GTEST_SKIP_("CPU backed textures are not supported on OpenGLES.");
994 }
995
996 auto context = GetContext();
997 auto allocator = context->GetResourceAllocator();
998 size_t dimension = 2;
999
1000 do {
1001 ISize size(dimension, dimension);
1002 TextureDescriptor texture_descriptor;
1003 texture_descriptor.storage_mode = StorageMode::kHostVisible;
1004 texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
1005 texture_descriptor.size = size;
1006 auto row_bytes =
1007 std::max(static_cast<uint16_t>(size.width * 4),
1008 allocator->MinimumBytesPerRow(texture_descriptor.format));
1009 auto buffer_size = size.height * row_bytes;
1010
1011 DeviceBufferDescriptor buffer_descriptor;
1012 buffer_descriptor.storage_mode = StorageMode::kHostVisible;
1013 buffer_descriptor.size = buffer_size;
1014
1015 auto buffer = allocator->CreateBuffer(buffer_descriptor);
1016
1017 ASSERT_TRUE(buffer);
1018
1019 auto texture = buffer->AsTexture(*allocator, texture_descriptor, row_bytes);
1020
1021 ASSERT_TRUE(texture);
1022 ASSERT_TRUE(texture->IsValid());
1023
1024 dimension *= 2;
1025 } while (dimension <= 8192);
1026 }
1027
1028 TEST_P(RendererTest, DefaultIndexSize) {
1029 using VS = BoxFadeVertexShader;
1030
1031 // Default to 16bit index buffer size, as this is a reasonable default and
1032 // supported on all backends without extensions.
1033 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1034 vertex_builder.AppendIndex(0u);
1035 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::k16bit);
1036 }
1037
1038 TEST_P(RendererTest, DefaultIndexBehavior) {
1039 using VS = BoxFadeVertexShader;
1040
1041 // Do not create any index buffer if no indices were provided.
1042 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1043 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1044 }
1045
1046 TEST_P(RendererTest, VertexBufferBuilder) {
1047 // Does not create index buffer if one is provided.
1048 using VS = BoxFadeVertexShader;
1049 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1050 vertex_builder.SetLabel("Box");
1051 vertex_builder.AddVertices({
1052 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1053 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1054 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1055 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1056 });
1057 vertex_builder.AppendIndex(0);
1058 vertex_builder.AppendIndex(1);
1059 vertex_builder.AppendIndex(2);
1060 vertex_builder.AppendIndex(1);
1061 vertex_builder.AppendIndex(2);
1062 vertex_builder.AppendIndex(3);
1063
1064 ASSERT_EQ(vertex_builder.GetIndexCount(), 6u);
1065 ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
1066 }
1067
1068 class CompareFunctionUIData {
1069 public:
1070 CompareFunctionUIData() {
1071 labels_.push_back("Never");
1072 functions_.push_back(CompareFunction::kNever);
1073 labels_.push_back("Always");
1074 functions_.push_back(CompareFunction::kAlways);
1075 labels_.push_back("Less");
1076 functions_.push_back(CompareFunction::kLess);
1077 labels_.push_back("Equal");
1078 functions_.push_back(CompareFunction::kEqual);
1079 labels_.push_back("LessEqual");
1080 functions_.push_back(CompareFunction::kLessEqual);
1081 labels_.push_back("Greater");
1082 functions_.push_back(CompareFunction::kGreater);
1083 labels_.push_back("NotEqual");
1084 functions_.push_back(CompareFunction::kNotEqual);
1085 labels_.push_back("GreaterEqual");
1086 functions_.push_back(CompareFunction::kGreaterEqual);
1087 assert(labels_.size() == functions_.size());
1088 }
1089
1090 const char* const* labels() const { return &labels_[0]; }
1091
1092 int size() const { return labels_.size(); }
1093
1094 int IndexOf(CompareFunction func) const {
1095 for (size_t i = 0; i < functions_.size(); i++) {
1096 if (functions_[i] == func) {
1097 return i;
1098 }
1099 }
1100 FML_UNREACHABLE();
1101 return -1;
1102 }
1103
1104 CompareFunction FunctionOf(int index) const { return functions_[index]; }
1105
1106 private:
1107 std::vector<const char*> labels_;
1108 std::vector<CompareFunction> functions_;
1109 };
1110
1111 static const CompareFunctionUIData& CompareFunctionUI() {
1112 static CompareFunctionUIData data;
1113 return data;
1114 }
1115
1116 TEST_P(RendererTest, StencilMask) {
1117 using VS = BoxFadeVertexShader;
1118 using FS = BoxFadeFragmentShader;
1119 auto context = GetContext();
1120 ASSERT_TRUE(context);
1121 using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1122 auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1123 ASSERT_TRUE(desc.has_value());
1124
1125 // Vertex buffer.
1126 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1127 vertex_builder.SetLabel("Box");
1128 vertex_builder.AddVertices({
1129 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1130 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1131 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1132 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1133 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1134 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1135 });
1136 auto vertex_buffer =
1137 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
1138 ASSERT_TRUE(vertex_buffer);
1139
1140 desc->SetSampleCount(SampleCount::kCount4);
1141 desc->SetStencilAttachmentDescriptors(std::nullopt);
1142
1143 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
1144 auto boston = CreateTextureForFixture("boston.jpg");
1145 ASSERT_TRUE(bridge && boston);
1146 const std::unique_ptr<const Sampler>& sampler =
1147 context->GetSamplerLibrary()->GetSampler({});
1148 ASSERT_TRUE(sampler);
1149
1150 static bool mirror = false;
1151 static int stencil_reference_write = 0xFF;
1152 static int stencil_reference_read = 0x1;
1153 std::vector<uint8_t> stencil_contents;
1154 static int last_stencil_contents_reference_value = 0;
1155 static int current_front_compare =
1156 CompareFunctionUI().IndexOf(CompareFunction::kLessEqual);
1157 static int current_back_compare =
1158 CompareFunctionUI().IndexOf(CompareFunction::kLessEqual);
1159
1160 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
1161 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
1162 auto buffer = context->CreateCommandBuffer();
1163 if (!buffer) {
1164 return false;
1165 }
1166 buffer->SetLabel("Playground Command Buffer");
1167
1168 {
1169 // Configure the stencil attachment for the test.
1170 RenderTarget::AttachmentConfig stencil_config;
1171 stencil_config.load_action = LoadAction::kLoad;
1172 stencil_config.store_action = StoreAction::kDontCare;
1173 stencil_config.storage_mode = StorageMode::kHostVisible;
1174 render_target.SetupDepthStencilAttachments(
1175 *context, *context->GetResourceAllocator(),
1176 render_target.GetRenderTargetSize(), true, "stencil", stencil_config);
1177 // Fill the stencil buffer with an checkerboard pattern.
1178 const auto target_width = render_target.GetRenderTargetSize().width;
1179 const auto target_height = render_target.GetRenderTargetSize().height;
1180 const size_t target_size = target_width * target_height;
1181 if (stencil_contents.size() != target_size ||
1182 last_stencil_contents_reference_value != stencil_reference_write) {
1183 stencil_contents.resize(target_size);
1184 last_stencil_contents_reference_value = stencil_reference_write;
1185 for (int y = 0; y < target_height; y++) {
1186 for (int x = 0; x < target_width; x++) {
1187 const auto index = y * target_width + x;
1188 const auto kCheckSize = 64;
1189 const auto value =
1190 (((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
1191 stencil_reference_write;
1192 stencil_contents[index] = value;
1193 }
1194 }
1195 }
1196 if (!render_target.GetStencilAttachment()->texture->SetContents(
1197 stencil_contents.data(), stencil_contents.size(), 0, false)) {
1198 VALIDATION_LOG << "Could not upload stencil contents to device memory";
1199 return false;
1200 }
1201 auto pass = buffer->CreateRenderPass(render_target);
1202 if (!pass) {
1203 return false;
1204 }
1205 pass->SetLabel("Stencil Buffer");
1206 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1207 ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
1208 0xFF);
1209 ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
1210 0xFF);
1211 ImGui::Checkbox("Back face mode", &mirror);
1212 ImGui::ListBox("Front face compare function", &current_front_compare,
1213 CompareFunctionUI().labels(), CompareFunctionUI().size());
1214 ImGui::ListBox("Back face compare function", &current_back_compare,
1215 CompareFunctionUI().labels(), CompareFunctionUI().size());
1216 ImGui::End();
1217
1218 StencilAttachmentDescriptor front;
1219 front.stencil_compare =
1220 CompareFunctionUI().FunctionOf(current_front_compare);
1221 StencilAttachmentDescriptor back;
1222 back.stencil_compare =
1223 CompareFunctionUI().FunctionOf(current_back_compare);
1224 desc->SetStencilAttachmentDescriptors(front, back);
1225 auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
1226
1227 assert(pipeline && pipeline->IsValid());
1228
1229 pass->SetCommandLabel("Box");
1230 pass->SetPipeline(pipeline);
1231 pass->SetStencilReference(stencil_reference_read);
1232 pass->SetVertexBuffer(vertex_buffer);
1233
1234 VS::UniformBuffer uniforms;
1235 EXPECT_EQ(pass->GetOrthographicTransform(),
1236 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
1237 uniforms.mvp = pass->GetOrthographicTransform() *
1238 Matrix::MakeScale(GetContentScale());
1239 if (mirror) {
1240 uniforms.mvp = Matrix::MakeScale(Vector2(-1, 1)) * uniforms.mvp;
1241 }
1242 VS::BindUniformBuffer(*pass, host_buffer->EmplaceUniform(uniforms));
1243
1244 FS::FrameInfo frame_info;
1245 frame_info.current_time = GetSecondsElapsed();
1246 frame_info.cursor_position = GetCursorPosition();
1247 frame_info.window_size.x = GetWindowSize().width;
1248 frame_info.window_size.y = GetWindowSize().height;
1249
1250 FS::BindFrameInfo(*pass, host_buffer->EmplaceUniform(frame_info));
1251 FS::BindContents1(*pass, boston, sampler);
1252 FS::BindContents2(*pass, bridge, sampler);
1253 if (!pass->Draw().ok()) {
1254 return false;
1255 }
1256 pass->EncodeCommands();
1257 }
1258
1259 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
1260 return false;
1261 }
1262 host_buffer->Reset();
1263 return true;
1264 };
1265 OpenPlaygroundHere(callback);
1266 }
1267
1268 TEST_P(RendererTest, CanLookupRenderTargetProperties) {
1269 auto context = GetContext();
1270 auto cmd_buffer = context->CreateCommandBuffer();
1271 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1272 GetContext()->GetResourceAllocator());
1273
1274 auto render_target = render_target_cache->CreateOffscreen(
1275 *context, {100, 100}, /*mip_count=*/1);
1276 auto render_pass = cmd_buffer->CreateRenderPass(render_target);
1277
1278 EXPECT_EQ(render_pass->GetSampleCount(), render_target.GetSampleCount());
1279 EXPECT_EQ(render_pass->GetRenderTargetPixelFormat(),
1280 render_target.GetRenderTargetPixelFormat());
1281 EXPECT_EQ(render_pass->HasStencilAttachment(),
1282 render_target.GetStencilAttachment().has_value());
1283 EXPECT_EQ(render_pass->GetRenderTargetSize(),
1284 render_target.GetRenderTargetSize());
1285 render_pass->EncodeCommands();
1286 }
1287
1288 TEST_P(RendererTest,
1289 RenderTargetCreateOffscreenMSAASetsDefaultDepthStencilFormat) {
1290 auto context = GetContext();
1291 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1292 GetContext()->GetResourceAllocator());
1293
1294 RenderTarget render_target = render_target_cache->CreateOffscreenMSAA(
1295 *context, {100, 100}, /*mip_count=*/1);
1296 EXPECT_EQ(render_target.GetDepthAttachment()
1297 ->texture->GetTextureDescriptor()
1298 .format,
1299 GetContext()->GetCapabilities()->GetDefaultDepthStencilFormat());
1300 }
1301
1302 template <class VertexShader, class FragmentShader>
1303 std::shared_ptr<Pipeline<PipelineDescriptor>> CreateDefaultPipeline(
1304 const std::shared_ptr<Context>& context) {
1305 using TexturePipelineBuilder = PipelineBuilder<VertexShader, FragmentShader>;
1306 auto pipeline_desc =
1307 TexturePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1308 if (!pipeline_desc.has_value()) {
1309 return nullptr;
1310 }
1311 pipeline_desc->SetSampleCount(SampleCount::kCount4);
1312 pipeline_desc->SetStencilAttachmentDescriptors(std::nullopt);
1313 auto pipeline =
1314 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
1315 if (!pipeline || !pipeline->IsValid()) {
1316 return nullptr;
1317 }
1318 return pipeline;
1319 }
1320
1321 TEST_P(RendererTest, CanSepiaToneWithSubpasses) {
1322 // The GLES framebuffer fetch implementation currently does not support this.
1323 // TODO(chinmaygarde): revisit after the GLES framebuffer fetch capabilities
1324 // are clarified.
1325 if (GetParam() == PlaygroundBackend::kOpenGLES) {
1326 GTEST_SKIP_("Not supported on GLES.");
1327 }
1328
1329 // Define shader types
1330 using TextureVS = TextureVertexShader;
1331 using TextureFS = TextureFragmentShader;
1332
1333 using SepiaVS = SepiaVertexShader;
1334 using SepiaFS = SepiaFragmentShader;
1335
1336 auto context = GetContext();
1337 ASSERT_TRUE(context);
1338
1339 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1340 GTEST_SKIP_(
1341 "This test uses framebuffer fetch and the backend doesn't support it.");
1342 return;
1343 }
1344
1345 // Create pipelines.
1346 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1347 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1348
1349 ASSERT_TRUE(texture_pipeline);
1350 ASSERT_TRUE(sepia_pipeline);
1351
1352 // Vertex buffer builders.
1353 VertexBufferBuilder<TextureVS::PerVertexData> texture_vtx_builder;
1354 texture_vtx_builder.AddVertices({
1355 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1356 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1357 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1358 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1359 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1360 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1361 });
1362
1363 VertexBufferBuilder<SepiaVS::PerVertexData> sepia_vtx_builder;
1364 sepia_vtx_builder.AddVertices({
1365 {{100, 100, 0.0}}, // 1
1366 {{800, 100, 0.0}}, // 2
1367 {{800, 800, 0.0}}, // 3
1368 {{100, 100, 0.0}}, // 1
1369 {{800, 800, 0.0}}, // 3
1370 {{100, 800, 0.0}}, // 4
1371 });
1372
1373 auto boston = CreateTextureForFixture("boston.jpg");
1374 ASSERT_TRUE(boston);
1375
1376 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1377 ASSERT_TRUE(sampler);
1378
1379 SinglePassCallback callback = [&](RenderPass& pass) {
1380 auto buffer = HostBuffer::Create(context->GetResourceAllocator());
1381
1382 // Draw the texture.
1383 {
1384 pass.SetPipeline(texture_pipeline);
1385 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1386 *context->GetResourceAllocator()));
1387 TextureVS::UniformBuffer uniforms;
1388 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1389 Matrix::MakeScale(GetContentScale());
1390 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1391 TextureFS::BindTextureContents(pass, boston, sampler);
1392 if (!pass.Draw().ok()) {
1393 return false;
1394 }
1395 }
1396
1397 // Draw the sepia toner.
1398 {
1399 pass.SetPipeline(sepia_pipeline);
1400 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1401 *context->GetResourceAllocator()));
1402 SepiaVS::UniformBuffer uniforms;
1403 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1404 Matrix::MakeScale(GetContentScale());
1405 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1406 if (!pass.Draw().ok()) {
1407 return false;
1408 }
1409 }
1410
1411 return true;
1412 };
1413 OpenPlaygroundHere(callback);
1414 }
1415
1416 TEST_P(RendererTest, CanSepiaToneThenSwizzleWithSubpasses) {
1417 // The GLES framebuffer fetch implementation currently does not support this.
1418 // TODO(chinmaygarde): revisit after the GLES framebuffer fetch capabilities
1419 // are clarified.
1420 if (GetParam() == PlaygroundBackend::kOpenGLES) {
1421 GTEST_SKIP_("Not supported on GLES.");
1422 }
1423
1424 // Define shader types
1425 using TextureVS = TextureVertexShader;
1426 using TextureFS = TextureFragmentShader;
1427
1428 using SwizzleVS = SepiaVertexShader;
1429 using SwizzleFS = SwizzleFragmentShader;
1430
1431 using SepiaVS = SepiaVertexShader;
1432 using SepiaFS = SepiaFragmentShader;
1433
1434 auto context = GetContext();
1435 ASSERT_TRUE(context);
1436
1437 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1438 GTEST_SKIP_(
1439 "This test uses framebuffer fetch and the backend doesn't support it.");
1440 return;
1441 }
1442
1443 // Create pipelines.
1444 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1445 auto swizzle_pipeline = CreateDefaultPipeline<SwizzleVS, SwizzleFS>(context);
1446 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1447
1448 ASSERT_TRUE(texture_pipeline);
1449 ASSERT_TRUE(swizzle_pipeline);
1450 ASSERT_TRUE(sepia_pipeline);
1451
1452 // Vertex buffer builders.
1453 VertexBufferBuilder<TextureVS::PerVertexData> texture_vtx_builder;
1454 texture_vtx_builder.AddVertices({
1455 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1456 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1457 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1458 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1459 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1460 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1461 });
1462
1463 VertexBufferBuilder<SepiaVS::PerVertexData> sepia_vtx_builder;
1464 sepia_vtx_builder.AddVertices({
1465 {{100, 100, 0.0}}, // 1
1466 {{800, 100, 0.0}}, // 2
1467 {{800, 800, 0.0}}, // 3
1468 {{100, 100, 0.0}}, // 1
1469 {{800, 800, 0.0}}, // 3
1470 {{100, 800, 0.0}}, // 4
1471 });
1472
1473 auto boston = CreateTextureForFixture("boston.jpg");
1474 ASSERT_TRUE(boston);
1475
1476 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1477 ASSERT_TRUE(sampler);
1478
1479 SinglePassCallback callback = [&](RenderPass& pass) {
1480 auto buffer = HostBuffer::Create(context->GetResourceAllocator());
1481
1482 // Draw the texture.
1483 {
1484 pass.SetPipeline(texture_pipeline);
1485 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1486 *context->GetResourceAllocator()));
1487 TextureVS::UniformBuffer uniforms;
1488 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1489 Matrix::MakeScale(GetContentScale());
1490 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1491 TextureFS::BindTextureContents(pass, boston, sampler);
1492 if (!pass.Draw().ok()) {
1493 return false;
1494 }
1495 }
1496
1497 // Draw the sepia toner.
1498 {
1499 pass.SetPipeline(sepia_pipeline);
1500 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1501 *context->GetResourceAllocator()));
1502 SepiaVS::UniformBuffer uniforms;
1503 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1504 Matrix::MakeScale(GetContentScale());
1505 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1506 if (!pass.Draw().ok()) {
1507 return false;
1508 }
1509 }
1510
1511 // Draw the swizzle.
1512 {
1513 pass.SetPipeline(swizzle_pipeline);
1514 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1515 *context->GetResourceAllocator()));
1516 SwizzleVS::UniformBuffer uniforms;
1517 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1518 Matrix::MakeScale(GetContentScale());
1519 SwizzleVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1520 if (!pass.Draw().ok()) {
1521 return false;
1522 }
1523 }
1524
1525 return true;
1526 };
1527 OpenPlaygroundHere(callback);
1528 }
1529
1530 } // namespace testing
1531 } // namespace impeller
1532
1533 // NOLINTEND(bugprone-unchecked-optional-access)
impeller::DeviceBuffer::AsBufferView
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
Definition: device_buffer.cc:18
impeller::Color::Blue
static constexpr Color Blue()
Definition: color.h:268
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::VertexBuffer::index_type
IndexType index_type
Definition: vertex_buffer.h:29
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:182
host_buffer.h
impeller::RenderTarget::AttachmentConfig::store_action
StoreAction store_action
Definition: render_target.h:43
impeller::CompareFunction::kGreater
@ kGreater
Comparison test passes if new_value > current_value.
impeller::testing::CompareFunctionUI
static const CompareFunctionUIData & CompareFunctionUI()
Definition: renderer_unittests.cc:1111
impeller::LoadAction::kLoad
@ kLoad
impeller::TextureUsage::kShaderWrite
@ kShaderWrite
impeller::RenderTarget::AttachmentConfig::load_action
LoadAction load_action
Definition: render_target.h:42
impeller::IndexType::k16bit
@ k16bit
impeller::Attachment::store_action
StoreAction store_action
Definition: formats.h:642
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::StencilAttachmentDescriptor::stencil_compare
CompareFunction stencil_compare
Definition: formats.h:598
impeller::testing::CompareFunctionUIData::IndexOf
int IndexOf(CompareFunction func) const
Definition: renderer_unittests.cc:1094
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:47
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:264
impeller::FillType::kOdd
@ kOdd
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::Tessellator
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Definition: tessellator.h:33
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:154
impeller::testing::CompareFunctionUIData
Definition: renderer_unittests.cc:1068
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:14
impeller::Renderer::RenderCallback
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition: renderer.h:23
impeller::VertexBufferBuilder::GetVertexCount
size_t GetVertexCount() const
Definition: vertex_buffer_builder.h:54
impeller::CompareFunction::kEqual
@ kEqual
Comparison test passes if new_value == current_value.
impeller::ColorAttachment
Definition: formats.h:647
impeller::CompareFunction::kGreaterEqual
@ kGreaterEqual
Comparison test passes if new_value >= current_value.
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:40
impeller::RenderTarget::SetColorAttachment
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
Definition: render_target.cc:169
impeller::VertexBuffer
Definition: vertex_buffer.h:13
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::testing::RendererTest
PlaygroundTest RendererTest
Definition: render_pass_cache_unittests.cc:14
formats.h
impeller::PathBuilder
Definition: path_builder.h:14
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:42
impeller::Vector2
Point Vector2
Definition: point.h:320
impeller::HostBuffer::Create
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator)
Definition: host_buffer.cc:20
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:195
impeller::StoreAction::kDontCare
@ kDontCare
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:123
impeller::DeviceBufferDescriptor::size
size_t size
Definition: device_buffer_descriptor.h:16
impeller::VertexBufferBuilder::AddVertices
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
Definition: vertex_buffer_builder.h:70
impeller::Color::Yellow
static constexpr Color Yellow()
Definition: color.h:834
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::VertexBuffer::vertex_buffer
BufferView vertex_buffer
Definition: vertex_buffer.h:14
impeller::StorageMode::kHostVisible
@ kHostVisible
pipeline_builder.h
impeller::VertexBuffer::vertex_count
size_t vertex_count
Definition: vertex_buffer.h:23
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::RenderPass::SetCommandLabel
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
impeller::RenderPass::GetOrthographicTransform
const Matrix & GetOrthographicTransform() const
Definition: render_pass.cc:47
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:43
impeller::Vector3::x
Scalar x
Definition: vector.h:23
impeller::PolygonMode::kFill
@ kFill
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:112
impeller::testing::CompareFunctionUIData::CompareFunctionUIData
CompareFunctionUIData()
Definition: renderer_unittests.cc:1070
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:471
impeller::RenderTarget::AttachmentConfig
Definition: render_target.h:40
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:127
tessellator.h
impeller::RenderPass::SetInstanceCount
virtual void SetInstanceCount(size_t count)
Definition: render_pass.cc:119
path_builder.h
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:15
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:15
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
command.h
impeller::saturated::distance
SI distance
Definition: saturated_math.h:57
impeller::StencilAttachment
Definition: formats.h:655
impeller::MipFilter::kNearest
@ kNearest
Sample from the nearest mip level.
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:43
impeller::TSize< int64_t >
impeller::LoadAction::kClear
@ kClear
impeller::CompareFunction
CompareFunction
Definition: formats.h:534
impeller::SamplerDescriptor::min_filter
MinMagFilter min_filter
Definition: sampler_descriptor.h:16
impeller::RenderTarget::GetDepthAttachment
const std::optional< DepthAttachment > & GetDepthAttachment() const
Definition: render_target.cc:203
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::CullMode::kBackFace
@ kBackFace
render_pass.h
impeller::testing::CompareFunctionUIData::FunctionOf
CompareFunction FunctionOf(int index) const
Definition: renderer_unittests.cc:1104
impeller::MipFilter
MipFilter
Definition: formats.h:415
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:639
impeller::VertexBufferBuilder
Definition: vertex_buffer_builder.h:24
impeller::MinMagFilter::kLinear
@ kLinear
impeller::testing::CreateDefaultPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > CreateDefaultPipeline(const std::shared_ptr< Context > &context)
Definition: renderer_unittests.cc:1303
impeller::DeviceBufferDescriptor::storage_mode
StorageMode storage_mode
Definition: device_buffer_descriptor.h:15
impeller::Color::Random
static Color Random()
Definition: color.h:842
impeller::SamplerDescriptor::width_address_mode
SamplerAddressMode width_address_mode
Definition: sampler_descriptor.h:20
impeller::WindingOrder::kCounterClockwise
@ kCounterClockwise
impeller::Vector3::z
Scalar z
Definition: vector.h:25
impeller::VertexBufferBuilder::GetIndexCount
size_t GetIndexCount() const
Definition: vertex_buffer_builder.h:56
impeller::Radians
Definition: scalar.h:38
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Tessellator::Result::kSuccess
@ kSuccess
impeller::RenderTarget::AttachmentConfig::storage_mode
StorageMode storage_mode
Definition: render_target.h:41
impeller::MinMagFilter
MinMagFilter
Definition: formats.h:407
impeller::testing::CompareFunctionUIData::size
int size() const
Definition: renderer_unittests.cc:1092
impeller::RenderTarget
Definition: render_target.h:38
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:266
impeller::StoreAction::kStore
@ kStore
impeller::CompareFunction::kLessEqual
@ kLessEqual
Comparison test passes if new_value <= current_value.
impeller::Vector3::y
Scalar y
Definition: vector.h:24
impeller::CompareFunction::kAlways
@ kAlways
Comparison test passes always passes.
impeller::VertexBufferBuilder::AppendIndex
VertexBufferBuilder & AppendIndex(IndexType_ index)
Definition: vertex_buffer_builder.h:79
impeller::VertexBufferBuilder::SetLabel
void SetLabel(const std::string &label)
Definition: vertex_buffer_builder.h:46
impeller::TSize::width
Type width
Definition: size.h:22
impeller::SamplerDescriptor::mip_filter
MipFilter mip_filter
Definition: sampler_descriptor.h:18
impeller::VertexBufferBuilder::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
Definition: vertex_buffer_builder.h:84
pipeline_library.h
impeller::CompareFunction::kNever
@ kNever
Comparison test never passes.
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:41
sampler_descriptor.h
impeller::VertexBuffer::index_buffer
BufferView index_buffer
The index buffer binding used by the vertex shader stage.
Definition: vertex_buffer.h:18
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
command_buffer.h
impeller::VertexBufferBuilder::GetIndexType
constexpr impeller::IndexType GetIndexType() const
Definition: vertex_buffer_builder.h:33
impeller::PlaygroundBackend::kOpenGLES
@ kOpenGLES
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:209
impeller::Range
Definition: range.h:14
impeller::RenderTarget::SetStencilAttachment
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
Definition: render_target.cc:188
impeller::testing::TEST_P
TEST_P(AiksTest, CanRenderMaskBlurHugeSigma)
Definition: aiks_blur_unittests.cc:23
impeller::Tessellator::Tessellate
Tessellator::Result Tessellate(const Path &path, Scalar tolerance, const BuilderCallback &callback)
Generates filled triangles from the path. A callback is invoked once for the entire tessellation.
Definition: tessellator.cc:58
impeller::StencilAttachmentDescriptor
Definition: formats.h:592
impeller::BufferView::buffer
std::shared_ptr< const DeviceBuffer > buffer
Definition: buffer_view.h:16
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:641
impeller::MipFilter::kLinear
@ kLinear
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:462
impeller::VertexBufferBuilder::AppendVertex
VertexBufferBuilder & AppendVertex(VertexType_ vertex)
Definition: vertex_buffer_builder.h:65
impeller::Attachment::IsValid
bool IsValid() const
Definition: formats.cc:26
impeller::Degrees
Definition: scalar.h:46
impeller::SampleCount::kCount1
@ kCount1
impeller::SampleCount::kCount4
@ kCount4
impeller::PolygonMode::kLine
@ kLine
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:38
impeller::TSize::height
Type height
Definition: size.h:23
impeller::PlaygroundTest
Definition: playground_test.h:23
impeller::RenderPass::SetPipeline
virtual void SetPipeline(const std::shared_ptr< Pipeline< PipelineDescriptor >> &pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:92
device_buffer_descriptor.h
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:37
impeller::CompareFunction::kNotEqual
@ kNotEqual
Comparison test passes if new_value != current_value.
render_target.h
impeller::PipelineBuilder
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
Definition: pipeline_builder.h:32
impeller::PipelineBuilder::MakeDefaultPipelineDescriptor
static std::optional< PipelineDescriptor > MakeDefaultPipelineDescriptor(const Context &context, const std::vector< Scalar > &constants={})
Create a default pipeline descriptor using the combination reflected shader information....
Definition: pipeline_builder.h:51
renderer.h
impeller::SamplerDescriptor::height_address_mode
SamplerAddressMode height_address_mode
Definition: sampler_descriptor.h:21
impeller::CompareFunction::kLess
@ kLess
Comparison test passes if new_value < current_value.
impeller
Definition: aiks_blur_unittests.cc:20
playground_test.h
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::testing::CompareFunctionUIData::labels
const char *const * labels() const
Definition: renderer_unittests.cc:1090
impeller::Vector3
Definition: vector.h:20
vertex_buffer_builder.h
impeller::SamplerAddressMode::kRepeat
@ kRepeat