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