Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
12#include "impeller/fixtures/array.frag.h"
13#include "impeller/fixtures/array.vert.h"
14#include "impeller/fixtures/box_fade.frag.h"
15#include "impeller/fixtures/box_fade.vert.h"
16#include "impeller/fixtures/colors.frag.h"
17#include "impeller/fixtures/colors.vert.h"
18#include "impeller/fixtures/impeller.frag.h"
19#include "impeller/fixtures/impeller.vert.h"
20#include "impeller/fixtures/inactive_uniforms.frag.h"
21#include "impeller/fixtures/inactive_uniforms.vert.h"
22#include "impeller/fixtures/instanced_draw.frag.h"
23#include "impeller/fixtures/instanced_draw.vert.h"
24#include "impeller/fixtures/mipmaps.frag.h"
25#include "impeller/fixtures/mipmaps.vert.h"
26#include "impeller/fixtures/planet.frag.h"
27#include "impeller/fixtures/planet.vert.h"
28#include "impeller/fixtures/sepia.frag.h"
29#include "impeller/fixtures/sepia.vert.h"
30#include "impeller/fixtures/swizzle.frag.h"
31#include "impeller/fixtures/texture.frag.h"
32#include "impeller/fixtures/texture.vert.h"
41#include "third_party/imgui/imgui.h"
42
43// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
44// NOLINTBEGIN(bugprone-unchecked-optional-access)
45
46namespace {
47std::pair<std::shared_ptr<impeller::HostBuffer>,
48 std::shared_ptr<impeller::HostBuffer>>
49createHostBuffers(const std::shared_ptr<impeller::Context>& context) {
50 auto data_host_buffer = impeller::HostBuffer::Create(
51 context->GetResourceAllocator(), context->GetIdleWaiter(),
52 context->GetCapabilities()->GetMinimumUniformAlignment());
53 auto indexes_host_buffer =
54 context->GetCapabilities()->NeedsPartitionedHostBuffer()
56 context->GetResourceAllocator(), context->GetIdleWaiter(),
57 context->GetCapabilities()->GetMinimumUniformAlignment())
58 : data_host_buffer;
59 return {data_host_buffer, indexes_host_buffer};
60}
61} // namespace
62
63namespace impeller {
64namespace testing {
65
66using RendererTest = PlaygroundTest;
68
69TEST_P(RendererTest, CanCreateBoxPrimitive) {
70 using VS = BoxFadeVertexShader;
71 using FS = BoxFadeFragmentShader;
72 auto context = GetContext();
73 ASSERT_TRUE(context);
74 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
75 auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
76 ASSERT_TRUE(desc.has_value());
77 desc->SetSampleCount(SampleCount::kCount4);
78 desc->SetStencilAttachmentDescriptors(std::nullopt);
79
80 // Vertex buffer.
82 vertex_builder.SetLabel("Box");
83 vertex_builder.AddVertices({
84 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
85 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
86 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
87 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
88 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
89 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
90 });
91 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
92 auto boston = CreateTextureForFixture("boston.jpg");
93 ASSERT_TRUE(bridge && boston);
94 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
95 ASSERT_TRUE(sampler);
96
97 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
98 SinglePassCallback callback = [&](RenderPass& pass) {
99 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
100 static bool wireframe;
101 ImGui::Checkbox("Wireframe", &wireframe);
102 ImGui::End();
103
104 desc->SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill);
105 auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
106
107 assert(pipeline && pipeline->IsValid());
108
109 pass.SetCommandLabel("Box");
110 pass.SetPipeline(pipeline);
111 pass.SetVertexBuffer(
112 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()));
113
114 VS::UniformBuffer uniforms;
115 EXPECT_EQ(pass.GetOrthographicTransform(),
116 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
117 uniforms.mvp =
118 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
119 VS::BindUniformBuffer(pass, data_host_buffer->EmplaceUniform(uniforms));
120
121 FS::FrameInfo frame_info;
122 frame_info.current_time = GetSecondsElapsed();
123 frame_info.cursor_position = GetCursorPosition();
124 frame_info.window_size.x = GetWindowSize().width;
125 frame_info.window_size.y = GetWindowSize().height;
126
127 FS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
128 FS::BindContents1(pass, boston, sampler);
129 FS::BindContents2(pass, bridge, sampler);
130
131 data_host_buffer->Reset();
132 return pass.Draw().ok();
133 };
134 OpenPlaygroundHere(callback);
135}
136
137TEST_P(RendererTest, CanRenderPerspectiveCube) {
138 using VS = ColorsVertexShader;
139 using FS = ColorsFragmentShader;
140 auto context = GetContext();
141 ASSERT_TRUE(context);
143 ASSERT_TRUE(desc.has_value());
144 desc->SetCullMode(CullMode::kBackFace);
145 desc->SetWindingOrder(WindingOrder::kCounterClockwise);
146 desc->SetSampleCount(SampleCount::kCount4);
147 desc->ClearStencilAttachments();
148
149 // Setup the vertex layout to take two bindings. The first for positions and
150 // the second for colors.
151 auto vertex_desc = std::make_shared<VertexDescriptor>();
152 ShaderStageIOSlot position_slot = VS::kInputPosition;
153 ShaderStageIOSlot color_slot = VS::kInputColor;
154 position_slot.binding = 0;
155 position_slot.offset = 0;
156 color_slot.binding = 1;
157 color_slot.offset = 0;
158 const std::vector<ShaderStageIOSlot> io_slots = {position_slot, color_slot};
159 const std::vector<ShaderStageBufferLayout> layouts = {
160 ShaderStageBufferLayout{.stride = 12u, .binding = 0},
161 ShaderStageBufferLayout{.stride = 16u, .binding = 1}};
162 vertex_desc->RegisterDescriptorSetLayouts(VS::kDescriptorSetLayouts);
163 vertex_desc->RegisterDescriptorSetLayouts(FS::kDescriptorSetLayouts);
164 vertex_desc->SetStageInputs(io_slots, layouts);
165 desc->SetVertexDescriptor(std::move(vertex_desc));
166 auto pipeline =
167 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
168 ASSERT_TRUE(pipeline);
169
170 struct Cube {
171 Vector3 positions[8] = {
172 // -Z
173 {-1, -1, -1},
174 {1, -1, -1},
175 {1, 1, -1},
176 {-1, 1, -1},
177 // +Z
178 {-1, -1, 1},
179 {1, -1, 1},
180 {1, 1, 1},
181 {-1, 1, 1},
182 };
183 Color colors[8] = {
184 Color::Red(), Color::Yellow(), Color::Green(), Color::Blue(),
185 Color::Green(), Color::Blue(), Color::Red(), Color::Yellow(),
186 };
187 uint16_t indices[36] = {
188 1, 5, 2, 2, 5, 6, // +X
189 4, 0, 7, 7, 0, 3, // -X
190 4, 5, 0, 0, 5, 1, // +Y
191 3, 2, 7, 7, 2, 6, // -Y
192 5, 4, 6, 6, 4, 7, // +Z
193 0, 1, 3, 3, 1, 2, // -Z
194 };
195 } cube;
196
197 auto device_buffer = context->GetResourceAllocator()->CreateBufferWithCopy(
198 reinterpret_cast<uint8_t*>(&cube), sizeof(cube));
199
200 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
201 ASSERT_TRUE(sampler);
202
203 Vector3 euler_angles;
204 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
205 SinglePassCallback callback = [&](RenderPass& pass) {
206 static Degrees fov_y(60);
207 static Scalar distance = 10;
208
209 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
210 ImGui::SliderFloat("Field of view", &fov_y.degrees, 0, 180);
211 ImGui::SliderFloat("Camera distance", &distance, 0, 30);
212 ImGui::End();
213
214 pass.SetCommandLabel("Perspective Cube");
215 pass.SetPipeline(pipeline);
216
217 std::array<BufferView, 2> vertex_buffers = {
218 BufferView(device_buffer,
219 Range(offsetof(Cube, positions), sizeof(Cube::positions))),
220 BufferView(device_buffer,
221 Range(offsetof(Cube, colors), sizeof(Cube::colors))),
222 };
223
224 BufferView index_buffer(
225 device_buffer, Range(offsetof(Cube, indices), sizeof(Cube::indices)));
226 pass.SetVertexBuffer(vertex_buffers.data(), vertex_buffers.size());
227 pass.SetElementCount(36);
228 pass.SetIndexBuffer(index_buffer, IndexType::k16bit);
229
230 VS::UniformBuffer uniforms;
231 Scalar time = GetSecondsElapsed();
232 euler_angles = Vector3(0.19 * time, 0.7 * time, 0.43 * time);
233
234 uniforms.mvp =
235 Matrix::MakePerspective(fov_y, pass.GetRenderTargetSize(), 0, 10) *
236 Matrix::MakeTranslation({0, 0, distance}) *
237 Matrix::MakeRotationX(Radians(euler_angles.x)) *
238 Matrix::MakeRotationY(Radians(euler_angles.y)) *
239 Matrix::MakeRotationZ(Radians(euler_angles.z));
240 VS::BindUniformBuffer(pass, data_host_buffer->EmplaceUniform(uniforms));
241
242 data_host_buffer->Reset();
243 return pass.Draw().ok();
244 };
245 OpenPlaygroundHere(callback);
246}
247
248TEST_P(RendererTest, CanRenderMultiplePrimitives) {
249 using VS = BoxFadeVertexShader;
250 using FS = BoxFadeFragmentShader;
251 auto context = GetContext();
252 ASSERT_TRUE(context);
253 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
254 auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
255 ASSERT_TRUE(desc.has_value());
256 desc->SetSampleCount(SampleCount::kCount4);
257 desc->SetStencilAttachmentDescriptors(std::nullopt);
258 auto box_pipeline =
259 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
260 ASSERT_TRUE(box_pipeline);
261
262 // Vertex buffer.
264 vertex_builder.SetLabel("Box");
265 vertex_builder.AddVertices({
266 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
267 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
268 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
269 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
270 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
271 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
272 });
273 auto vertex_buffer =
274 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
275 ASSERT_TRUE(vertex_buffer);
276
277 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
278 auto boston = CreateTextureForFixture("boston.jpg");
279 ASSERT_TRUE(bridge && boston);
280 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
281 ASSERT_TRUE(sampler);
282
283 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
284 SinglePassCallback callback = [&](RenderPass& pass) {
285 for (size_t i = 0; i < 1; i++) {
286 for (size_t j = 0; j < 1; j++) {
287 pass.SetCommandLabel("Box");
288 pass.SetPipeline(box_pipeline);
289 pass.SetVertexBuffer(vertex_buffer);
290
291 FS::FrameInfo frame_info;
292 frame_info.current_time = GetSecondsElapsed();
293 frame_info.cursor_position = GetCursorPosition();
294 frame_info.window_size.x = GetWindowSize().width;
295 frame_info.window_size.y = GetWindowSize().height;
296
297 FS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
298 FS::BindContents1(pass, boston, sampler);
299 FS::BindContents2(pass, bridge, sampler);
300
301 VS::UniformBuffer uniforms;
302 EXPECT_EQ(pass.GetOrthographicTransform(),
303 Matrix::MakeOrthographic(pass.GetRenderTargetSize()));
304 uniforms.mvp = pass.GetOrthographicTransform() *
305 Matrix::MakeScale(GetContentScale()) *
306 Matrix::MakeTranslation({i * 50.0f, j * 50.0f, 0.0f});
307 VS::BindUniformBuffer(pass, data_host_buffer->EmplaceUniform(uniforms));
308 if (!pass.Draw().ok()) {
309 return false;
310 }
311 }
312 }
313
314 data_host_buffer->Reset();
315 return true;
316 };
317 OpenPlaygroundHere(callback);
318}
319
320TEST_P(RendererTest, CanRenderToTexture) {
321 using VS = BoxFadeVertexShader;
322 using FS = BoxFadeFragmentShader;
323 auto context = GetContext();
324 ASSERT_TRUE(context);
325 using BoxPipelineBuilder = PipelineBuilder<VS, FS>;
326 auto pipeline_desc =
327 BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context);
328 pipeline_desc->SetSampleCount(SampleCount::kCount1);
329 pipeline_desc->ClearDepthAttachment();
330 pipeline_desc->SetStencilPixelFormat(PixelFormat::kS8UInt);
331
332 ASSERT_TRUE(pipeline_desc.has_value());
333 auto box_pipeline =
334 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
335 ASSERT_TRUE(box_pipeline);
336 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
337
339 vertex_builder.SetLabel("Box");
340 vertex_builder.AddVertices({
341 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
342 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
343 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
344 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
345 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
346 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
347 });
348 auto vertex_buffer =
349 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
350 ASSERT_TRUE(vertex_buffer);
351
352 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
353 auto boston = CreateTextureForFixture("boston.jpg");
354 ASSERT_TRUE(bridge && boston);
355 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
356 ASSERT_TRUE(sampler);
357
358 std::shared_ptr<RenderPass> r2t_pass;
359 auto cmd_buffer = context->CreateCommandBuffer();
360 ASSERT_TRUE(cmd_buffer);
361 {
362 ColorAttachment color0;
365
366 TextureDescriptor texture_descriptor;
367 ASSERT_NE(pipeline_desc->GetColorAttachmentDescriptor(0u), nullptr);
368 texture_descriptor.format =
369 pipeline_desc->GetColorAttachmentDescriptor(0u)->format;
370 texture_descriptor.storage_mode = StorageMode::kHostVisible;
371 texture_descriptor.size = {400, 400};
372 texture_descriptor.mip_count = 1u;
373 texture_descriptor.usage = TextureUsage::kRenderTarget;
374
375 color0.texture =
376 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
377
378 ASSERT_TRUE(color0.IsValid());
379
380 color0.texture->SetLabel("r2t_target");
381
382 StencilAttachment stencil0;
385 TextureDescriptor stencil_texture_desc;
386 stencil_texture_desc.storage_mode = StorageMode::kDeviceTransient;
387 stencil_texture_desc.size = texture_descriptor.size;
388 stencil_texture_desc.format = PixelFormat::kS8UInt;
389 stencil_texture_desc.usage = TextureUsage::kRenderTarget;
390 stencil0.texture =
391 context->GetResourceAllocator()->CreateTexture(stencil_texture_desc);
392
393 RenderTarget r2t_desc;
394 r2t_desc.SetColorAttachment(color0, 0u);
395 r2t_desc.SetStencilAttachment(stencil0);
396 r2t_pass = cmd_buffer->CreateRenderPass(r2t_desc);
397 ASSERT_TRUE(r2t_pass && r2t_pass->IsValid());
398 }
399
400 r2t_pass->SetCommandLabel("Box");
401 r2t_pass->SetPipeline(box_pipeline);
402 r2t_pass->SetVertexBuffer(vertex_buffer);
403
404 FS::FrameInfo frame_info;
405 frame_info.current_time = GetSecondsElapsed();
406 frame_info.cursor_position = GetCursorPosition();
407 frame_info.window_size.x = GetWindowSize().width;
408 frame_info.window_size.y = GetWindowSize().height;
409
410 FS::BindFrameInfo(*r2t_pass, data_host_buffer->EmplaceUniform(frame_info));
411 FS::BindContents1(*r2t_pass, boston, sampler);
412 FS::BindContents2(*r2t_pass, bridge, sampler);
413
414 VS::UniformBuffer uniforms;
415 uniforms.mvp = Matrix::MakeOrthographic(ISize{1024, 768}) *
416 Matrix::MakeTranslation({50.0f, 50.0f, 0.0f});
417 VS::BindUniformBuffer(*r2t_pass, data_host_buffer->EmplaceUniform(uniforms));
418 ASSERT_TRUE(r2t_pass->Draw().ok());
419 ASSERT_TRUE(r2t_pass->EncodeCommands());
420}
421
422TEST_P(RendererTest, CanRenderInstanced) {
423 if (GetParam() == PlaygroundBackend::kOpenGLES ||
424 GetParam() == PlaygroundBackend::kOpenGLESSDF) {
425 // This test drives instancing through gl_InstanceIndex and a storage
426 // buffer, both of which require OpenGL ES 3.1. The portable instance-rate
427 // vertex attribute path, which works down to OpenGL ES 2.0, is covered by
428 // CanRenderInstancedWithVertexAttributes.
429 GTEST_SKIP() << "This test's instance-ID mechanism requires OpenGL ES 3.1; "
430 "CanRenderInstancedWithVertexAttributes covers the "
431 "portable instance-rate path.";
432 }
433 using VS = InstancedDrawVertexShader;
434 using FS = InstancedDrawFragmentShader;
435
437 builder.AddVertices({
438 VS::PerVertexData{Point{10, 10}},
439 VS::PerVertexData{Point{10, 110}},
440 VS::PerVertexData{Point{110, 10}},
441 VS::PerVertexData{Point{10, 110}},
442 VS::PerVertexData{Point{110, 10}},
443 VS::PerVertexData{Point{110, 110}},
444 });
445
446 ASSERT_NE(GetContext(), nullptr);
447 auto pipeline =
448 GetContext()
449 ->GetPipelineLibrary()
451 *GetContext())
452 ->SetSampleCount(SampleCount::kCount4)
453 .SetStencilAttachmentDescriptors(std::nullopt))
454
455 .Get();
456 ASSERT_TRUE(pipeline && pipeline->IsValid());
457
458 static constexpr size_t kInstancesCount = 5u;
459 VS::InstanceInfo<kInstancesCount> instances;
460 for (size_t i = 0; i < kInstancesCount; i++) {
461 instances.colors[i] = Color::Random();
462 }
463
464 auto [data_host_buffer, indexes_host_buffer] =
465 createHostBuffers(GetContext());
466 ASSERT_TRUE(OpenPlaygroundHere([&](RenderPass& pass) -> bool {
467 pass.SetPipeline(pipeline);
468 pass.SetCommandLabel("InstancedDraw");
469
470 VS::FrameInfo frame_info;
471 EXPECT_EQ(pass.GetOrthographicTransform(),
473 frame_info.mvp =
474 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
475 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
476 VS::BindInstanceInfo(pass,
477 data_host_buffer->EmplaceStorageBuffer(instances));
478 pass.SetVertexBuffer(
479 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
480
481 pass.SetInstanceCount(kInstancesCount);
482 pass.Draw();
483
484 data_host_buffer->Reset();
485 return true;
486 }));
487}
488
489TEST_P(RendererTest, CanBlitTextureToTexture) {
490 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
491 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
492 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
493 }
494 auto context = GetContext();
495 ASSERT_TRUE(context);
496
497 using VS = MipmapsVertexShader;
498 using FS = MipmapsFragmentShader;
500 ASSERT_TRUE(desc.has_value());
501 desc->SetSampleCount(SampleCount::kCount4);
502 desc->SetStencilAttachmentDescriptors(std::nullopt);
503 auto mipmaps_pipeline =
504 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
505 ASSERT_TRUE(mipmaps_pipeline);
506
507 TextureDescriptor texture_desc;
510 texture_desc.size = {800, 600};
511 texture_desc.mip_count = 1u;
513 auto texture = context->GetResourceAllocator()->CreateTexture(texture_desc);
514 ASSERT_TRUE(texture);
515
516 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
517 auto boston = CreateTextureForFixture("boston.jpg");
518 ASSERT_TRUE(bridge && boston);
519 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
520 ASSERT_TRUE(sampler);
521
522 // Vertex buffer.
524 vertex_builder.SetLabel("Box");
525 auto size = Point(boston->GetSize());
526 vertex_builder.AddVertices({
527 {{0, 0}, {0.0, 0.0}}, // 1
528 {{size.x, 0}, {1.0, 0.0}}, // 2
529 {{size.x, size.y}, {1.0, 1.0}}, // 3
530 {{0, 0}, {0.0, 0.0}}, // 1
531 {{size.x, size.y}, {1.0, 1.0}}, // 3
532 {{0, size.y}, {0.0, 1.0}}, // 4
533 });
534 auto vertex_buffer =
535 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
536 ASSERT_TRUE(vertex_buffer);
537
538 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
539 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
540 auto buffer = context->CreateCommandBuffer();
541 if (!buffer) {
542 return false;
543 }
544 buffer->SetLabel("Playground Command Buffer");
545
546 {
547 auto pass = buffer->CreateBlitPass();
548 if (!pass) {
549 return false;
550 }
551 pass->SetLabel("Playground Blit Pass");
552
553 // Blit `bridge` to the top left corner of the texture.
554 pass->AddCopy(bridge, texture);
555
556 if (!pass->EncodeCommands()) {
557 return false;
558 }
559 }
560
561 {
562 auto pass = buffer->CreateRenderPass(render_target);
563 if (!pass) {
564 return false;
565 }
566 pass->SetLabel("Playground Render Pass");
567 {
568 pass->SetCommandLabel("Image");
569 pass->SetPipeline(mipmaps_pipeline);
570 pass->SetVertexBuffer(vertex_buffer);
571
572 VS::FrameInfo frame_info;
573 EXPECT_EQ(pass->GetOrthographicTransform(),
574 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
575 frame_info.mvp = pass->GetOrthographicTransform() *
576 Matrix::MakeScale(GetContentScale());
577 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
578
579 FS::FragInfo frag_info;
580 frag_info.lod = 0;
581 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
582
583 auto sampler = context->GetSamplerLibrary()->GetSampler({});
584 FS::BindTex(*pass, texture, sampler);
585
586 pass->Draw();
587 }
588 pass->EncodeCommands();
589 }
590
591 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
592 return false;
593 }
594 data_host_buffer->Reset();
595 return true;
596 };
597 OpenPlaygroundHere(callback);
598}
599
600TEST_P(RendererTest, CanBlitTextureToBuffer) {
601 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
602 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
603 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
604 }
605 auto context = GetContext();
606 ASSERT_TRUE(context);
607
608 using VS = MipmapsVertexShader;
609 using FS = MipmapsFragmentShader;
611 ASSERT_TRUE(desc.has_value());
612 desc->SetSampleCount(SampleCount::kCount4);
613 desc->SetStencilAttachmentDescriptors(std::nullopt);
614 auto mipmaps_pipeline =
615 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
616 ASSERT_TRUE(mipmaps_pipeline);
617
618 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
619 auto boston = CreateTextureForFixture("boston.jpg");
620 ASSERT_TRUE(bridge && boston);
621 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
622 ASSERT_TRUE(sampler);
623
624 TextureDescriptor texture_desc;
627 texture_desc.size = bridge->GetTextureDescriptor().size;
628 texture_desc.mip_count = 1u;
629 texture_desc.usage = TextureUsage::kRenderTarget |
631 DeviceBufferDescriptor device_buffer_desc;
632 device_buffer_desc.storage_mode = StorageMode::kHostVisible;
633 device_buffer_desc.size =
634 bridge->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
635 auto device_buffer =
636 context->GetResourceAllocator()->CreateBuffer(device_buffer_desc);
637
638 // Vertex buffer.
640 vertex_builder.SetLabel("Box");
641 auto size = Point(boston->GetSize());
642 vertex_builder.AddVertices({
643 {{0, 0}, {0.0, 0.0}}, // 1
644 {{size.x, 0}, {1.0, 0.0}}, // 2
645 {{size.x, size.y}, {1.0, 1.0}}, // 3
646 {{0, 0}, {0.0, 0.0}}, // 1
647 {{size.x, size.y}, {1.0, 1.0}}, // 3
648 {{0, size.y}, {0.0, 1.0}}, // 4
649 });
650 auto vertex_buffer =
651 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
652 ASSERT_TRUE(vertex_buffer);
653
654 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
655 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
656 {
657 auto buffer = context->CreateCommandBuffer();
658 if (!buffer) {
659 return false;
660 }
661 buffer->SetLabel("Playground Command Buffer");
662 auto pass = buffer->CreateBlitPass();
663 if (!pass) {
664 return false;
665 }
666 pass->SetLabel("Playground Blit Pass");
667
668 // Blit `bridge` to the top left corner of the texture.
669 pass->AddCopy(bridge, device_buffer);
670 pass->EncodeCommands();
671
672 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
673 return false;
674 }
675 }
676
677 {
678 auto buffer = context->CreateCommandBuffer();
679 if (!buffer) {
680 return false;
681 }
682 buffer->SetLabel("Playground Command Buffer");
683
684 auto pass = buffer->CreateRenderPass(render_target);
685 if (!pass) {
686 return false;
687 }
688 pass->SetLabel("Playground Render Pass");
689 {
690 pass->SetCommandLabel("Image");
691 pass->SetPipeline(mipmaps_pipeline);
692 pass->SetVertexBuffer(vertex_buffer);
693
694 VS::FrameInfo frame_info;
695 EXPECT_EQ(pass->GetOrthographicTransform(),
696 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
697 frame_info.mvp = pass->GetOrthographicTransform() *
698 Matrix::MakeScale(GetContentScale());
699 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
700
701 FS::FragInfo frag_info;
702 frag_info.lod = 0;
703 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
704
705 raw_ptr<const Sampler> sampler =
706 context->GetSamplerLibrary()->GetSampler({});
707 auto buffer_view = DeviceBuffer::AsBufferView(device_buffer);
708 auto texture =
709 context->GetResourceAllocator()->CreateTexture(texture_desc);
710 if (!texture->SetContents(device_buffer->OnGetContents(),
711 buffer_view.GetRange().length)) {
712 VALIDATION_LOG << "Could not upload texture to device memory";
713 return false;
714 }
715 FS::BindTex(*pass, texture, sampler);
716
717 pass->Draw().ok();
718 }
719 pass->EncodeCommands();
720 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
721 return false;
722 }
723 }
724 data_host_buffer->Reset();
725 return true;
726 };
727 OpenPlaygroundHere(callback);
728}
729
730TEST_P(RendererTest, CanGenerateMipmaps) {
731 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
732 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
733 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
734 }
735 auto context = GetContext();
736 ASSERT_TRUE(context);
737
738 using VS = MipmapsVertexShader;
739 using FS = MipmapsFragmentShader;
741 ASSERT_TRUE(desc.has_value());
742 desc->SetSampleCount(SampleCount::kCount4);
743 desc->SetStencilAttachmentDescriptors(std::nullopt);
744 auto mipmaps_pipeline =
745 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
746 ASSERT_TRUE(mipmaps_pipeline);
747
748 auto boston = CreateTextureForFixture("boston.jpg", true);
749 ASSERT_TRUE(boston);
750
751 // Vertex buffer.
753 vertex_builder.SetLabel("Box");
754 auto size = Point(boston->GetSize());
755 vertex_builder.AddVertices({
756 {{0, 0}, {0.0, 0.0}}, // 1
757 {{size.x, 0}, {1.0, 0.0}}, // 2
758 {{size.x, size.y}, {1.0, 1.0}}, // 3
759 {{0, 0}, {0.0, 0.0}}, // 1
760 {{size.x, size.y}, {1.0, 1.0}}, // 3
761 {{0, size.y}, {0.0, 1.0}}, // 4
762 });
763 auto vertex_buffer =
764 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
765 ASSERT_TRUE(vertex_buffer);
766
767 bool first_frame = true;
768 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
769 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
770 const char* mip_filter_names[] = {"Base", "Nearest", "Linear"};
771 const MipFilter mip_filters[] = {MipFilter::kBase, MipFilter::kNearest,
773 const char* min_filter_names[] = {"Nearest", "Linear"};
774 const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
776
777 // UI state.
778 static int selected_mip_filter = 1;
779 static int selected_min_filter = 0;
780 static float lod = 4.5;
781
782 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
783 ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names,
784 sizeof(mip_filter_names) / sizeof(char*));
785 ImGui::Combo("Min filter", &selected_min_filter, min_filter_names,
786 sizeof(min_filter_names) / sizeof(char*));
787 ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1);
788 ImGui::End();
789
790 auto buffer = context->CreateCommandBuffer();
791 if (!buffer) {
792 return false;
793 }
794 buffer->SetLabel("Playground Command Buffer");
795
796 if (first_frame) {
797 auto pass = buffer->CreateBlitPass();
798 if (!pass) {
799 return false;
800 }
801 pass->SetLabel("Playground Blit Pass");
802
803 pass->GenerateMipmap(boston, "Boston Mipmap");
804
805 pass->EncodeCommands();
806 }
807
808 first_frame = false;
809
810 {
811 auto pass = buffer->CreateRenderPass(render_target);
812 if (!pass) {
813 return false;
814 }
815 pass->SetLabel("Playground Render Pass");
816 {
817 pass->SetCommandLabel("Image LOD");
818 pass->SetPipeline(mipmaps_pipeline);
819 pass->SetVertexBuffer(vertex_buffer);
820
821 VS::FrameInfo frame_info;
822 EXPECT_EQ(pass->GetOrthographicTransform(),
823 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
824 frame_info.mvp = pass->GetOrthographicTransform() *
825 Matrix::MakeScale(GetContentScale());
826 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
827
828 FS::FragInfo frag_info;
829 frag_info.lod = lod;
830 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
831
832 SamplerDescriptor sampler_desc;
833 sampler_desc.mip_filter = mip_filters[selected_mip_filter];
834 sampler_desc.min_filter = min_filters[selected_min_filter];
835 raw_ptr<const Sampler> sampler =
836 context->GetSamplerLibrary()->GetSampler(sampler_desc);
837 FS::BindTex(*pass, boston, sampler);
838
839 pass->Draw();
840 }
841 pass->EncodeCommands();
842 }
843
844 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
845 return false;
846 }
847 data_host_buffer->Reset();
848 return true;
849 };
850 OpenPlaygroundHere(callback);
851}
852
853TEST_P(RendererTest, TheImpeller) {
854 using VS = ImpellerVertexShader;
855 using FS = ImpellerFragmentShader;
856
857 auto context = GetContext();
858 auto pipeline_descriptor =
860 ASSERT_TRUE(pipeline_descriptor.has_value());
861 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
862 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
863 auto pipeline =
864 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
865 ASSERT_TRUE(pipeline && pipeline->IsValid());
866
867 auto blue_noise = CreateTextureForFixture("blue_noise.png");
868 SamplerDescriptor noise_sampler_desc;
871 raw_ptr<const Sampler> noise_sampler =
872 context->GetSamplerLibrary()->GetSampler(noise_sampler_desc);
873
874 auto cube_map = CreateTextureCubeForFixture(
875 {"table_mountain_px.png", "table_mountain_nx.png",
876 "table_mountain_py.png", "table_mountain_ny.png",
877 "table_mountain_pz.png", "table_mountain_nz.png"});
878 raw_ptr<const Sampler> cube_map_sampler =
879 context->GetSamplerLibrary()->GetSampler({});
880
881 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
882 SinglePassCallback callback = [&](RenderPass& pass) {
883 auto size = pass.GetRenderTargetSize();
884
885 pass.SetPipeline(pipeline);
886 pass.SetCommandLabel("Impeller SDF scene");
888 builder.AddVertices({{Point()},
889 {Point(0, size.height)},
890 {Point(size.width, 0)},
891 {Point(size.width, 0)},
892 {Point(0, size.height)},
893 {Point(size.width, size.height)}});
894 pass.SetVertexBuffer(
895 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
896
897 VS::FrameInfo frame_info;
898 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
899 frame_info.mvp = pass.GetOrthographicTransform();
900 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
901
902 FS::FragInfo fs_uniform;
903 fs_uniform.texture_size = Point(size);
904 fs_uniform.time = GetSecondsElapsed();
905 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
906 FS::BindBlueNoise(pass, blue_noise, noise_sampler);
907 FS::BindCubeMap(pass, cube_map, cube_map_sampler);
908
909 pass.Draw().ok();
910 data_host_buffer->Reset();
911 return true;
912 };
913 OpenPlaygroundHere(callback);
914}
915
917 using VS = PlanetVertexShader;
918 using FS = PlanetFragmentShader;
919
920 auto context = GetContext();
921 auto pipeline_descriptor =
923 ASSERT_TRUE(pipeline_descriptor.has_value());
924 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
925 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
926 auto pipeline =
927 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
928 ASSERT_TRUE(pipeline && pipeline->IsValid());
929
930 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
931 SinglePassCallback callback = [&](RenderPass& pass) {
932 static Scalar speed = 0.1;
933 static Scalar planet_size = 550.0;
934 static bool show_normals = false;
935 static bool show_noise = false;
936 static Scalar seed_value = 42.0;
937
938 auto size = pass.GetRenderTargetSize();
939
940 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
941 ImGui::SliderFloat("Speed", &speed, 0.0, 10.0);
942 ImGui::SliderFloat("Planet Size", &planet_size, 0.1, 1000);
943 ImGui::Checkbox("Show Normals", &show_normals);
944 ImGui::Checkbox("Show Noise", &show_noise);
945 ImGui::InputFloat("Seed Value", &seed_value);
946 ImGui::End();
947
948 pass.SetPipeline(pipeline);
949 pass.SetCommandLabel("Planet scene");
951 builder.AddVertices({{Point()},
952 {Point(0, size.height)},
953 {Point(size.width, 0)},
954 {Point(size.width, 0)},
955 {Point(0, size.height)},
956 {Point(size.width, size.height)}});
957 pass.SetVertexBuffer(
958 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
959
960 VS::FrameInfo frame_info;
961 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
962 frame_info.mvp = pass.GetOrthographicTransform();
963 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
964
965 FS::FragInfo fs_uniform;
966 fs_uniform.resolution = Point(size);
967 fs_uniform.time = GetSecondsElapsed();
968 fs_uniform.speed = speed;
969 fs_uniform.planet_size = planet_size;
970 fs_uniform.show_normals = show_normals ? 1.0 : 0.0;
971 fs_uniform.show_noise = show_noise ? 1.0 : 0.0;
972 fs_uniform.seed_value = seed_value;
973 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
974
975 pass.Draw().ok();
976 data_host_buffer->Reset();
977 return true;
978 };
979 OpenPlaygroundHere(callback);
980}
981
982TEST_P(RendererTest, ArrayUniforms) {
983 using VS = ArrayVertexShader;
984 using FS = ArrayFragmentShader;
985
986 auto context = GetContext();
987 auto pipeline_descriptor =
989 ASSERT_TRUE(pipeline_descriptor.has_value());
990 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
991 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
992 auto pipeline =
993 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
994 ASSERT_TRUE(pipeline && pipeline->IsValid());
995
996 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
997 SinglePassCallback callback = [&](RenderPass& pass) {
998 auto size = pass.GetRenderTargetSize();
999
1000 pass.SetPipeline(pipeline);
1001 pass.SetCommandLabel("Google Dots");
1003 builder.AddVertices({{Point()},
1004 {Point(0, size.height)},
1005 {Point(size.width, 0)},
1006 {Point(size.width, 0)},
1007 {Point(0, size.height)},
1008 {Point(size.width, size.height)}});
1009 pass.SetVertexBuffer(
1010 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
1011
1012 VS::FrameInfo frame_info;
1013 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
1014 frame_info.mvp =
1015 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
1016 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
1017
1018 auto time = GetSecondsElapsed();
1019 auto y_pos = [&time](float x) {
1020 return 400 + 10 * std::cos(time * 5 + x / 6);
1021 };
1022
1023 FS::FragInfo fs_uniform = {
1024 .circle_positions = {Point(430, y_pos(0)), Point(480, y_pos(1)),
1025 Point(530, y_pos(2)), Point(580, y_pos(3))},
1026 .colors = {Color::MakeRGBA8(66, 133, 244, 255),
1027 Color::MakeRGBA8(219, 68, 55, 255),
1028 Color::MakeRGBA8(244, 180, 0, 255),
1029 Color::MakeRGBA8(15, 157, 88, 255)},
1030 };
1031 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
1032
1033 pass.Draw();
1034 data_host_buffer->Reset();
1035 return true;
1036 };
1037 OpenPlaygroundHere(callback);
1038}
1039
1040TEST_P(RendererTest, InactiveUniforms) {
1041 using VS = InactiveUniformsVertexShader;
1042 using FS = InactiveUniformsFragmentShader;
1043
1044 auto context = GetContext();
1045 auto pipeline_descriptor =
1047 ASSERT_TRUE(pipeline_descriptor.has_value());
1048 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
1049 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
1050 auto pipeline =
1051 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
1052 ASSERT_TRUE(pipeline && pipeline->IsValid());
1053
1054 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
1055 SinglePassCallback callback = [&](RenderPass& pass) {
1056 auto size = pass.GetRenderTargetSize();
1057
1058 pass.SetPipeline(pipeline);
1059 pass.SetCommandLabel("Inactive Uniform");
1060
1062 builder.AddVertices({{Point()},
1063 {Point(0, size.height)},
1064 {Point(size.width, 0)},
1065 {Point(size.width, 0)},
1066 {Point(0, size.height)},
1067 {Point(size.width, size.height)}});
1068 pass.SetVertexBuffer(
1069 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
1070
1071 VS::FrameInfo frame_info;
1072 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
1073 frame_info.mvp =
1074 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
1075 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
1076
1077 FS::FragInfo fs_uniform = {.unused_color = Color::Red(),
1078 .color = Color::Green()};
1079 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
1080
1081 pass.Draw().ok();
1082 data_host_buffer->Reset();
1083 return true;
1084 };
1085 OpenPlaygroundHere(callback);
1086}
1087
1088TEST_P(RendererTest, DefaultIndexSize) {
1089 using VS = BoxFadeVertexShader;
1090
1091 // Default to 16bit index buffer size, as this is a reasonable default and
1092 // supported on all backends without extensions.
1094 vertex_builder.AppendIndex(0u);
1095 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::k16bit);
1096}
1097
1098TEST_P(RendererTest, DefaultIndexBehavior) {
1099 using VS = BoxFadeVertexShader;
1100
1101 // Do not create any index buffer if no indices were provided.
1103 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1104}
1105
1107 // Does not create index buffer if one is provided.
1108 using VS = BoxFadeVertexShader;
1110 vertex_builder.SetLabel("Box");
1111 vertex_builder.AddVertices({
1112 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1113 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1114 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1115 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1116 });
1117 vertex_builder.AppendIndex(0);
1118 vertex_builder.AppendIndex(1);
1119 vertex_builder.AppendIndex(2);
1120 vertex_builder.AppendIndex(1);
1121 vertex_builder.AppendIndex(2);
1122 vertex_builder.AppendIndex(3);
1123
1124 ASSERT_EQ(vertex_builder.GetIndexCount(), 6u);
1125 ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
1126}
1127
1129 public:
1131 labels_.push_back("Never");
1132 functions_.push_back(CompareFunction::kNever);
1133 labels_.push_back("Always");
1134 functions_.push_back(CompareFunction::kAlways);
1135 labels_.push_back("Less");
1136 functions_.push_back(CompareFunction::kLess);
1137 labels_.push_back("Equal");
1138 functions_.push_back(CompareFunction::kEqual);
1139 labels_.push_back("LessEqual");
1140 functions_.push_back(CompareFunction::kLessEqual);
1141 labels_.push_back("Greater");
1142 functions_.push_back(CompareFunction::kGreater);
1143 labels_.push_back("NotEqual");
1144 functions_.push_back(CompareFunction::kNotEqual);
1145 labels_.push_back("GreaterEqual");
1146 functions_.push_back(CompareFunction::kGreaterEqual);
1147 assert(labels_.size() == functions_.size());
1148 }
1149
1150 const char* const* labels() const { return &labels_[0]; }
1151
1152 int size() const { return labels_.size(); }
1153
1154 int IndexOf(CompareFunction func) const {
1155 for (size_t i = 0; i < functions_.size(); i++) {
1156 if (functions_[i] == func) {
1157 return i;
1158 }
1159 }
1161 return -1;
1162 }
1163
1164 CompareFunction FunctionOf(int index) const { return functions_[index]; }
1165
1166 private:
1167 std::vector<const char*> labels_;
1168 std::vector<CompareFunction> functions_;
1169};
1170
1173 return data;
1174}
1175
1176TEST_P(RendererTest, StencilMask) {
1177 using VS = BoxFadeVertexShader;
1178 using FS = BoxFadeFragmentShader;
1179 auto context = GetContext();
1180 ASSERT_TRUE(context);
1181 using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1182 auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1183 ASSERT_TRUE(desc.has_value());
1184
1185 // Vertex buffer.
1187 vertex_builder.SetLabel("Box");
1188 vertex_builder.AddVertices({
1189 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1190 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1191 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1192 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1193 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1194 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1195 });
1196 auto vertex_buffer =
1197 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
1198 ASSERT_TRUE(vertex_buffer);
1199
1200 desc->SetSampleCount(SampleCount::kCount4);
1201 desc->SetStencilAttachmentDescriptors(std::nullopt);
1202
1203 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
1204 auto boston = CreateTextureForFixture("boston.jpg");
1205 ASSERT_TRUE(bridge && boston);
1206 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
1207 ASSERT_TRUE(sampler);
1208
1209 static bool mirror = false;
1210 static int stencil_reference_write = 0xFF;
1211 static int stencil_reference_read = 0x1;
1212 std::vector<uint8_t> stencil_contents;
1213 static int last_stencil_contents_reference_value = 0;
1214 static int current_front_compare =
1216 static int current_back_compare =
1218
1219 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
1220 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
1221 auto buffer = context->CreateCommandBuffer();
1222 if (!buffer) {
1223 return false;
1224 }
1225 buffer->SetLabel("Playground Command Buffer");
1226
1227 {
1228 // Configure the stencil attachment for the test.
1229 RenderTarget::AttachmentConfig stencil_config;
1230 stencil_config.load_action = LoadAction::kLoad;
1231 stencil_config.store_action = StoreAction::kDontCare;
1232 stencil_config.storage_mode = StorageMode::kHostVisible;
1233 render_target.SetupDepthStencilAttachments(
1234 *context, *context->GetResourceAllocator(),
1235 render_target.GetRenderTargetSize(), true, "stencil", stencil_config);
1236 // Fill the stencil buffer with an checkerboard pattern.
1237 const auto target_width = render_target.GetRenderTargetSize().width;
1238 const auto target_height = render_target.GetRenderTargetSize().height;
1239 const size_t target_size = target_width * target_height;
1240 if (stencil_contents.size() != target_size ||
1241 last_stencil_contents_reference_value != stencil_reference_write) {
1242 stencil_contents.resize(target_size);
1243 last_stencil_contents_reference_value = stencil_reference_write;
1244 for (int y = 0; y < target_height; y++) {
1245 for (int x = 0; x < target_width; x++) {
1246 const auto index = y * target_width + x;
1247 const auto kCheckSize = 64;
1248 const auto value =
1249 (((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
1250 stencil_reference_write;
1251 stencil_contents[index] = value;
1252 }
1253 }
1254 }
1255 if (!render_target.GetStencilAttachment()->texture->SetContents(
1256 stencil_contents.data(), stencil_contents.size(), 0, false)) {
1257 VALIDATION_LOG << "Could not upload stencil contents to device memory";
1258 return false;
1259 }
1260 auto pass = buffer->CreateRenderPass(render_target);
1261 if (!pass) {
1262 return false;
1263 }
1264 pass->SetLabel("Stencil Buffer");
1265 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1266 ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
1267 0xFF);
1268 ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
1269 0xFF);
1270 ImGui::Checkbox("Back face mode", &mirror);
1271 ImGui::ListBox("Front face compare function", &current_front_compare,
1272 CompareFunctionUI().labels(), CompareFunctionUI().size());
1273 ImGui::ListBox("Back face compare function", &current_back_compare,
1274 CompareFunctionUI().labels(), CompareFunctionUI().size());
1275 ImGui::End();
1276
1278 front.stencil_compare =
1279 CompareFunctionUI().FunctionOf(current_front_compare);
1281 back.stencil_compare =
1282 CompareFunctionUI().FunctionOf(current_back_compare);
1283 desc->SetStencilAttachmentDescriptors(front, back);
1284 auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
1285
1286 assert(pipeline && pipeline->IsValid());
1287
1288 pass->SetCommandLabel("Box");
1289 pass->SetPipeline(pipeline);
1290 pass->SetStencilReference(stencil_reference_read);
1291 pass->SetVertexBuffer(vertex_buffer);
1292
1293 VS::UniformBuffer uniforms;
1294 EXPECT_EQ(pass->GetOrthographicTransform(),
1295 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
1296 uniforms.mvp = pass->GetOrthographicTransform() *
1297 Matrix::MakeScale(GetContentScale());
1298 if (mirror) {
1299 uniforms.mvp = Matrix::MakeScale(Vector2(-1, 1)) * uniforms.mvp;
1300 }
1301 VS::BindUniformBuffer(*pass, data_host_buffer->EmplaceUniform(uniforms));
1302
1303 FS::FrameInfo frame_info;
1304 frame_info.current_time = GetSecondsElapsed();
1305 frame_info.cursor_position = GetCursorPosition();
1306 frame_info.window_size.x = GetWindowSize().width;
1307 frame_info.window_size.y = GetWindowSize().height;
1308
1309 FS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
1310 FS::BindContents1(*pass, boston, sampler);
1311 FS::BindContents2(*pass, bridge, sampler);
1312 if (!pass->Draw().ok()) {
1313 return false;
1314 }
1315 pass->EncodeCommands();
1316 }
1317
1318 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
1319 return false;
1320 }
1321 data_host_buffer->Reset();
1322 return true;
1323 };
1324 OpenPlaygroundHere(callback);
1325}
1326
1327TEST_P(RendererTest, CanLookupRenderTargetProperties) {
1328 auto context = GetContext();
1329 auto cmd_buffer = context->CreateCommandBuffer();
1330 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1331 GetContext()->GetResourceAllocator());
1332
1333 auto render_target = render_target_cache->CreateOffscreen(
1334 *context, {100, 100}, /*mip_count=*/1);
1335 auto render_pass = cmd_buffer->CreateRenderPass(render_target);
1336
1337 EXPECT_EQ(render_pass->GetSampleCount(), render_target.GetSampleCount());
1338 EXPECT_EQ(render_pass->GetRenderTargetPixelFormat(),
1339 render_target.GetRenderTargetPixelFormat());
1340 EXPECT_EQ(render_pass->HasStencilAttachment(),
1341 render_target.GetStencilAttachment().has_value());
1342 EXPECT_EQ(render_pass->GetRenderTargetSize(),
1343 render_target.GetRenderTargetSize());
1344 render_pass->EncodeCommands();
1345}
1346
1348 RenderTargetCreateOffscreenMSAASetsDefaultDepthStencilFormat) {
1349 auto context = GetContext();
1350 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1351 GetContext()->GetResourceAllocator());
1352
1353 RenderTarget render_target = render_target_cache->CreateOffscreenMSAA(
1354 *context, {100, 100}, /*mip_count=*/1);
1355 EXPECT_EQ(render_target.GetDepthAttachment()
1356 ->texture->GetTextureDescriptor()
1357 .format,
1358 GetContext()->GetCapabilities()->GetDefaultDepthStencilFormat());
1359}
1360
1361template <class VertexShader, class FragmentShader>
1362std::shared_ptr<Pipeline<PipelineDescriptor>> CreateDefaultPipeline(
1363 const std::shared_ptr<Context>& context) {
1364 using TexturePipelineBuilder = PipelineBuilder<VertexShader, FragmentShader>;
1365 auto pipeline_desc =
1366 TexturePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1367 if (!pipeline_desc.has_value()) {
1368 return nullptr;
1369 }
1370 pipeline_desc->SetSampleCount(SampleCount::kCount4);
1371 pipeline_desc->SetStencilAttachmentDescriptors(std::nullopt);
1372 auto pipeline =
1373 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
1374 if (!pipeline || !pipeline->IsValid()) {
1375 return nullptr;
1376 }
1377 return pipeline;
1378}
1379
1380TEST_P(RendererTest, CanSepiaToneWithSubpasses) {
1381 // Define shader types
1382 using TextureVS = TextureVertexShader;
1383 using TextureFS = TextureFragmentShader;
1384
1385 using SepiaVS = SepiaVertexShader;
1386 using SepiaFS = SepiaFragmentShader;
1387
1388 auto context = GetContext();
1389 ASSERT_TRUE(context);
1390
1391 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1392 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1393 "support it.";
1394 return;
1395 }
1396
1397 // Create pipelines.
1398 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1399 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1400
1401 ASSERT_TRUE(texture_pipeline);
1402 ASSERT_TRUE(sepia_pipeline);
1403
1404 // Vertex buffer builders.
1406 texture_vtx_builder.AddVertices({
1407 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1408 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1409 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1410 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1411 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1412 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1413 });
1414
1416 sepia_vtx_builder.AddVertices({
1417 {{100, 100, 0.0}}, // 1
1418 {{800, 100, 0.0}}, // 2
1419 {{800, 800, 0.0}}, // 3
1420 {{100, 100, 0.0}}, // 1
1421 {{800, 800, 0.0}}, // 3
1422 {{100, 800, 0.0}}, // 4
1423 });
1424
1425 auto boston = CreateTextureForFixture("boston.jpg");
1426 ASSERT_TRUE(boston);
1427
1428 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1429 ASSERT_TRUE(sampler);
1430
1432 context->GetResourceAllocator(), context->GetIdleWaiter(),
1433 context->GetCapabilities()->GetMinimumUniformAlignment());
1434 SinglePassCallback callback = [&](RenderPass& pass) {
1435 // Draw the texture.
1436 {
1437 pass.SetPipeline(texture_pipeline);
1438 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1439 *context->GetResourceAllocator()));
1440 TextureVS::UniformBuffer uniforms;
1441 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1442 Matrix::MakeScale(GetContentScale());
1443 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1444 TextureFS::BindTextureContents(pass, boston, sampler);
1445 if (!pass.Draw().ok()) {
1446 return false;
1447 }
1448 }
1449
1450 // Draw the sepia toner.
1451 {
1452 pass.SetPipeline(sepia_pipeline);
1453 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1454 *context->GetResourceAllocator()));
1455 SepiaVS::UniformBuffer uniforms;
1456 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1457 Matrix::MakeScale(GetContentScale());
1458 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1459 if (!pass.Draw().ok()) {
1460 return false;
1461 }
1462 }
1463
1464 return true;
1465 };
1466 OpenPlaygroundHere(callback);
1467}
1468
1469TEST_P(RendererTest, CanSepiaToneThenSwizzleWithSubpasses) {
1470 // Define shader types
1471 using TextureVS = TextureVertexShader;
1472 using TextureFS = TextureFragmentShader;
1473
1474 using SwizzleVS = SepiaVertexShader;
1475 using SwizzleFS = SwizzleFragmentShader;
1476
1477 using SepiaVS = SepiaVertexShader;
1478 using SepiaFS = SepiaFragmentShader;
1479
1480 auto context = GetContext();
1481 ASSERT_TRUE(context);
1482
1483 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1484 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1485 "support it.";
1486 return;
1487 }
1488
1489 // Create pipelines.
1490 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1491 auto swizzle_pipeline = CreateDefaultPipeline<SwizzleVS, SwizzleFS>(context);
1492 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1493
1494 ASSERT_TRUE(texture_pipeline);
1495 ASSERT_TRUE(swizzle_pipeline);
1496 ASSERT_TRUE(sepia_pipeline);
1497
1498 // Vertex buffer builders.
1500 texture_vtx_builder.AddVertices({
1501 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1502 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1503 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1504 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1505 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1506 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1507 });
1508
1510 sepia_vtx_builder.AddVertices({
1511 {{100, 100, 0.0}}, // 1
1512 {{800, 100, 0.0}}, // 2
1513 {{800, 800, 0.0}}, // 3
1514 {{100, 100, 0.0}}, // 1
1515 {{800, 800, 0.0}}, // 3
1516 {{100, 800, 0.0}}, // 4
1517 });
1518
1519 auto boston = CreateTextureForFixture("boston.jpg");
1520 ASSERT_TRUE(boston);
1521
1522 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1523 ASSERT_TRUE(sampler);
1524
1525 auto data_buffer = HostBuffer::Create(
1526 context->GetResourceAllocator(), context->GetIdleWaiter(),
1527 context->GetCapabilities()->GetMinimumUniformAlignment());
1528 SinglePassCallback callback = [&](RenderPass& pass) {
1529 // Draw the texture.
1530 {
1531 pass.SetPipeline(texture_pipeline);
1532 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1533 *context->GetResourceAllocator()));
1534 TextureVS::UniformBuffer uniforms;
1535 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1536 Matrix::MakeScale(GetContentScale());
1537 TextureVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1538 TextureFS::BindTextureContents(pass, boston, sampler);
1539 if (!pass.Draw().ok()) {
1540 return false;
1541 }
1542 }
1543
1544 // Draw the sepia toner.
1545 {
1546 pass.SetPipeline(sepia_pipeline);
1547 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1548 *context->GetResourceAllocator()));
1549 SepiaVS::UniformBuffer uniforms;
1550 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1551 Matrix::MakeScale(GetContentScale());
1552 SepiaVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1553 if (!pass.Draw().ok()) {
1554 return false;
1555 }
1556 }
1557
1558 // Draw the swizzle.
1559 {
1560 pass.SetPipeline(swizzle_pipeline);
1561 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1562 *context->GetResourceAllocator()));
1563 SwizzleVS::UniformBuffer uniforms;
1564 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1565 Matrix::MakeScale(GetContentScale());
1566 SwizzleVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1567 if (!pass.Draw().ok()) {
1568 return false;
1569 }
1570 }
1571
1572 return true;
1573 };
1574 OpenPlaygroundHere(callback);
1575}
1576
1577TEST_P(RendererTest, BindingNullTexturesDoesNotCrash) {
1578 using FS = BoxFadeFragmentShader;
1579
1580 auto context = GetContext();
1581 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
1582 auto command_buffer = context->CreateCommandBuffer();
1583
1584 RenderTargetAllocator allocator(context->GetResourceAllocator());
1585 RenderTarget target = allocator.CreateOffscreen(*context, {1, 1}, 1);
1586
1587 auto pass = command_buffer->CreateRenderPass(target);
1588 EXPECT_FALSE(FS::BindContents2(*pass, nullptr, sampler));
1589}
1590
1591// Clears a single cube map face by attaching it as a render target slice.
1592// Rendering to cube faces is portable down to OpenGL ES 2.0, so this runs on
1593// every backend.
1594TEST_P(RendererTest, CanRenderToTextureSlice) {
1595 auto context = GetContext();
1596 ASSERT_TRUE(context);
1597
1598 TextureDescriptor desc;
1602 desc.size = {100, 100};
1604 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1605 ASSERT_TRUE(texture);
1606
1607 ColorAttachment color0;
1608 color0.texture = texture;
1609 color0.slice = 3u; // +Y face.
1612 color0.clear_color = Color::Green();
1614 target.SetColorAttachment(color0, 0u);
1615
1616 auto buffer = context->CreateCommandBuffer();
1617 auto pass = buffer->CreateRenderPass(target);
1618 ASSERT_TRUE(pass && pass->IsValid());
1619 pass->EncodeCommands();
1620 EXPECT_TRUE(context->GetCommandQueue()->Submit({buffer}).ok());
1621}
1622
1623// Clears mip level 1 of a texture by attaching it as a render target. Skipped
1624// on OpenGL ES, where rendering to non-zero mip levels needs ES 3.0 or
1625// GL_OES_fbo_render_mipmap.
1626TEST_P(RendererTest, CanRenderToMipLevel) {
1627 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
1628 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
1629 GTEST_SKIP() << "Rendering to non-zero mip levels is gated on a GLES "
1630 "capability; covered by the Metal and Vulkan backends.";
1631 }
1632 auto context = GetContext();
1633 ASSERT_TRUE(context);
1634
1635 TextureDescriptor desc;
1638 desc.size = {100, 100};
1639 desc.mip_count = 2u;
1641 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1642 ASSERT_TRUE(texture);
1643
1644 ColorAttachment color0;
1645 color0.texture = texture;
1646 color0.mip_level = 1u;
1649 color0.clear_color = Color::Green();
1651 target.SetColorAttachment(color0, 0u);
1652 // The render area follows the mip level dimensions.
1653 EXPECT_EQ(target.GetRenderTargetSize(), ISize(50, 50));
1654
1655 auto buffer = context->CreateCommandBuffer();
1656 auto pass = buffer->CreateRenderPass(target);
1657 ASSERT_TRUE(pass && pass->IsValid());
1658 pass->EncodeCommands();
1659 EXPECT_TRUE(context->GetCommandQueue()->Submit({buffer}).ok());
1660}
1661
1662// Attachment validation rejects out-of-range mip levels and slices.
1663TEST_P(RendererTest, AttachmentRejectsOutOfRangeSubresource) {
1664 auto context = GetContext();
1665 ASSERT_TRUE(context);
1666
1667 TextureDescriptor desc;
1670 desc.size = {100, 100};
1671 desc.mip_count = 2u;
1673 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1674 ASSERT_TRUE(texture);
1675
1676 ColorAttachment color0;
1677 color0.texture = texture;
1680 EXPECT_TRUE(color0.IsValid());
1681
1682 // The out-of-range cases log validation errors on purpose.
1683 ScopedValidationDisable disable_validation;
1684
1685 color0.mip_level = 2u; // Only levels 0 and 1 exist.
1686 EXPECT_FALSE(color0.IsValid());
1687
1688 color0.mip_level = 0u;
1689 color0.slice = 1u; // A 2D texture has a single slice.
1690 EXPECT_FALSE(color0.IsValid());
1691}
1692
1693} // namespace testing
1694} // namespace impeller
1695
1696// NOLINTEND(bugprone-unchecked-optional-access)
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)
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition playground.h:71
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.
const Matrix & GetOrthographicTransform() const
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
ISize GetRenderTargetSize() const
virtual void SetInstanceCount(size_t count)
virtual fml::Status Draw()
Record the currently pending command.
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
const std::optional< DepthAttachment > & GetDepthAttachment() const
VertexBuffer CreateVertexBuffer(HostBuffer &data_host_buffer, HostBuffer &indexes_host_buffer) const
VertexBufferBuilder & AppendIndex(IndexType_ index)
void SetLabel(const std::string &label)
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
constexpr impeller::IndexType GetIndexType() const
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
uint32_t * target
FlutterDesktopBinaryReply callback
#define FML_UNREACHABLE()
Definition logging.h:128
std::shared_ptr< ImpellerAllocator > allocator
FlTexture * texture
double y
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
static const CompareFunctionUIData & CompareFunctionUI()
TEST_P(AiksTest, DrawAtlasNoColor)
Point Vector2
Definition point.h:430
float Scalar
Definition scalar.h:19
@ kNone
Does not use the index buffer.
LinePipeline::FragmentShader FS
CompareFunction
Definition formats.h:804
@ 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:602
@ 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
static std::unique_ptr< PipelineT > CreateDefaultPipeline(const Context &context)
MinMagFilter
Describes how the texture should be sampled when the texture is being shrunk (minified) or expanded (...
Definition formats.h:592
@ kNearest
Select nearest to the sample point. Most widely supported.
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< PipelineGLES > pipeline
std::shared_ptr< CommandBuffer > command_buffer
bool IsValid() const
Definition formats.cc:26
LoadAction load_action
Definition formats.h:911
std::shared_ptr< Texture > texture
Definition formats.h:909
StoreAction store_action
Definition formats.h:912
static constexpr Color Red()
Definition color.h:277
static Color Random()
Definition color.h:855
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition color.h:152
static constexpr Color Green()
Definition color.h:279
Scalar degrees
Definition scalar.h:67
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition matrix.h:641
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:650
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...
#define VALIDATION_LOG
Definition validation.h:91