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