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"
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"
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;
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.
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);
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) *
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.
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 
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;
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;
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 
395 
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()
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(),
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;
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;
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.
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;
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;
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 |
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.
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;
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.
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,
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 =
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;
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");
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 =
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");
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 =
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 
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.
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.
1043  ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1044 }
1045 
1047  // Does not create index buffer if one is provided.
1048  using VS = BoxFadeVertexShader;
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 
1069  public:
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 
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.
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 =
1157  static int current_back_compare =
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 
1219  front.stencil_compare =
1220  CompareFunctionUI().FunctionOf(current_front_compare);
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 
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.
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 
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.
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 
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