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 "flutter/testing/testing.h"
10 #include "impeller/core/sampler.h"
12 #include "impeller/fixtures/array.frag.h"
13 #include "impeller/fixtures/array.vert.h"
14 #include "impeller/fixtures/box_fade.frag.h"
15 #include "impeller/fixtures/box_fade.vert.h"
16 #include "impeller/fixtures/colors.frag.h"
17 #include "impeller/fixtures/colors.vert.h"
18 #include "impeller/fixtures/impeller.frag.h"
19 #include "impeller/fixtures/impeller.vert.h"
20 #include "impeller/fixtures/inactive_uniforms.frag.h"
21 #include "impeller/fixtures/inactive_uniforms.vert.h"
22 #include "impeller/fixtures/instanced_draw.frag.h"
23 #include "impeller/fixtures/instanced_draw.vert.h"
24 #include "impeller/fixtures/mipmaps.frag.h"
25 #include "impeller/fixtures/mipmaps.vert.h"
26 #include "impeller/fixtures/test_texture.frag.h"
27 #include "impeller/fixtures/test_texture.vert.h"
41 #include "third_party/imgui/imgui.h"
42 
43 // TODO(zanderso): https://github.com/flutter/flutter/issues/127701
44 // NOLINTBEGIN(bugprone-unchecked-optional-access)
45 
46 namespace impeller {
47 namespace testing {
48 
51 
52 TEST_P(RendererTest, CanCreateBoxPrimitive) {
53  using VS = BoxFadeVertexShader;
54  using FS = BoxFadeFragmentShader;
55  auto context = GetContext();
56  ASSERT_TRUE(context);
57  using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
58  auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
59  ASSERT_TRUE(desc.has_value());
60  desc->SetSampleCount(SampleCount::kCount4);
61  desc->SetStencilAttachmentDescriptors(std::nullopt);
62 
63  // Vertex buffer.
65  vertex_builder.SetLabel("Box");
66  vertex_builder.AddVertices({
67  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
68  {{800, 100, 0.0}, {1.0, 0.0}}, // 2
69  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
70  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
71  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
72  {{100, 800, 0.0}, {0.0, 1.0}}, // 4
73  });
74  auto vertex_buffer =
75  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
76  ASSERT_TRUE(vertex_buffer);
77 
78  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
79  auto boston = CreateTextureForFixture("boston.jpg");
80  ASSERT_TRUE(bridge && boston);
81  auto sampler = context->GetSamplerLibrary()->GetSampler({});
82  ASSERT_TRUE(sampler);
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  Command cmd;
95  DEBUG_COMMAND_INFO(cmd, "Box");
96  cmd.pipeline = pipeline;
97 
98  cmd.BindVertices(vertex_buffer);
99 
100  VS::UniformBuffer uniforms;
101  uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
102  Matrix::MakeScale(GetContentScale());
103  VS::BindUniformBuffer(cmd,
104  pass.GetTransientsBuffer().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(cmd,
113  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
114  FS::BindContents1(cmd, boston, sampler);
115  FS::BindContents2(cmd, bridge, sampler);
116  if (!pass.AddCommand(std::move(cmd))) {
117  return false;
118  }
119  return true;
120  };
121  OpenPlaygroundHere(callback);
122 }
123 
124 TEST_P(RendererTest, CanRenderPerspectiveCube) {
125  using VS = ColorsVertexShader;
126  using FS = ColorsFragmentShader;
127  auto context = GetContext();
128  ASSERT_TRUE(context);
130  ASSERT_TRUE(desc.has_value());
131  desc->SetCullMode(CullMode::kBackFace);
132  desc->SetWindingOrder(WindingOrder::kCounterClockwise);
133  desc->SetSampleCount(SampleCount::kCount4);
134  desc->SetStencilAttachmentDescriptors(std::nullopt);
135  auto pipeline =
136  context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
137  ASSERT_TRUE(pipeline);
138 
139  struct Cube {
140  VS::PerVertexData vertices[8] = {
141  // -Z
142  {{-1, -1, -1}, Color::Red()},
143  {{1, -1, -1}, Color::Yellow()},
144  {{1, 1, -1}, Color::Green()},
145  {{-1, 1, -1}, Color::Blue()},
146  // +Z
147  {{-1, -1, 1}, Color::Green()},
148  {{1, -1, 1}, Color::Blue()},
149  {{1, 1, 1}, Color::Red()},
150  {{-1, 1, 1}, Color::Yellow()},
151  };
152  uint16_t indices[36] = {
153  1, 5, 2, 2, 5, 6, // +X
154  4, 0, 7, 7, 0, 3, // -X
155  4, 5, 0, 0, 5, 1, // +Y
156  3, 2, 7, 7, 2, 6, // -Y
157  5, 4, 6, 6, 4, 7, // +Z
158  0, 1, 3, 3, 1, 2, // -Z
159  };
160  } cube;
161 
162  VertexBuffer vertex_buffer;
163  {
164  auto device_buffer = context->GetResourceAllocator()->CreateBufferWithCopy(
165  reinterpret_cast<uint8_t*>(&cube), sizeof(cube));
166  vertex_buffer.vertex_buffer = {
167  .buffer = device_buffer,
168  .range = Range(offsetof(Cube, vertices), sizeof(Cube::vertices))};
169  vertex_buffer.index_buffer = {
170  .buffer = device_buffer,
171  .range = Range(offsetof(Cube, indices), sizeof(Cube::indices))};
172  vertex_buffer.vertex_count = 36;
173  vertex_buffer.index_type = IndexType::k16bit;
174  }
175 
176  auto sampler = context->GetSamplerLibrary()->GetSampler({});
177  ASSERT_TRUE(sampler);
178 
179  Vector3 euler_angles;
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  Command cmd;
190  DEBUG_COMMAND_INFO(cmd, "Perspective Cube");
191  cmd.pipeline = pipeline;
192 
193  cmd.BindVertices(vertex_buffer);
194 
195  VS::UniformBuffer uniforms;
196  Scalar time = GetSecondsElapsed();
197  euler_angles = Vector3(0.19 * time, 0.7 * time, 0.43 * time);
198 
199  uniforms.mvp =
200  Matrix::MakePerspective(fov_y, pass.GetRenderTargetSize(), 0, 10) *
201  Matrix::MakeTranslation({0, 0, distance}) *
202  Matrix::MakeRotationX(Radians(euler_angles.x)) *
203  Matrix::MakeRotationY(Radians(euler_angles.y)) *
204  Matrix::MakeRotationZ(Radians(euler_angles.z));
205  VS::BindUniformBuffer(cmd,
206  pass.GetTransientsBuffer().EmplaceUniform(uniforms));
207  if (!pass.AddCommand(std::move(cmd))) {
208  return false;
209  }
210  return true;
211  };
212  OpenPlaygroundHere(callback);
213 }
214 
215 TEST_P(RendererTest, CanRenderMultiplePrimitives) {
216  using VS = BoxFadeVertexShader;
217  using FS = BoxFadeFragmentShader;
218  auto context = GetContext();
219  ASSERT_TRUE(context);
220  using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
221  auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
222  ASSERT_TRUE(desc.has_value());
223  desc->SetSampleCount(SampleCount::kCount4);
224  desc->SetStencilAttachmentDescriptors(std::nullopt);
225  auto box_pipeline =
226  context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
227  ASSERT_TRUE(box_pipeline);
228 
229  // Vertex buffer.
231  vertex_builder.SetLabel("Box");
232  vertex_builder.AddVertices({
233  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
234  {{800, 100, 0.0}, {1.0, 0.0}}, // 2
235  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
236  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
237  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
238  {{100, 800, 0.0}, {0.0, 1.0}}, // 4
239  });
240  auto vertex_buffer =
241  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
242  ASSERT_TRUE(vertex_buffer);
243 
244  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
245  auto boston = CreateTextureForFixture("boston.jpg");
246  ASSERT_TRUE(bridge && boston);
247  auto sampler = context->GetSamplerLibrary()->GetSampler({});
248  ASSERT_TRUE(sampler);
249 
250  SinglePassCallback callback = [&](RenderPass& pass) {
251  Command cmd;
252  DEBUG_COMMAND_INFO(cmd, "Box");
253  cmd.pipeline = box_pipeline;
254 
255  cmd.BindVertices(vertex_buffer);
256 
257  FS::FrameInfo frame_info;
258  frame_info.current_time = GetSecondsElapsed();
259  frame_info.cursor_position = GetCursorPosition();
260  frame_info.window_size.x = GetWindowSize().width;
261  frame_info.window_size.y = GetWindowSize().height;
262 
263  FS::BindFrameInfo(cmd,
264  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
265  FS::BindContents1(cmd, boston, sampler);
266  FS::BindContents2(cmd, bridge, sampler);
267 
268  for (size_t i = 0; i < 1; i++) {
269  for (size_t j = 0; j < 1; j++) {
270  VS::UniformBuffer uniforms;
271  uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
272  Matrix::MakeScale(GetContentScale()) *
273  Matrix::MakeTranslation({i * 50.0f, j * 50.0f, 0.0f});
274  VS::BindUniformBuffer(
275  cmd, pass.GetTransientsBuffer().EmplaceUniform(uniforms));
276  if (!pass.AddCommand(std::move(cmd))) {
277  return false;
278  }
279  }
280  }
281 
282  return true;
283  };
284  OpenPlaygroundHere(callback);
285 }
286 
287 TEST_P(RendererTest, CanRenderToTexture) {
288  using VS = BoxFadeVertexShader;
289  using FS = BoxFadeFragmentShader;
290  auto context = GetContext();
291  ASSERT_TRUE(context);
292  using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
293  auto pipeline_desc =
294  BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
295  pipeline_desc->SetSampleCount(SampleCount::kCount1);
296 
297  ASSERT_TRUE(pipeline_desc.has_value());
298  auto box_pipeline =
299  context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
300  ASSERT_TRUE(box_pipeline);
301 
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  auto sampler = context->GetSamplerLibrary()->GetSampler({});
320  ASSERT_TRUE(sampler);
321  std::shared_ptr<RenderPass> r2t_pass;
322  auto cmd_buffer = context->CreateCommandBuffer();
323  ASSERT_TRUE(cmd_buffer);
324  {
325  ColorAttachment color0;
328 
329  TextureDescriptor texture_descriptor;
330  ASSERT_NE(pipeline_desc->GetColorAttachmentDescriptor(0u), nullptr);
331  texture_descriptor.format =
332  pipeline_desc->GetColorAttachmentDescriptor(0u)->format;
333  texture_descriptor.storage_mode = StorageMode::kHostVisible;
334  texture_descriptor.size = {400, 400};
335  texture_descriptor.mip_count = 1u;
336  texture_descriptor.usage =
338 
339  color0.texture =
340  context->GetResourceAllocator()->CreateTexture(texture_descriptor);
341 
342  ASSERT_TRUE(color0.IsValid());
343 
344  color0.texture->SetLabel("r2t_target");
345 
346  StencilAttachment stencil0;
347  stencil0.load_action = LoadAction::kClear;
349  TextureDescriptor stencil_texture_desc;
350  stencil_texture_desc.storage_mode = StorageMode::kDeviceTransient;
351  stencil_texture_desc.size = texture_descriptor.size;
352  stencil_texture_desc.format = PixelFormat::kS8UInt;
353  stencil_texture_desc.usage =
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  Command cmd;
366  DEBUG_COMMAND_INFO(cmd, "Box");
367  cmd.pipeline = box_pipeline;
368 
369  cmd.BindVertices(vertex_buffer);
370 
371  FS::FrameInfo frame_info;
372  frame_info.current_time = GetSecondsElapsed();
373  frame_info.cursor_position = GetCursorPosition();
374  frame_info.window_size.x = GetWindowSize().width;
375  frame_info.window_size.y = GetWindowSize().height;
376 
377  FS::BindFrameInfo(cmd,
378  r2t_pass->GetTransientsBuffer().EmplaceUniform(frame_info));
379  FS::BindContents1(cmd, boston, sampler);
380  FS::BindContents2(cmd, bridge, sampler);
381 
382  VS::UniformBuffer uniforms;
383  uniforms.mvp = Matrix::MakeOrthographic(ISize{1024, 768}) *
384  Matrix::MakeTranslation({50.0f, 50.0f, 0.0f});
385  VS::BindUniformBuffer(
386  cmd, r2t_pass->GetTransientsBuffer().EmplaceUniform(uniforms));
387  ASSERT_TRUE(r2t_pass->AddCommand(std::move(cmd)));
388  ASSERT_TRUE(r2t_pass->EncodeCommands());
389 }
390 
391 TEST_P(RendererTest, CanRenderInstanced) {
392  if (GetParam() == PlaygroundBackend::kOpenGLES) {
393  GTEST_SKIP_("Instancing is not supported on OpenGL.");
394  }
395  using VS = InstancedDrawVertexShader;
396  using FS = InstancedDrawFragmentShader;
397 
399 
403  PathBuilder{}
404  .AddRect(Rect::MakeXYWH(10, 10, 100, 100))
405  .TakePath()
406  .CreatePolyline(1.0f),
407  [&builder](const float* vertices, size_t vertices_count,
408  const uint16_t* indices, size_t indices_count) {
409  for (auto i = 0u; i < vertices_count * 2; i += 2) {
410  VS::PerVertexData data;
411  data.vtx = {vertices[i], vertices[i + 1]};
412  builder.AppendVertex(data);
413  }
414  for (auto i = 0u; i < indices_count; i++) {
415  builder.AppendIndex(indices[i]);
416  }
417  return true;
418  }));
419 
420  ASSERT_NE(GetContext(), nullptr);
421  auto pipeline =
422  GetContext()
423  ->GetPipelineLibrary()
425  *GetContext())
426  ->SetSampleCount(SampleCount::kCount4)
427  .SetStencilAttachmentDescriptors(std::nullopt))
428 
429  .Get();
430  ASSERT_TRUE(pipeline && pipeline->IsValid());
431 
432  Command cmd;
433  cmd.pipeline = pipeline;
434  DEBUG_COMMAND_INFO(cmd, "InstancedDraw");
435 
436  static constexpr size_t kInstancesCount = 5u;
437  VS::InstanceInfo<kInstancesCount> instances;
438  for (size_t i = 0; i < kInstancesCount; i++) {
439  instances.colors[i] = Color::Random();
440  }
441 
442  ASSERT_TRUE(OpenPlaygroundHere([&](RenderPass& pass) -> bool {
443  VS::FrameInfo frame_info;
444  frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
445  Matrix::MakeScale(GetContentScale());
446  VS::BindFrameInfo(cmd,
447  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
448  VS::BindInstanceInfo(
449  cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(instances));
451 
452  cmd.instance_count = kInstancesCount;
453  pass.AddCommand(std::move(cmd));
454  return true;
455  }));
456 }
457 
458 TEST_P(RendererTest, CanBlitTextureToTexture) {
459  auto context = GetContext();
460  ASSERT_TRUE(context);
461 
462  using VS = MipmapsVertexShader;
463  using FS = MipmapsFragmentShader;
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;
474  texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
475  texture_desc.size = {800, 600};
476  texture_desc.mip_count = 1u;
477  texture_desc.usage =
480  auto texture = context->GetResourceAllocator()->CreateTexture(texture_desc);
481  ASSERT_TRUE(texture);
482 
483  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
484  auto boston = CreateTextureForFixture("boston.jpg");
485  ASSERT_TRUE(bridge && boston);
486  auto sampler = context->GetSamplerLibrary()->GetSampler({});
487  ASSERT_TRUE(sampler);
488 
489  // Vertex buffer.
491  vertex_builder.SetLabel("Box");
492  auto size = Point(boston->GetSize());
493  vertex_builder.AddVertices({
494  {{0, 0}, {0.0, 0.0}}, // 1
495  {{size.x, 0}, {1.0, 0.0}}, // 2
496  {{size.x, size.y}, {1.0, 1.0}}, // 3
497  {{0, 0}, {0.0, 0.0}}, // 1
498  {{size.x, size.y}, {1.0, 1.0}}, // 3
499  {{0, size.y}, {0.0, 1.0}}, // 4
500  });
501  auto vertex_buffer =
502  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
503  ASSERT_TRUE(vertex_buffer);
504 
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  Command cmd;
539  DEBUG_COMMAND_INFO(cmd, "Image");
540  cmd.pipeline = mipmaps_pipeline;
541 
542  cmd.BindVertices(vertex_buffer);
543 
544  VS::FrameInfo frame_info;
545  frame_info.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
546  Matrix::MakeScale(GetContentScale());
547  VS::BindFrameInfo(
548  cmd, pass->GetTransientsBuffer().EmplaceUniform(frame_info));
549 
550  FS::FragInfo frag_info;
551  frag_info.lod = 0;
552  FS::BindFragInfo(cmd,
553  pass->GetTransientsBuffer().EmplaceUniform(frag_info));
554 
555  auto sampler = context->GetSamplerLibrary()->GetSampler({});
556  FS::BindTex(cmd, texture, sampler);
557 
558  pass->AddCommand(std::move(cmd));
559  }
560  pass->EncodeCommands();
561  }
562 
563  if (!buffer->SubmitCommands()) {
564  return false;
565  }
566  return true;
567  };
568  OpenPlaygroundHere(callback);
569 }
570 
571 TEST_P(RendererTest, CanBlitTextureToBuffer) {
572  auto context = GetContext();
573  ASSERT_TRUE(context);
574 
575  using VS = MipmapsVertexShader;
576  using FS = MipmapsFragmentShader;
578  ASSERT_TRUE(desc.has_value());
579  desc->SetSampleCount(SampleCount::kCount4);
580  desc->SetStencilAttachmentDescriptors(std::nullopt);
581  auto mipmaps_pipeline =
582  context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
583  ASSERT_TRUE(mipmaps_pipeline);
584 
585  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
586  auto boston = CreateTextureForFixture("boston.jpg");
587  ASSERT_TRUE(bridge && boston);
588  auto sampler = context->GetSamplerLibrary()->GetSampler({});
589  ASSERT_TRUE(sampler);
590 
591  TextureDescriptor texture_desc;
593  texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
594  texture_desc.size = bridge->GetTextureDescriptor().size;
595  texture_desc.mip_count = 1u;
596  texture_desc.usage =
600  DeviceBufferDescriptor device_buffer_desc;
601  device_buffer_desc.storage_mode = StorageMode::kHostVisible;
602  device_buffer_desc.size =
603  bridge->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
604  auto device_buffer =
605  context->GetResourceAllocator()->CreateBuffer(device_buffer_desc);
606 
607  // Vertex buffer.
609  vertex_builder.SetLabel("Box");
610  auto size = Point(boston->GetSize());
611  vertex_builder.AddVertices({
612  {{0, 0}, {0.0, 0.0}}, // 1
613  {{size.x, 0}, {1.0, 0.0}}, // 2
614  {{size.x, size.y}, {1.0, 1.0}}, // 3
615  {{0, 0}, {0.0, 0.0}}, // 1
616  {{size.x, size.y}, {1.0, 1.0}}, // 3
617  {{0, size.y}, {0.0, 1.0}}, // 4
618  });
619  auto vertex_buffer =
620  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
621  ASSERT_TRUE(vertex_buffer);
622 
623  Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
624  {
625  auto buffer = context->CreateCommandBuffer();
626  if (!buffer) {
627  return false;
628  }
629  buffer->SetLabel("Playground Command Buffer");
630  auto pass = buffer->CreateBlitPass();
631  if (!pass) {
632  return false;
633  }
634  pass->SetLabel("Playground Blit Pass");
635 
636  if (render_target.GetColorAttachments().empty()) {
637  return false;
638  }
639 
640  // Blit `bridge` to the top left corner of the texture.
641  pass->AddCopy(bridge, device_buffer);
642 
643  pass->EncodeCommands(context->GetResourceAllocator());
644 
645  if (!buffer->SubmitCommands()) {
646  return false;
647  }
648  }
649 
650  {
651  auto buffer = context->CreateCommandBuffer();
652  if (!buffer) {
653  return false;
654  }
655  buffer->SetLabel("Playground Command Buffer");
656 
657  auto pass = buffer->CreateRenderPass(render_target);
658  if (!pass) {
659  return false;
660  }
661  pass->SetLabel("Playground Render Pass");
662  {
663  Command cmd;
664  DEBUG_COMMAND_INFO(cmd, "Image");
665  cmd.pipeline = mipmaps_pipeline;
666 
667  cmd.BindVertices(vertex_buffer);
668 
669  VS::FrameInfo frame_info;
670  frame_info.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
671  Matrix::MakeScale(GetContentScale());
672  VS::BindFrameInfo(
673  cmd, pass->GetTransientsBuffer().EmplaceUniform(frame_info));
674 
675  FS::FragInfo frag_info;
676  frag_info.lod = 0;
677  FS::BindFragInfo(cmd,
678  pass->GetTransientsBuffer().EmplaceUniform(frag_info));
679 
680  auto sampler = context->GetSamplerLibrary()->GetSampler({});
681  auto buffer_view = device_buffer->AsBufferView();
682  auto texture =
683  context->GetResourceAllocator()->CreateTexture(texture_desc);
684  if (!texture->SetContents(buffer_view.contents,
685  buffer_view.range.length)) {
686  VALIDATION_LOG << "Could not upload texture to device memory";
687  return false;
688  }
689  FS::BindTex(cmd, texture, sampler);
690 
691  pass->AddCommand(std::move(cmd));
692  }
693  pass->EncodeCommands();
694  if (!buffer->SubmitCommands()) {
695  return false;
696  }
697  }
698  return true;
699  };
700  OpenPlaygroundHere(callback);
701 }
702 
703 TEST_P(RendererTest, CanGenerateMipmaps) {
704  auto context = GetContext();
705  ASSERT_TRUE(context);
706 
707  using VS = MipmapsVertexShader;
708  using FS = MipmapsFragmentShader;
710  ASSERT_TRUE(desc.has_value());
711  desc->SetSampleCount(SampleCount::kCount4);
712  desc->SetStencilAttachmentDescriptors(std::nullopt);
713  auto mipmaps_pipeline =
714  context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
715  ASSERT_TRUE(mipmaps_pipeline);
716 
717  auto boston = CreateTextureForFixture("boston.jpg", true);
718  ASSERT_TRUE(boston);
719 
720  // Vertex buffer.
722  vertex_builder.SetLabel("Box");
723  auto size = Point(boston->GetSize());
724  vertex_builder.AddVertices({
725  {{0, 0}, {0.0, 0.0}}, // 1
726  {{size.x, 0}, {1.0, 0.0}}, // 2
727  {{size.x, size.y}, {1.0, 1.0}}, // 3
728  {{0, 0}, {0.0, 0.0}}, // 1
729  {{size.x, size.y}, {1.0, 1.0}}, // 3
730  {{0, size.y}, {0.0, 1.0}}, // 4
731  });
732  auto vertex_buffer =
733  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
734  ASSERT_TRUE(vertex_buffer);
735 
736  bool first_frame = true;
737  Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
738  const char* mip_filter_names[] = {"Nearest", "Linear"};
739  const MipFilter mip_filters[] = {MipFilter::kNearest, MipFilter::kLinear};
740  const char* min_filter_names[] = {"Nearest", "Linear"};
741  const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
743 
744  // UI state.
745  static int selected_mip_filter = 1;
746  static int selected_min_filter = 0;
747  static float lod = 4.5;
748 
749  ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
750  ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names,
751  sizeof(mip_filter_names) / sizeof(char*));
752  ImGui::Combo("Min filter", &selected_min_filter, min_filter_names,
753  sizeof(min_filter_names) / sizeof(char*));
754  ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1);
755  ImGui::End();
756 
757  auto buffer = context->CreateCommandBuffer();
758  if (!buffer) {
759  return false;
760  }
761  buffer->SetLabel("Playground Command Buffer");
762 
763  if (first_frame) {
764  auto pass = buffer->CreateBlitPass();
765  if (!pass) {
766  return false;
767  }
768  pass->SetLabel("Playground Blit Pass");
769 
770  pass->GenerateMipmap(boston, "Boston Mipmap");
771 
772  pass->EncodeCommands(context->GetResourceAllocator());
773  }
774 
775  first_frame = false;
776 
777  {
778  auto pass = buffer->CreateRenderPass(render_target);
779  if (!pass) {
780  return false;
781  }
782  pass->SetLabel("Playground Render Pass");
783  {
784  Command cmd;
785  DEBUG_COMMAND_INFO(cmd, "Image LOD");
786  cmd.pipeline = mipmaps_pipeline;
787 
788  cmd.BindVertices(vertex_buffer);
789 
790  VS::FrameInfo frame_info;
791  frame_info.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
792  Matrix::MakeScale(GetContentScale());
793  VS::BindFrameInfo(
794  cmd, pass->GetTransientsBuffer().EmplaceUniform(frame_info));
795 
796  FS::FragInfo frag_info;
797  frag_info.lod = lod;
798  FS::BindFragInfo(cmd,
799  pass->GetTransientsBuffer().EmplaceUniform(frag_info));
800 
801  SamplerDescriptor sampler_desc;
802  sampler_desc.mip_filter = mip_filters[selected_mip_filter];
803  sampler_desc.min_filter = min_filters[selected_min_filter];
804  auto sampler = context->GetSamplerLibrary()->GetSampler(sampler_desc);
805  FS::BindTex(cmd, boston, sampler);
806 
807  pass->AddCommand(std::move(cmd));
808  }
809  pass->EncodeCommands();
810  }
811 
812  if (!buffer->SubmitCommands()) {
813  return false;
814  }
815  return true;
816  };
817  OpenPlaygroundHere(callback);
818 }
819 
820 TEST_P(RendererTest, TheImpeller) {
821  using VS = ImpellerVertexShader;
822  using FS = ImpellerFragmentShader;
823 
824  auto context = GetContext();
825  auto pipeline_descriptor =
827  ASSERT_TRUE(pipeline_descriptor.has_value());
828  pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
829  pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
830  auto pipeline =
831  context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
832  ASSERT_TRUE(pipeline && pipeline->IsValid());
833 
834  auto blue_noise = CreateTextureForFixture("blue_noise.png");
835  SamplerDescriptor noise_sampler_desc;
836  noise_sampler_desc.width_address_mode = SamplerAddressMode::kRepeat;
838  auto noise_sampler =
839  context->GetSamplerLibrary()->GetSampler(noise_sampler_desc);
840 
841  auto cube_map = CreateTextureCubeForFixture(
842  {"table_mountain_px.png", "table_mountain_nx.png",
843  "table_mountain_py.png", "table_mountain_ny.png",
844  "table_mountain_pz.png", "table_mountain_nz.png"});
845  auto cube_map_sampler = context->GetSamplerLibrary()->GetSampler({});
846 
847  SinglePassCallback callback = [&](RenderPass& pass) {
848  auto size = pass.GetRenderTargetSize();
849 
850  Command cmd;
851  cmd.pipeline = pipeline;
852  DEBUG_COMMAND_INFO(cmd, "Impeller SDF scene");
854  builder.AddVertices({{Point()},
855  {Point(0, size.height)},
856  {Point(size.width, 0)},
857  {Point(size.width, 0)},
858  {Point(0, size.height)},
859  {Point(size.width, size.height)}});
860  cmd.BindVertices(builder.CreateVertexBuffer(pass.GetTransientsBuffer()));
861 
862  VS::FrameInfo frame_info;
863  frame_info.mvp = Matrix::MakeOrthographic(size);
864  VS::BindFrameInfo(cmd,
865  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
866 
867  FS::FragInfo fs_uniform;
868  fs_uniform.texture_size = Point(size);
869  fs_uniform.time = GetSecondsElapsed();
870  FS::BindFragInfo(cmd,
871  pass.GetTransientsBuffer().EmplaceUniform(fs_uniform));
872  FS::BindBlueNoise(cmd, blue_noise, noise_sampler);
873  FS::BindCubeMap(cmd, cube_map, cube_map_sampler);
874 
875  pass.AddCommand(std::move(cmd));
876  return true;
877  };
878  OpenPlaygroundHere(callback);
879 }
880 
881 TEST_P(RendererTest, ArrayUniforms) {
882  using VS = ArrayVertexShader;
883  using FS = ArrayFragmentShader;
884 
885  auto context = GetContext();
886  auto pipeline_descriptor =
888  ASSERT_TRUE(pipeline_descriptor.has_value());
889  pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
890  pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
891  auto pipeline =
892  context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
893  ASSERT_TRUE(pipeline && pipeline->IsValid());
894 
895  SinglePassCallback callback = [&](RenderPass& pass) {
896  auto size = pass.GetRenderTargetSize();
897 
898  Command cmd;
899  cmd.pipeline = pipeline;
900  DEBUG_COMMAND_INFO(cmd, "Google Dots");
902  builder.AddVertices({{Point()},
903  {Point(0, size.height)},
904  {Point(size.width, 0)},
905  {Point(size.width, 0)},
906  {Point(0, size.height)},
907  {Point(size.width, size.height)}});
908  cmd.BindVertices(builder.CreateVertexBuffer(pass.GetTransientsBuffer()));
909 
910  VS::FrameInfo frame_info;
911  frame_info.mvp =
912  Matrix::MakeOrthographic(size) * Matrix::MakeScale(GetContentScale());
913  VS::BindFrameInfo(cmd,
914  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
915 
916  auto time = GetSecondsElapsed();
917  auto y_pos = [&time](float x) {
918  return 400 + 10 * std::cos(time * 5 + x / 6);
919  };
920 
921  FS::FragInfo fs_uniform = {
922  .circle_positions = {Point(430, y_pos(0)), Point(480, y_pos(1)),
923  Point(530, y_pos(2)), Point(580, y_pos(3))},
924  .colors = {Color::MakeRGBA8(66, 133, 244, 255),
925  Color::MakeRGBA8(219, 68, 55, 255),
926  Color::MakeRGBA8(244, 180, 0, 255),
927  Color::MakeRGBA8(15, 157, 88, 255)},
928  };
929  FS::BindFragInfo(cmd,
930  pass.GetTransientsBuffer().EmplaceUniform(fs_uniform));
931 
932  pass.AddCommand(std::move(cmd));
933  return true;
934  };
935  OpenPlaygroundHere(callback);
936 }
937 
938 TEST_P(RendererTest, InactiveUniforms) {
939  using VS = InactiveUniformsVertexShader;
940  using FS = InactiveUniformsFragmentShader;
941 
942  auto context = GetContext();
943  auto pipeline_descriptor =
945  ASSERT_TRUE(pipeline_descriptor.has_value());
946  pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
947  pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
948  auto pipeline =
949  context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
950  ASSERT_TRUE(pipeline && pipeline->IsValid());
951 
952  SinglePassCallback callback = [&](RenderPass& pass) {
953  auto size = pass.GetRenderTargetSize();
954 
955  Command cmd;
956  cmd.pipeline = pipeline;
957  DEBUG_COMMAND_INFO(cmd, "Inactive Uniform");
959  builder.AddVertices({{Point()},
960  {Point(0, size.height)},
961  {Point(size.width, 0)},
962  {Point(size.width, 0)},
963  {Point(0, size.height)},
964  {Point(size.width, size.height)}});
965  cmd.BindVertices(builder.CreateVertexBuffer(pass.GetTransientsBuffer()));
966 
967  VS::FrameInfo frame_info;
968  frame_info.mvp =
969  Matrix::MakeOrthographic(size) * Matrix::MakeScale(GetContentScale());
970  VS::BindFrameInfo(cmd,
971  pass.GetTransientsBuffer().EmplaceUniform(frame_info));
972 
973  FS::FragInfo fs_uniform = {.unused_color = Color::Red(),
974  .color = Color::Green()};
975  FS::BindFragInfo(cmd,
976  pass.GetTransientsBuffer().EmplaceUniform(fs_uniform));
977 
978  pass.AddCommand(std::move(cmd));
979  return true;
980  };
981  OpenPlaygroundHere(callback);
982 }
983 
984 TEST_P(RendererTest, CanCreateCPUBackedTexture) {
985  if (GetParam() == PlaygroundBackend::kOpenGLES) {
986  GTEST_SKIP_("CPU backed textures are not supported on OpenGLES.");
987  }
988 
989  auto context = GetContext();
990  auto allocator = context->GetResourceAllocator();
991  size_t dimension = 2;
992 
993  do {
994  ISize size(dimension, dimension);
995  TextureDescriptor texture_descriptor;
996  texture_descriptor.storage_mode = StorageMode::kHostVisible;
997  texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
998  texture_descriptor.size = size;
999  auto row_bytes =
1000  std::max(static_cast<uint16_t>(size.width * 4),
1001  allocator->MinimumBytesPerRow(texture_descriptor.format));
1002  auto buffer_size = size.height * row_bytes;
1003 
1004  DeviceBufferDescriptor buffer_descriptor;
1005  buffer_descriptor.storage_mode = StorageMode::kHostVisible;
1006  buffer_descriptor.size = buffer_size;
1007 
1008  auto buffer = allocator->CreateBuffer(buffer_descriptor);
1009 
1010  ASSERT_TRUE(buffer);
1011 
1012  auto texture = buffer->AsTexture(*allocator, texture_descriptor, row_bytes);
1013 
1014  ASSERT_TRUE(texture);
1015  ASSERT_TRUE(texture->IsValid());
1016 
1017  dimension *= 2;
1018  } while (dimension <= 8192);
1019 }
1020 
1021 TEST_P(RendererTest, DefaultIndexSize) {
1022  using VS = BoxFadeVertexShader;
1023 
1024  // Default to 16bit index buffer size, as this is a reasonable default and
1025  // supported on all backends without extensions.
1027  vertex_builder.AppendIndex(0u);
1028  ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::k16bit);
1029 }
1030 
1031 TEST_P(RendererTest, DefaultIndexBehavior) {
1032  using VS = BoxFadeVertexShader;
1033 
1034  // Do not create any index buffer if no indices were provided.
1036  ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1037 }
1038 
1040  // Does not create index buffer if one is provided.
1041  using VS = BoxFadeVertexShader;
1043  vertex_builder.SetLabel("Box");
1044  vertex_builder.AddVertices({
1045  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1046  {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1047  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1048  {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1049  });
1050  vertex_builder.AppendIndex(0);
1051  vertex_builder.AppendIndex(1);
1052  vertex_builder.AppendIndex(2);
1053  vertex_builder.AppendIndex(1);
1054  vertex_builder.AppendIndex(2);
1055  vertex_builder.AppendIndex(3);
1056 
1057  ASSERT_EQ(vertex_builder.GetIndexCount(), 6u);
1058  ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
1059 }
1060 
1062  public:
1064  labels_.push_back("Never");
1065  functions_.push_back(CompareFunction::kNever);
1066  labels_.push_back("Always");
1067  functions_.push_back(CompareFunction::kAlways);
1068  labels_.push_back("Less");
1069  functions_.push_back(CompareFunction::kLess);
1070  labels_.push_back("Equal");
1071  functions_.push_back(CompareFunction::kEqual);
1072  labels_.push_back("LessEqual");
1073  functions_.push_back(CompareFunction::kLessEqual);
1074  labels_.push_back("Greater");
1075  functions_.push_back(CompareFunction::kGreater);
1076  labels_.push_back("NotEqual");
1077  functions_.push_back(CompareFunction::kNotEqual);
1078  labels_.push_back("GreaterEqual");
1079  functions_.push_back(CompareFunction::kGreaterEqual);
1080  assert(labels_.size() == functions_.size());
1081  }
1082 
1083  const char* const* labels() const { return &labels_[0]; }
1084 
1085  int size() const { return labels_.size(); }
1086 
1087  int IndexOf(CompareFunction func) const {
1088  for (size_t i = 0; i < functions_.size(); i++) {
1089  if (functions_[i] == func) {
1090  return i;
1091  }
1092  }
1093  FML_UNREACHABLE();
1094  return -1;
1095  }
1096 
1097  CompareFunction FunctionOf(int index) const { return functions_[index]; }
1098 
1099  private:
1100  std::vector<const char*> labels_;
1101  std::vector<CompareFunction> functions_;
1102 };
1103 
1105  static CompareFunctionUIData data;
1106  return data;
1107 }
1108 
1109 TEST_P(RendererTest, StencilMask) {
1110  using VS = BoxFadeVertexShader;
1111  using FS = BoxFadeFragmentShader;
1112  auto context = GetContext();
1113  ASSERT_TRUE(context);
1114  using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1115  auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1116  ASSERT_TRUE(desc.has_value());
1117 
1118  // Vertex buffer.
1120  vertex_builder.SetLabel("Box");
1121  vertex_builder.AddVertices({
1122  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1123  {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1124  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1125  {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1126  {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1127  {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1128  });
1129  auto vertex_buffer =
1130  vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
1131  ASSERT_TRUE(vertex_buffer);
1132 
1133  desc->SetSampleCount(SampleCount::kCount4);
1134  desc->SetStencilAttachmentDescriptors(std::nullopt);
1135 
1136  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
1137  auto boston = CreateTextureForFixture("boston.jpg");
1138  ASSERT_TRUE(bridge && boston);
1139  auto sampler = context->GetSamplerLibrary()->GetSampler({});
1140  ASSERT_TRUE(sampler);
1141 
1142  static bool mirror = false;
1143  static int stencil_reference_write = 0xFF;
1144  static int stencil_reference_read = 0x1;
1145  std::vector<uint8_t> stencil_contents;
1146  static int last_stencil_contents_reference_value = 0;
1147  static int current_front_compare =
1149  static int current_back_compare =
1151  Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
1152  auto buffer = context->CreateCommandBuffer();
1153  if (!buffer) {
1154  return false;
1155  }
1156  buffer->SetLabel("Playground Command Buffer");
1157 
1158  {
1159  // Configure the stencil attachment for the test.
1160  RenderTarget::AttachmentConfig stencil_config;
1161  stencil_config.load_action = LoadAction::kLoad;
1162  stencil_config.store_action = StoreAction::kDontCare;
1163  stencil_config.storage_mode = StorageMode::kHostVisible;
1164  auto render_target_allocator =
1165  RenderTargetAllocator(context->GetResourceAllocator());
1166  render_target.SetupStencilAttachment(*context, render_target_allocator,
1167  render_target.GetRenderTargetSize(),
1168  true, "stencil", stencil_config);
1169  // Fill the stencil buffer with an checkerboard pattern.
1170  const auto target_width = render_target.GetRenderTargetSize().width;
1171  const auto target_height = render_target.GetRenderTargetSize().height;
1172  const size_t target_size = target_width * target_height;
1173  if (stencil_contents.size() != target_size ||
1174  last_stencil_contents_reference_value != stencil_reference_write) {
1175  stencil_contents.resize(target_size);
1176  last_stencil_contents_reference_value = stencil_reference_write;
1177  for (int y = 0; y < target_height; y++) {
1178  for (int x = 0; x < target_width; x++) {
1179  const auto index = y * target_width + x;
1180  const auto kCheckSize = 64;
1181  const auto value =
1182  (((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
1183  stencil_reference_write;
1184  stencil_contents[index] = value;
1185  }
1186  }
1187  }
1188  if (!render_target.GetStencilAttachment()->texture->SetContents(
1189  stencil_contents.data(), stencil_contents.size(), 0, false)) {
1190  VALIDATION_LOG << "Could not upload stencil contents to device memory";
1191  return false;
1192  }
1193  auto pass = buffer->CreateRenderPass(render_target);
1194  if (!pass) {
1195  return false;
1196  }
1197  pass->SetLabel("Stencil Buffer");
1198  ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1199  ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
1200  0xFF);
1201  ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
1202  0xFF);
1203  ImGui::Checkbox("Back face mode", &mirror);
1204  ImGui::ListBox("Front face compare function", &current_front_compare,
1205  CompareFunctionUI().labels(), CompareFunctionUI().size());
1206  ImGui::ListBox("Back face compare function", &current_back_compare,
1207  CompareFunctionUI().labels(), CompareFunctionUI().size());
1208  ImGui::End();
1209 
1211  front.stencil_compare =
1212  CompareFunctionUI().FunctionOf(current_front_compare);
1214  back.stencil_compare =
1215  CompareFunctionUI().FunctionOf(current_back_compare);
1216  desc->SetStencilAttachmentDescriptors(front, back);
1217  auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
1218 
1219  assert(pipeline && pipeline->IsValid());
1220 
1221  Command cmd;
1222  DEBUG_COMMAND_INFO(cmd, "Box");
1223  cmd.pipeline = pipeline;
1224  cmd.stencil_reference = stencil_reference_read;
1225 
1226  cmd.BindVertices(vertex_buffer);
1227 
1228  VS::UniformBuffer uniforms;
1229  uniforms.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
1230  Matrix::MakeScale(GetContentScale());
1231  if (mirror) {
1232  uniforms.mvp = Matrix::MakeScale(Vector2(-1, 1)) * uniforms.mvp;
1233  }
1234  VS::BindUniformBuffer(
1235  cmd, pass->GetTransientsBuffer().EmplaceUniform(uniforms));
1236 
1237  FS::FrameInfo frame_info;
1238  frame_info.current_time = GetSecondsElapsed();
1239  frame_info.cursor_position = GetCursorPosition();
1240  frame_info.window_size.x = GetWindowSize().width;
1241  frame_info.window_size.y = GetWindowSize().height;
1242 
1243  FS::BindFrameInfo(cmd,
1244  pass->GetTransientsBuffer().EmplaceUniform(frame_info));
1245  FS::BindContents1(cmd, boston, sampler);
1246  FS::BindContents2(cmd, bridge, sampler);
1247  if (!pass->AddCommand(std::move(cmd))) {
1248  return false;
1249  }
1250  pass->EncodeCommands();
1251  }
1252 
1253  if (!buffer->SubmitCommands()) {
1254  return false;
1255  }
1256  return true;
1257  };
1258  OpenPlaygroundHere(callback);
1259 }
1260 
1261 } // namespace testing
1262 } // namespace impeller
1263 
1264 // NOLINTEND(bugprone-unchecked-optional-access)
impeller::Color::Blue
static constexpr Color Blue()
Definition: color.h:266
impeller::Command
An object used to specify work to the GPU along with references to resources the GPU will used when d...
Definition: command.h:99
impeller::VertexBuffer::index_type
IndexType index_type
Definition: vertex_buffer.h:18
DEBUG_COMMAND_INFO
#define DEBUG_COMMAND_INFO(obj, arg)
Definition: command.h:31
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:181
impeller::RenderTarget::AttachmentConfig::store_action
StoreAction store_action
Definition: render_target.h:53
impeller::testing::CompareFunctionUI
static const CompareFunctionUIData & CompareFunctionUI()
Definition: renderer_unittests.cc:1104
impeller::LoadAction::kLoad
@ kLoad
impeller::RenderTarget::AttachmentConfig::load_action
LoadAction load_action
Definition: render_target.h:52
impeller::TextureUsageMask
uint64_t TextureUsageMask
Definition: formats.h:274
impeller::IndexType::k16bit
@ k16bit
impeller::Attachment::store_action
StoreAction store_action
Definition: formats.h:594
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::StencilAttachmentDescriptor::stencil_compare
CompareFunction stencil_compare
Definition: formats.h:550
impeller::CompareFunction::kGreater
@ kGreater
Comparison test passes if new_value > current_value.
sampler_library.h
impeller::testing::CompareFunctionUIData::IndexOf
int IndexOf(CompareFunction func) const
Definition: renderer_unittests.cc:1087
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:44
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:262
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:47
impeller::Tessellator
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Definition: tessellator.h:35
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:152
impeller::testing::CompareFunctionUIData
Definition: renderer_unittests.cc:1061
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:13
impeller::Renderer::RenderCallback
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition: renderer.h:25
impeller::VertexBufferBuilder::GetVertexCount
size_t GetVertexCount() const
Definition: vertex_buffer_builder.h:53
impeller::ColorAttachment
Definition: formats.h:599
impeller::CompareFunction::kNotEqual
@ kNotEqual
Comparison test passes if new_value != current_value.
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:42
impeller::RenderTarget::SetColorAttachment
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
Definition: render_target.cc:180
impeller::VertexBuffer
Definition: vertex_buffer.h:12
formats.h
impeller::PathBuilder
Definition: path_builder.h:13
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:44
impeller::Vector2
Point Vector2
Definition: point.h:310
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:194
impeller::SampleCount::kCount1
@ kCount1
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::StoreAction::kDontCare
@ kDontCare
impeller::DeviceBufferDescriptor::size
size_t size
Definition: device_buffer_descriptor.h:15
impeller::VertexBufferBuilder::AddVertices
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
Definition: vertex_buffer_builder.h:64
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::Color::Yellow
static constexpr Color Yellow()
Definition: color.h:832
impeller::VertexBuffer::vertex_buffer
BufferView vertex_buffer
Definition: vertex_buffer.h:13
impeller::StorageMode::kHostVisible
@ kHostVisible
pipeline_builder.h
impeller::VertexBuffer::vertex_count
size_t vertex_count
Definition: vertex_buffer.h:17
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:94
impeller::Command::instance_count
size_t instance_count
Definition: command.h:177
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:45
impeller::Vector3::x
Scalar x
Definition: vector.h:20
impeller::SampleCount::kCount4
@ kCount4
sampler.h
impeller::PolygonMode::kFill
@ kFill
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:181
impeller::FillType::kPositive
@ kPositive
impeller::testing::CompareFunctionUIData::CompareFunctionUIData
CompareFunctionUIData()
Definition: renderer_unittests.cc:1063
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:457
impeller::RenderTarget::AttachmentConfig
Definition: render_target.h:50
tessellator.h
path_builder.h
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:18
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
surface.h
command.h
impeller::StencilAttachment
Definition: formats.h:607
impeller::MipFilter::kNearest
@ kNearest
Sample from the nearest mip level.
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:30
impeller::testing::TEST_P
TEST_P(AiksTest, RotateColorFilteredPath)
Definition: aiks_unittests.cc:56
impeller::TSize< int64_t >
impeller::LoadAction::kClear
@ kClear
impeller::SamplerDescriptor::min_filter
MinMagFilter min_filter
Definition: sampler_descriptor.h:19
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::Point
TPoint< Scalar > Point
Definition: point.h:306
impeller::CullMode::kBackFace
@ kBackFace
impeller::testing::CompareFunctionUIData::FunctionOf
CompareFunction FunctionOf(int index) const
Definition: renderer_unittests.cc:1097
impeller::MipFilter
MipFilter
Definition: formats.h:369
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:591
impeller::VertexBufferBuilder
Definition: vertex_buffer_builder.h:23
impeller::MinMagFilter::kLinear
@ kLinear
impeller::BufferView::buffer
std::shared_ptr< const Buffer > buffer
Definition: buffer_view.h:14
impeller::DeviceBufferDescriptor::storage_mode
StorageMode storage_mode
Definition: device_buffer_descriptor.h:14
impeller::Color::Random
static Color Random()
Definition: color.h:840
impeller::SamplerDescriptor::width_address_mode
SamplerAddressMode width_address_mode
Definition: sampler_descriptor.h:23
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::CompareFunction::kNever
@ kNever
Comparison test never passes.
impeller::WindingOrder::kCounterClockwise
@ kCounterClockwise
impeller::Vector3::z
Scalar z
Definition: vector.h:22
impeller::VertexBufferBuilder::GetIndexCount
size_t GetIndexCount() const
Definition: vertex_buffer_builder.h:55
impeller::Radians
Definition: scalar.h:35
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:51
impeller::MinMagFilter
MinMagFilter
Definition: formats.h:361
impeller::testing::CompareFunctionUIData::size
int size() const
Definition: renderer_unittests.cc:1085
impeller::RenderTarget
Definition: render_target.h:48
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:264
impeller::StoreAction::kStore
@ kStore
strings.h
impeller::Vector3::y
Scalar y
Definition: vector.h:21
impeller::RenderTargetAllocator
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
Definition: render_target.h:22
impeller::VertexBufferBuilder::AppendIndex
VertexBufferBuilder & AppendIndex(IndexType_ index)
Definition: vertex_buffer_builder.h:73
impeller::TSize::width
Type width
Definition: size.h:21
impeller::SamplerDescriptor::mip_filter
MipFilter mip_filter
Definition: sampler_descriptor.h:21
impeller::VertexBufferBuilder::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
Definition: vertex_buffer_builder.h:78
pipeline_library.h
impeller::CompareFunction::kLess
@ kLess
Comparison test passes if new_value < current_value.
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:27
decompressed_image.h
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:43
sampler_descriptor.h
impeller::VertexBuffer::index_buffer
BufferView index_buffer
Definition: vertex_buffer.h:14
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
command_buffer.h
impeller::Command::stencil_reference
uint32_t stencil_reference
Definition: command.h:152
impeller::VertexBufferBuilder::GetIndexType
constexpr impeller::IndexType GetIndexType() const
Definition: vertex_buffer_builder.h:32
impeller::CompareFunction::kGreaterEqual
@ kGreaterEqual
Comparison test passes if new_value >= current_value.
impeller::PlaygroundBackend::kOpenGLES
@ kOpenGLES
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:208
impeller::Tessellator::Tessellate
Tessellator::Result Tessellate(FillType fill_type, const Path::Polyline &polyline, const BuilderCallback &callback) const
Generates filled triangles from the polyline. A callback is invoked once for the entire tessellation.
Definition: tessellator.cc:61
impeller::Range
Definition: range.h:13
impeller::CompareFunction
CompareFunction
Definition: formats.h:486
impeller::PipelineBuilder::MakeDefaultPipelineDescriptor
static std::optional< PipelineDescriptor > MakeDefaultPipelineDescriptor(const Context &context)
Create a default pipeline descriptor using the combination reflected shader information....
Definition: pipeline_builder.h:50
impeller::CompareFunction::kAlways
@ kAlways
Comparison test passes always passes.
impeller::RenderTarget::SetStencilAttachment
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
Definition: render_target.cc:199
impeller::VertexBufferBuilder::SetLabel
void SetLabel(std::string label)
Definition: vertex_buffer_builder.h:45
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::StencilAttachmentDescriptor
Definition: formats.h:544
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:593
impeller::MipFilter::kLinear
@ kLinear
impeller::HostBuffer::EmplaceUniform
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:43
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:448
impeller::VertexBufferBuilder::AppendVertex
VertexBufferBuilder & AppendVertex(VertexType_ vertex)
Definition: vertex_buffer_builder.h:59
impeller::Attachment::IsValid
bool IsValid() const
Definition: formats.cc:26
impeller::Degrees
Definition: scalar.h:43
impeller::CompareFunction::kEqual
@ kEqual
Comparison test passes if new_value == current_value.
impeller::PolygonMode::kLine
@ kLine
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:40
impeller::TSize::height
Type height
Definition: size.h:22
impeller::HostBuffer::EmplaceStorageBuffer
BufferView EmplaceStorageBuffer(const StorageBufferType &buffer)
Emplace storage buffer data onto the host buffer. Ensure that backend specific uniform alignment requ...
Definition: host_buffer.h:65
impeller::PlaygroundTest
Definition: playground_test.h:22
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:39
impeller::Command::BindVertices
bool BindVertices(const VertexBuffer &buffer)
Specify the vertex and index buffer to use for this command.
Definition: command.cc:15
impeller::Command::pipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > pipeline
Definition: command.h:103
impeller::PipelineBuilder
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
Definition: pipeline_builder.h:31
renderer.h
impeller::SamplerDescriptor::height_address_mode
SamplerAddressMode height_address_mode
Definition: sampler_descriptor.h:24
impeller::CompareFunction::kLessEqual
@ kLessEqual
Comparison test passes if new_value <= current_value.
impeller::TextureUsage::kShaderWrite
@ kShaderWrite
impeller::RenderPass::AddCommand
bool AddCommand(Command &&command)
Record a command for subsequent encoding to the underlying command buffer. No work is encoded into th...
Definition: render_pass.cc:46
impeller
Definition: aiks_context.cc:10
playground_test.h
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:103
impeller::testing::CompareFunctionUIData::labels
const char *const * labels() const
Definition: renderer_unittests.cc:1083
compressed_image.h
impeller::RenderPass::GetTransientsBuffer
HostBuffer & GetTransientsBuffer()
Definition: render_pass.cc:34
impeller::Vector3
Definition: vector.h:17
vertex_buffer_builder.h
impeller::SamplerAddressMode::kRepeat
@ kRepeat