| 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"
7 #include "impeller/core/device_buffer_descriptor.h"
8 #include "impeller/core/formats.h"
9 #include "impeller/core/host_buffer.h"
10 #include "impeller/core/sampler_descriptor.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"
34 #include "impeller/geometry/path_builder.h"
35 #include "impeller/playground/playground.h"
36 #include "impeller/playground/playground_test.h"
37 #include "impeller/renderer/command_buffer.h"
38 #include "impeller/renderer/pipeline_builder.h"
39 #include "impeller/renderer/pipeline_library.h"
40 #include "impeller/renderer/render_pass.h"
41 #include "impeller/renderer/render_target.h"
42 #include "impeller/renderer/vertex_buffer_builder.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;
52 INSTANTIATE_PLAYGROUND_SUITE(RendererTest);
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.
66 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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.
136 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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);
181 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*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) *
253 Matrix::MakeTranslation({0, 0, distance}) *
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.
280 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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
356 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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;
382 color0.load_action = LoadAction::kClear;
383 color0.store_action = StoreAction::kStore;
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;
403 stencil0.store_action = StoreAction::kDontCare;
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
448 VertexBufferBuilder<VS::PerVertexData> builder;
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()
462 ->GetPipeline(PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(
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(),
483 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
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;
507 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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;
516 texture_desc.storage_mode = StorageMode::kHostVisible;
517 texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
518 texture_desc.size = {800, 600};
519 texture_desc.mip_count = 1u;
520 texture_desc.usage = TextureUsage::kRenderTarget | TextureUsage::kShaderRead;
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.
532 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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 Playground::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;
622 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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;
638 texture_desc.storage_mode = StorageMode::kHostVisible;
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 |
643 TextureUsage::kShaderWrite | TextureUsage::kShaderRead;
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.
652 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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 Playground::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;
756 auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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.
768 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
786 const char* mip_filter_names[] = {"Base", "Nearest", "Linear"};
787 const MipFilter mip_filters[] = {MipFilter::kBase, MipFilter::kNearest,
788 MipFilter::kLinear};
789 const char* min_filter_names[] = {"Nearest", "Linear"};
790 const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
791 MinMagFilter::kLinear};
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 =
875 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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;
886 noise_sampler_desc.height_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");
903 VertexBufferBuilder<VS::PerVertexData> builder;
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
931 TEST_P(RendererTest, Planet) {
932 using VS = PlanetVertexShader;
933 using FS = PlanetFragmentShader;
934
935 auto context = GetContext();
936 auto pipeline_descriptor =
937 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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");
966 VertexBufferBuilder<VS::PerVertexData> builder;
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 =
1003 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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");
1017 VertexBufferBuilder<VS::PerVertexData> builder;
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 =
1060 PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
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
1075 VertexBufferBuilder<VS::PerVertexData> builder;
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.
1106 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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.
1115 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1116 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1117 }
1118
1119 TEST_P(RendererTest, VertexBufferBuilder) {
1120 // Does not create index buffer if one is provided.
1121 using VS = BoxFadeVertexShader;
1122 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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
1141 class CompareFunctionUIData {
1142 public:
1143 CompareFunctionUIData() {
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
1184 static const CompareFunctionUIData& CompareFunctionUI() {
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.
1199 VertexBufferBuilder<VS::PerVertexData> vertex_builder;
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 =
1229 CompareFunctionUI().IndexOf(CompareFunction::kLessEqual);
1230 static int current_back_compare =
1231 CompareFunctionUI().IndexOf(CompareFunction::kLessEqual);
1232
1233 auto host_buffer = HostBuffer::Create(context->GetResourceAllocator());
1234 Playground::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
1291 StencilAttachmentDescriptor front;
1292 front.stencil_compare =
1293 CompareFunctionUI().FunctionOf(current_front_compare);
1294 StencilAttachmentDescriptor back;
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
1361 TEST_P(RendererTest,
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 // Define shader types
1396 using TextureVS = TextureVertexShader;
1397 using TextureFS = TextureFragmentShader;
1398
1399 using SepiaVS = SepiaVertexShader;
1400 using SepiaFS = SepiaFragmentShader;
1401
1402 auto context = GetContext();
1403 ASSERT_TRUE(context);
1404
1405 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1406 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1407 "support it.";
1408 return;
1409 }
1410
1411 // Create pipelines.
1412 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1413 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1414
1415 ASSERT_TRUE(texture_pipeline);
1416 ASSERT_TRUE(sepia_pipeline);
1417
1418 // Vertex buffer builders.
1419 VertexBufferBuilder<TextureVS::PerVertexData> texture_vtx_builder;
1420 texture_vtx_builder.AddVertices({
1421 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1422 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1423 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1424 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1425 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1426 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1427 });
1428
1429 VertexBufferBuilder<SepiaVS::PerVertexData> sepia_vtx_builder;
1430 sepia_vtx_builder.AddVertices({
1431 {{100, 100, 0.0}}, // 1
1432 {{800, 100, 0.0}}, // 2
1433 {{800, 800, 0.0}}, // 3
1434 {{100, 100, 0.0}}, // 1
1435 {{800, 800, 0.0}}, // 3
1436 {{100, 800, 0.0}}, // 4
1437 });
1438
1439 auto boston = CreateTextureForFixture("boston.jpg");
1440 ASSERT_TRUE(boston);
1441
1442 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1443 ASSERT_TRUE(sampler);
1444
1445 SinglePassCallback callback = [&](RenderPass& pass) {
1446 auto buffer = HostBuffer::Create(context->GetResourceAllocator());
1447
1448 // Draw the texture.
1449 {
1450 pass.SetPipeline(texture_pipeline);
1451 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1452 *context->GetResourceAllocator()));
1453 TextureVS::UniformBuffer uniforms;
1454 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1455 Matrix::MakeScale(GetContentScale());
1456 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1457 TextureFS::BindTextureContents(pass, boston, sampler);
1458 if (!pass.Draw().ok()) {
1459 return false;
1460 }
1461 }
1462
1463 // Draw the sepia toner.
1464 {
1465 pass.SetPipeline(sepia_pipeline);
1466 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1467 *context->GetResourceAllocator()));
1468 SepiaVS::UniformBuffer uniforms;
1469 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1470 Matrix::MakeScale(GetContentScale());
1471 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1472 if (!pass.Draw().ok()) {
1473 return false;
1474 }
1475 }
1476
1477 return true;
1478 };
1479 OpenPlaygroundHere(callback);
1480 }
1481
1482 TEST_P(RendererTest, CanSepiaToneThenSwizzleWithSubpasses) {
1483 // Define shader types
1484 using TextureVS = TextureVertexShader;
1485 using TextureFS = TextureFragmentShader;
1486
1487 using SwizzleVS = SepiaVertexShader;
1488 using SwizzleFS = SwizzleFragmentShader;
1489
1490 using SepiaVS = SepiaVertexShader;
1491 using SepiaFS = SepiaFragmentShader;
1492
1493 auto context = GetContext();
1494 ASSERT_TRUE(context);
1495
1496 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1497 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1498 "support it.";
1499 return;
1500 }
1501
1502 // Create pipelines.
1503 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1504 auto swizzle_pipeline = CreateDefaultPipeline<SwizzleVS, SwizzleFS>(context);
1505 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1506
1507 ASSERT_TRUE(texture_pipeline);
1508 ASSERT_TRUE(swizzle_pipeline);
1509 ASSERT_TRUE(sepia_pipeline);
1510
1511 // Vertex buffer builders.
1512 VertexBufferBuilder<TextureVS::PerVertexData> texture_vtx_builder;
1513 texture_vtx_builder.AddVertices({
1514 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1515 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1516 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1517 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1518 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1519 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1520 });
1521
1522 VertexBufferBuilder<SepiaVS::PerVertexData> sepia_vtx_builder;
1523 sepia_vtx_builder.AddVertices({
1524 {{100, 100, 0.0}}, // 1
1525 {{800, 100, 0.0}}, // 2
1526 {{800, 800, 0.0}}, // 3
1527 {{100, 100, 0.0}}, // 1
1528 {{800, 800, 0.0}}, // 3
1529 {{100, 800, 0.0}}, // 4
1530 });
1531
1532 auto boston = CreateTextureForFixture("boston.jpg");
1533 ASSERT_TRUE(boston);
1534
1535 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1536 ASSERT_TRUE(sampler);
1537
1538 SinglePassCallback callback = [&](RenderPass& pass) {
1539 auto buffer = HostBuffer::Create(context->GetResourceAllocator());
1540
1541 // Draw the texture.
1542 {
1543 pass.SetPipeline(texture_pipeline);
1544 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1545 *context->GetResourceAllocator()));
1546 TextureVS::UniformBuffer uniforms;
1547 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1548 Matrix::MakeScale(GetContentScale());
1549 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1550 TextureFS::BindTextureContents(pass, boston, sampler);
1551 if (!pass.Draw().ok()) {
1552 return false;
1553 }
1554 }
1555
1556 // Draw the sepia toner.
1557 {
1558 pass.SetPipeline(sepia_pipeline);
1559 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1560 *context->GetResourceAllocator()));
1561 SepiaVS::UniformBuffer uniforms;
1562 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1563 Matrix::MakeScale(GetContentScale());
1564 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1565 if (!pass.Draw().ok()) {
1566 return false;
1567 }
1568 }
1569
1570 // Draw the swizzle.
1571 {
1572 pass.SetPipeline(swizzle_pipeline);
1573 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1574 *context->GetResourceAllocator()));
1575 SwizzleVS::UniformBuffer uniforms;
1576 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1577 Matrix::MakeScale(GetContentScale());
1578 SwizzleVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1579 if (!pass.Draw().ok()) {
1580 return false;
1581 }
1582 }
1583
1584 return true;
1585 };
1586 OpenPlaygroundHere(callback);
1587 }
1588
1589 } // namespace testing
1590 } // namespace impeller
1591
1592 // 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:275
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:660
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::StencilAttachmentDescriptor::stencil_compare
CompareFunction stencil_compare
Definition: formats.h:616
impeller::testing::CompareFunctionUIData::IndexOf
int IndexOf(CompareFunction func) const
Definition: renderer_unittests.cc:1167
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:52
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:271
playground_test.h
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:151
impeller::testing::CompareFunctionUIData
Definition: renderer_unittests.cc:1141
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:14
impeller::VertexBufferBuilder::GetVertexCount
size_t GetVertexCount() const
Definition: vertex_buffer_builder.h:66
impeller::CompareFunction::kEqual
@ kEqual
Comparison test passes if new_value == current_value.
impeller::ColorAttachment
Definition: formats.h:665
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
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:43
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::HostBuffer::Create
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator)
Definition: host_buffer.cc:21
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:198
path_builder.h
formats.h
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
playground.h
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:82
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:128
impeller::Color::Yellow
static constexpr Color Yellow()
Definition: color.h:841
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:532
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
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:673
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:552
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:327
impeller::CullMode::kBackFace
@ kBackFace
render_pass.h
impeller::Playground::RenderCallback
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition: playground.h:80
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:425
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:657
impeller::VertexBufferBuilder
Definition: vertex_buffer_builder.h:36
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:849
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:68
impeller::Radians
Definition: scalar.h:43
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:415
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:273
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:91
impeller::VertexBufferBuilder::SetLabel
void SetLabel(const std::string &label)
Definition: vertex_buffer_builder.h:58
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:96
pipeline_library.h
impeller::CompareFunction::kNever
@ kNever
Comparison test never passes.
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:78
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:91
command_buffer.h
impeller::VertexBufferBuilder::GetIndexType
constexpr impeller::IndexType GetIndexType() const
Definition: vertex_buffer_builder.h:45
impeller::PlaygroundBackend::kOpenGLES
@ kOpenGLES
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:213
impeller::Range
Definition: range.h:13
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:610
impeller::BufferView::buffer
std::shared_ptr< const DeviceBuffer > buffer
Definition: buffer_view.h:16
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:659
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:523
impeller::Attachment::IsValid
bool IsValid() const
Definition: formats.cc:26
impeller::Degrees
Definition: scalar.h:51
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
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: allocation.cc:12
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