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 ASSERT_TRUE(context->FlushCommandBuffers());
421}
422
423TEST_P(RendererTest, CanRenderInstanced) {
424 if (GetParam() == PlaygroundBackend::kOpenGLES ||
425 GetParam() == PlaygroundBackend::kOpenGLESSDF) {
426 // This test drives instancing through gl_InstanceIndex and a storage
427 // buffer, both of which require OpenGL ES 3.1. The portable instance-rate
428 // vertex attribute path, which works down to OpenGL ES 2.0, is covered by
429 // CanRenderInstancedWithVertexAttributes.
430 GTEST_SKIP() << "This test's instance-ID mechanism requires OpenGL ES 3.1; "
431 "CanRenderInstancedWithVertexAttributes covers the "
432 "portable instance-rate path.";
433 }
434 using VS = InstancedDrawVertexShader;
435 using FS = InstancedDrawFragmentShader;
436
438 builder.AddVertices({
439 VS::PerVertexData{Point{10, 10}},
440 VS::PerVertexData{Point{10, 110}},
441 VS::PerVertexData{Point{110, 10}},
442 VS::PerVertexData{Point{10, 110}},
443 VS::PerVertexData{Point{110, 10}},
444 VS::PerVertexData{Point{110, 110}},
445 });
446
447 ASSERT_NE(GetContext(), nullptr);
448 auto pipeline =
449 GetContext()
450 ->GetPipelineLibrary()
452 *GetContext())
453 ->SetSampleCount(SampleCount::kCount4)
454 .SetStencilAttachmentDescriptors(std::nullopt))
455
456 .Get();
457 ASSERT_TRUE(pipeline && pipeline->IsValid());
458
459 static constexpr size_t kInstancesCount = 5u;
460 VS::InstanceInfo<kInstancesCount> instances;
461 for (size_t i = 0; i < kInstancesCount; i++) {
462 instances.colors[i] = Color::Random();
463 }
464
465 auto [data_host_buffer, indexes_host_buffer] =
466 createHostBuffers(GetContext());
467 ASSERT_TRUE(OpenPlaygroundHere([&](RenderPass& pass) -> bool {
468 pass.SetPipeline(pipeline);
469 pass.SetCommandLabel("InstancedDraw");
470
471 VS::FrameInfo frame_info;
472 EXPECT_EQ(pass.GetOrthographicTransform(),
474 frame_info.mvp =
475 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
476 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
477 VS::BindInstanceInfo(pass,
478 data_host_buffer->EmplaceStorageBuffer(instances));
479 pass.SetVertexBuffer(
480 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
481
482 pass.SetInstanceCount(kInstancesCount);
483 pass.Draw();
484
485 data_host_buffer->Reset();
486 return true;
487 }));
488}
489
490TEST_P(RendererTest, CanBlitTextureToTexture) {
491 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
492 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
493 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
494 }
495 auto context = GetContext();
496 ASSERT_TRUE(context);
497
498 using VS = MipmapsVertexShader;
499 using FS = MipmapsFragmentShader;
501 ASSERT_TRUE(desc.has_value());
502 desc->SetSampleCount(SampleCount::kCount4);
503 desc->SetStencilAttachmentDescriptors(std::nullopt);
504 auto mipmaps_pipeline =
505 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
506 ASSERT_TRUE(mipmaps_pipeline);
507
508 TextureDescriptor texture_desc;
511 texture_desc.size = {800, 600};
512 texture_desc.mip_count = 1u;
514 auto texture = context->GetResourceAllocator()->CreateTexture(texture_desc);
515 ASSERT_TRUE(texture);
516
517 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
518 auto boston = CreateTextureForFixture("boston.jpg");
519 ASSERT_TRUE(bridge && boston);
520 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
521 ASSERT_TRUE(sampler);
522
523 // Vertex buffer.
525 vertex_builder.SetLabel("Box");
526 auto size = Point(boston->GetSize());
527 vertex_builder.AddVertices({
528 {{0, 0}, {0.0, 0.0}}, // 1
529 {{size.x, 0}, {1.0, 0.0}}, // 2
530 {{size.x, size.y}, {1.0, 1.0}}, // 3
531 {{0, 0}, {0.0, 0.0}}, // 1
532 {{size.x, size.y}, {1.0, 1.0}}, // 3
533 {{0, size.y}, {0.0, 1.0}}, // 4
534 });
535 auto vertex_buffer =
536 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
537 ASSERT_TRUE(vertex_buffer);
538
539 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
540 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
541 auto buffer = context->CreateCommandBuffer();
542 if (!buffer) {
543 return false;
544 }
545 buffer->SetLabel("Playground Command Buffer");
546
547 {
548 auto pass = buffer->CreateBlitPass();
549 if (!pass) {
550 return false;
551 }
552 pass->SetLabel("Playground Blit Pass");
553
554 // Blit `bridge` to the top left corner of the texture.
555 pass->AddCopy(bridge, texture);
556
557 if (!pass->EncodeCommands()) {
558 return false;
559 }
560 }
561
562 {
563 auto pass = buffer->CreateRenderPass(render_target);
564 if (!pass) {
565 return false;
566 }
567 pass->SetLabel("Playground Render Pass");
568 {
569 pass->SetCommandLabel("Image");
570 pass->SetPipeline(mipmaps_pipeline);
571 pass->SetVertexBuffer(vertex_buffer);
572
573 VS::FrameInfo frame_info;
574 EXPECT_EQ(pass->GetOrthographicTransform(),
575 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
576 frame_info.mvp = pass->GetOrthographicTransform() *
577 Matrix::MakeScale(GetContentScale());
578 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
579
580 FS::FragInfo frag_info;
581 frag_info.lod = 0;
582 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
583
584 auto sampler = context->GetSamplerLibrary()->GetSampler({});
585 FS::BindTex(*pass, texture, sampler);
586
587 pass->Draw();
588 }
589 pass->EncodeCommands();
590 }
591
592 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
593 return false;
594 }
595 data_host_buffer->Reset();
596 return true;
597 };
598 OpenPlaygroundHere(callback);
599}
600
601TEST_P(RendererTest, CanBlitTextureToBuffer) {
602 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
603 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
604 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
605 }
606 auto context = GetContext();
607 ASSERT_TRUE(context);
608
609 using VS = MipmapsVertexShader;
610 using FS = MipmapsFragmentShader;
612 ASSERT_TRUE(desc.has_value());
613 desc->SetSampleCount(SampleCount::kCount4);
614 desc->SetStencilAttachmentDescriptors(std::nullopt);
615 auto mipmaps_pipeline =
616 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
617 ASSERT_TRUE(mipmaps_pipeline);
618
619 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
620 auto boston = CreateTextureForFixture("boston.jpg");
621 ASSERT_TRUE(bridge && boston);
622 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
623 ASSERT_TRUE(sampler);
624
625 TextureDescriptor texture_desc;
628 texture_desc.size = bridge->GetTextureDescriptor().size;
629 texture_desc.mip_count = 1u;
630 texture_desc.usage = TextureUsage::kRenderTarget |
632 DeviceBufferDescriptor device_buffer_desc;
633 device_buffer_desc.storage_mode = StorageMode::kHostVisible;
634 device_buffer_desc.size =
635 bridge->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
636 auto device_buffer =
637 context->GetResourceAllocator()->CreateBuffer(device_buffer_desc);
638
639 // Vertex buffer.
641 vertex_builder.SetLabel("Box");
642 auto size = Point(boston->GetSize());
643 vertex_builder.AddVertices({
644 {{0, 0}, {0.0, 0.0}}, // 1
645 {{size.x, 0}, {1.0, 0.0}}, // 2
646 {{size.x, size.y}, {1.0, 1.0}}, // 3
647 {{0, 0}, {0.0, 0.0}}, // 1
648 {{size.x, size.y}, {1.0, 1.0}}, // 3
649 {{0, size.y}, {0.0, 1.0}}, // 4
650 });
651 auto vertex_buffer =
652 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
653 ASSERT_TRUE(vertex_buffer);
654
655 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
656 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
657 {
658 auto buffer = context->CreateCommandBuffer();
659 if (!buffer) {
660 return false;
661 }
662 buffer->SetLabel("Playground Command Buffer");
663 auto pass = buffer->CreateBlitPass();
664 if (!pass) {
665 return false;
666 }
667 pass->SetLabel("Playground Blit Pass");
668
669 // Blit `bridge` to the top left corner of the texture.
670 pass->AddCopy(bridge, device_buffer);
671 pass->EncodeCommands();
672
673 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
674 return false;
675 }
676 }
677
678 {
679 auto buffer = context->CreateCommandBuffer();
680 if (!buffer) {
681 return false;
682 }
683 buffer->SetLabel("Playground Command Buffer");
684
685 auto pass = buffer->CreateRenderPass(render_target);
686 if (!pass) {
687 return false;
688 }
689 pass->SetLabel("Playground Render Pass");
690 {
691 pass->SetCommandLabel("Image");
692 pass->SetPipeline(mipmaps_pipeline);
693 pass->SetVertexBuffer(vertex_buffer);
694
695 VS::FrameInfo frame_info;
696 EXPECT_EQ(pass->GetOrthographicTransform(),
697 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
698 frame_info.mvp = pass->GetOrthographicTransform() *
699 Matrix::MakeScale(GetContentScale());
700 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
701
702 FS::FragInfo frag_info;
703 frag_info.lod = 0;
704 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
705
706 raw_ptr<const Sampler> sampler =
707 context->GetSamplerLibrary()->GetSampler({});
708 auto buffer_view = DeviceBuffer::AsBufferView(device_buffer);
709 auto texture =
710 context->GetResourceAllocator()->CreateTexture(texture_desc);
711 if (!texture->SetContents(device_buffer->OnGetContents(),
712 buffer_view.GetRange().length)) {
713 VALIDATION_LOG << "Could not upload texture to device memory";
714 return false;
715 }
716 FS::BindTex(*pass, texture, sampler);
717
718 pass->Draw().ok();
719 }
720 pass->EncodeCommands();
721 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
722 return false;
723 }
724 }
725 data_host_buffer->Reset();
726 return true;
727 };
728 OpenPlaygroundHere(callback);
729}
730
731TEST_P(RendererTest, CanGenerateMipmaps) {
732 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
733 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
734 GTEST_SKIP() << "Mipmap test shader not supported on GLES.";
735 }
736 auto context = GetContext();
737 ASSERT_TRUE(context);
738
739 using VS = MipmapsVertexShader;
740 using FS = MipmapsFragmentShader;
742 ASSERT_TRUE(desc.has_value());
743 desc->SetSampleCount(SampleCount::kCount4);
744 desc->SetStencilAttachmentDescriptors(std::nullopt);
745 auto mipmaps_pipeline =
746 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
747 ASSERT_TRUE(mipmaps_pipeline);
748
749 auto boston = CreateTextureForFixture("boston.jpg", true);
750 ASSERT_TRUE(boston);
751
752 // Vertex buffer.
754 vertex_builder.SetLabel("Box");
755 auto size = Point(boston->GetSize());
756 vertex_builder.AddVertices({
757 {{0, 0}, {0.0, 0.0}}, // 1
758 {{size.x, 0}, {1.0, 0.0}}, // 2
759 {{size.x, size.y}, {1.0, 1.0}}, // 3
760 {{0, 0}, {0.0, 0.0}}, // 1
761 {{size.x, size.y}, {1.0, 1.0}}, // 3
762 {{0, size.y}, {0.0, 1.0}}, // 4
763 });
764 auto vertex_buffer =
765 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
766 ASSERT_TRUE(vertex_buffer);
767
768 bool first_frame = true;
769 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
770 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
771 const char* mip_filter_names[] = {"Base", "Nearest", "Linear"};
772 const MipFilter mip_filters[] = {MipFilter::kBase, MipFilter::kNearest,
774 const char* min_filter_names[] = {"Nearest", "Linear"};
775 const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
777
778 // UI state.
779 static int selected_mip_filter = 1;
780 static int selected_min_filter = 0;
781 static float lod = 4.5;
782
783 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
784 ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names,
785 sizeof(mip_filter_names) / sizeof(char*));
786 ImGui::Combo("Min filter", &selected_min_filter, min_filter_names,
787 sizeof(min_filter_names) / sizeof(char*));
788 ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1);
789 ImGui::End();
790
791 auto buffer = context->CreateCommandBuffer();
792 if (!buffer) {
793 return false;
794 }
795 buffer->SetLabel("Playground Command Buffer");
796
797 if (first_frame) {
798 auto pass = buffer->CreateBlitPass();
799 if (!pass) {
800 return false;
801 }
802 pass->SetLabel("Playground Blit Pass");
803
804 pass->GenerateMipmap(boston, "Boston Mipmap");
805
806 pass->EncodeCommands();
807 }
808
809 first_frame = false;
810
811 {
812 auto pass = buffer->CreateRenderPass(render_target);
813 if (!pass) {
814 return false;
815 }
816 pass->SetLabel("Playground Render Pass");
817 {
818 pass->SetCommandLabel("Image LOD");
819 pass->SetPipeline(mipmaps_pipeline);
820 pass->SetVertexBuffer(vertex_buffer);
821
822 VS::FrameInfo frame_info;
823 EXPECT_EQ(pass->GetOrthographicTransform(),
824 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
825 frame_info.mvp = pass->GetOrthographicTransform() *
826 Matrix::MakeScale(GetContentScale());
827 VS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
828
829 FS::FragInfo frag_info;
830 frag_info.lod = lod;
831 FS::BindFragInfo(*pass, data_host_buffer->EmplaceUniform(frag_info));
832
833 SamplerDescriptor sampler_desc;
834 sampler_desc.mip_filter = mip_filters[selected_mip_filter];
835 sampler_desc.min_filter = min_filters[selected_min_filter];
836 raw_ptr<const Sampler> sampler =
837 context->GetSamplerLibrary()->GetSampler(sampler_desc);
838 FS::BindTex(*pass, boston, sampler);
839
840 pass->Draw();
841 }
842 pass->EncodeCommands();
843 }
844
845 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
846 return false;
847 }
848 data_host_buffer->Reset();
849 return true;
850 };
851 OpenPlaygroundHere(callback);
852}
853
854TEST_P(RendererTest, TheImpeller) {
855 using VS = ImpellerVertexShader;
856 using FS = ImpellerFragmentShader;
857
858 auto context = GetContext();
859 auto pipeline_descriptor =
861 ASSERT_TRUE(pipeline_descriptor.has_value());
862 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
863 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
864 auto pipeline =
865 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
866 ASSERT_TRUE(pipeline && pipeline->IsValid());
867
868 auto blue_noise = CreateTextureForFixture("blue_noise.png");
869 SamplerDescriptor noise_sampler_desc;
872 raw_ptr<const Sampler> noise_sampler =
873 context->GetSamplerLibrary()->GetSampler(noise_sampler_desc);
874
875 auto cube_map = CreateTextureCubeForFixture(
876 {"table_mountain_px.png", "table_mountain_nx.png",
877 "table_mountain_py.png", "table_mountain_ny.png",
878 "table_mountain_pz.png", "table_mountain_nz.png"});
879 raw_ptr<const Sampler> cube_map_sampler =
880 context->GetSamplerLibrary()->GetSampler({});
881
882 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
883 SinglePassCallback callback = [&](RenderPass& pass) {
884 auto size = pass.GetRenderTargetSize();
885
886 pass.SetPipeline(pipeline);
887 pass.SetCommandLabel("Impeller SDF scene");
889 builder.AddVertices({{Point()},
890 {Point(0, size.height)},
891 {Point(size.width, 0)},
892 {Point(size.width, 0)},
893 {Point(0, size.height)},
894 {Point(size.width, size.height)}});
895 pass.SetVertexBuffer(
896 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
897
898 VS::FrameInfo frame_info;
899 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
900 frame_info.mvp = pass.GetOrthographicTransform();
901 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
902
903 FS::FragInfo fs_uniform;
904 fs_uniform.texture_size = Point(size);
905 fs_uniform.time = GetSecondsElapsed();
906 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
907 FS::BindBlueNoise(pass, blue_noise, noise_sampler);
908 FS::BindCubeMap(pass, cube_map, cube_map_sampler);
909
910 pass.Draw().ok();
911 data_host_buffer->Reset();
912 return true;
913 };
914 OpenPlaygroundHere(callback);
915}
916
918 using VS = PlanetVertexShader;
919 using FS = PlanetFragmentShader;
920
921 auto context = GetContext();
922 auto pipeline_descriptor =
924 ASSERT_TRUE(pipeline_descriptor.has_value());
925 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
926 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
927 auto pipeline =
928 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
929 ASSERT_TRUE(pipeline && pipeline->IsValid());
930
931 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
932 SinglePassCallback callback = [&](RenderPass& pass) {
933 static Scalar speed = 0.1;
934 static Scalar planet_size = 550.0;
935 static bool show_normals = false;
936 static bool show_noise = false;
937 static Scalar seed_value = 42.0;
938
939 auto size = pass.GetRenderTargetSize();
940
941 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
942 ImGui::SliderFloat("Speed", &speed, 0.0, 10.0);
943 ImGui::SliderFloat("Planet Size", &planet_size, 0.1, 1000);
944 ImGui::Checkbox("Show Normals", &show_normals);
945 ImGui::Checkbox("Show Noise", &show_noise);
946 ImGui::InputFloat("Seed Value", &seed_value);
947 ImGui::End();
948
949 pass.SetPipeline(pipeline);
950 pass.SetCommandLabel("Planet scene");
952 builder.AddVertices({{Point()},
953 {Point(0, size.height)},
954 {Point(size.width, 0)},
955 {Point(size.width, 0)},
956 {Point(0, size.height)},
957 {Point(size.width, size.height)}});
958 pass.SetVertexBuffer(
959 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
960
961 VS::FrameInfo frame_info;
962 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
963 frame_info.mvp = pass.GetOrthographicTransform();
964 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
965
966 FS::FragInfo fs_uniform;
967 fs_uniform.resolution = Point(size);
968 fs_uniform.time = GetSecondsElapsed();
969 fs_uniform.speed = speed;
970 fs_uniform.planet_size = planet_size;
971 fs_uniform.show_normals = show_normals ? 1.0 : 0.0;
972 fs_uniform.show_noise = show_noise ? 1.0 : 0.0;
973 fs_uniform.seed_value = seed_value;
974 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
975
976 pass.Draw().ok();
977 data_host_buffer->Reset();
978 return true;
979 };
980 OpenPlaygroundHere(callback);
981}
982
983TEST_P(RendererTest, ArrayUniforms) {
984 using VS = ArrayVertexShader;
985 using FS = ArrayFragmentShader;
986
987 auto context = GetContext();
988 auto pipeline_descriptor =
990 ASSERT_TRUE(pipeline_descriptor.has_value());
991 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
992 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
993 auto pipeline =
994 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
995 ASSERT_TRUE(pipeline && pipeline->IsValid());
996
997 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
998 SinglePassCallback callback = [&](RenderPass& pass) {
999 auto size = pass.GetRenderTargetSize();
1000
1001 pass.SetPipeline(pipeline);
1002 pass.SetCommandLabel("Google Dots");
1004 builder.AddVertices({{Point()},
1005 {Point(0, size.height)},
1006 {Point(size.width, 0)},
1007 {Point(size.width, 0)},
1008 {Point(0, size.height)},
1009 {Point(size.width, size.height)}});
1010 pass.SetVertexBuffer(
1011 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
1012
1013 VS::FrameInfo frame_info;
1014 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
1015 frame_info.mvp =
1016 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
1017 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
1018
1019 auto time = GetSecondsElapsed();
1020 auto y_pos = [&time](float x) {
1021 return 400 + 10 * std::cos(time * 5 + x / 6);
1022 };
1023
1024 FS::FragInfo fs_uniform = {
1025 .circle_positions = {Point(430, y_pos(0)), Point(480, y_pos(1)),
1026 Point(530, y_pos(2)), Point(580, y_pos(3))},
1027 .colors = {Color::MakeRGBA8(66, 133, 244, 255),
1028 Color::MakeRGBA8(219, 68, 55, 255),
1029 Color::MakeRGBA8(244, 180, 0, 255),
1030 Color::MakeRGBA8(15, 157, 88, 255)},
1031 };
1032 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
1033
1034 pass.Draw();
1035 data_host_buffer->Reset();
1036 return true;
1037 };
1038 OpenPlaygroundHere(callback);
1039}
1040
1041TEST_P(RendererTest, InactiveUniforms) {
1042 using VS = InactiveUniformsVertexShader;
1043 using FS = InactiveUniformsFragmentShader;
1044
1045 auto context = GetContext();
1046 auto pipeline_descriptor =
1048 ASSERT_TRUE(pipeline_descriptor.has_value());
1049 pipeline_descriptor->SetSampleCount(SampleCount::kCount4);
1050 pipeline_descriptor->SetStencilAttachmentDescriptors(std::nullopt);
1051 auto pipeline =
1052 context->GetPipelineLibrary()->GetPipeline(pipeline_descriptor).Get();
1053 ASSERT_TRUE(pipeline && pipeline->IsValid());
1054
1055 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
1056 SinglePassCallback callback = [&](RenderPass& pass) {
1057 auto size = pass.GetRenderTargetSize();
1058
1059 pass.SetPipeline(pipeline);
1060 pass.SetCommandLabel("Inactive Uniform");
1061
1063 builder.AddVertices({{Point()},
1064 {Point(0, size.height)},
1065 {Point(size.width, 0)},
1066 {Point(size.width, 0)},
1067 {Point(0, size.height)},
1068 {Point(size.width, size.height)}});
1069 pass.SetVertexBuffer(
1070 builder.CreateVertexBuffer(*data_host_buffer, *indexes_host_buffer));
1071
1072 VS::FrameInfo frame_info;
1073 EXPECT_EQ(pass.GetOrthographicTransform(), Matrix::MakeOrthographic(size));
1074 frame_info.mvp =
1075 pass.GetOrthographicTransform() * Matrix::MakeScale(GetContentScale());
1076 VS::BindFrameInfo(pass, data_host_buffer->EmplaceUniform(frame_info));
1077
1078 FS::FragInfo fs_uniform = {.unused_color = Color::Red(),
1079 .color = Color::Green()};
1080 FS::BindFragInfo(pass, data_host_buffer->EmplaceUniform(fs_uniform));
1081
1082 pass.Draw().ok();
1083 data_host_buffer->Reset();
1084 return true;
1085 };
1086 OpenPlaygroundHere(callback);
1087}
1088
1089TEST_P(RendererTest, DefaultIndexSize) {
1090 using VS = BoxFadeVertexShader;
1091
1092 // Default to 16bit index buffer size, as this is a reasonable default and
1093 // supported on all backends without extensions.
1095 vertex_builder.AppendIndex(0u);
1096 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::k16bit);
1097}
1098
1099TEST_P(RendererTest, DefaultIndexBehavior) {
1100 using VS = BoxFadeVertexShader;
1101
1102 // Do not create any index buffer if no indices were provided.
1104 ASSERT_EQ(vertex_builder.GetIndexType(), IndexType::kNone);
1105}
1106
1108 // Does not create index buffer if one is provided.
1109 using VS = BoxFadeVertexShader;
1111 vertex_builder.SetLabel("Box");
1112 vertex_builder.AddVertices({
1113 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1114 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1115 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1116 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1117 });
1118 vertex_builder.AppendIndex(0);
1119 vertex_builder.AppendIndex(1);
1120 vertex_builder.AppendIndex(2);
1121 vertex_builder.AppendIndex(1);
1122 vertex_builder.AppendIndex(2);
1123 vertex_builder.AppendIndex(3);
1124
1125 ASSERT_EQ(vertex_builder.GetIndexCount(), 6u);
1126 ASSERT_EQ(vertex_builder.GetVertexCount(), 4u);
1127}
1128
1130 public:
1132 labels_.push_back("Never");
1133 functions_.push_back(CompareFunction::kNever);
1134 labels_.push_back("Always");
1135 functions_.push_back(CompareFunction::kAlways);
1136 labels_.push_back("Less");
1137 functions_.push_back(CompareFunction::kLess);
1138 labels_.push_back("Equal");
1139 functions_.push_back(CompareFunction::kEqual);
1140 labels_.push_back("LessEqual");
1141 functions_.push_back(CompareFunction::kLessEqual);
1142 labels_.push_back("Greater");
1143 functions_.push_back(CompareFunction::kGreater);
1144 labels_.push_back("NotEqual");
1145 functions_.push_back(CompareFunction::kNotEqual);
1146 labels_.push_back("GreaterEqual");
1147 functions_.push_back(CompareFunction::kGreaterEqual);
1148 assert(labels_.size() == functions_.size());
1149 }
1150
1151 const char* const* labels() const { return &labels_[0]; }
1152
1153 int size() const { return labels_.size(); }
1154
1155 int IndexOf(CompareFunction func) const {
1156 for (size_t i = 0; i < functions_.size(); i++) {
1157 if (functions_[i] == func) {
1158 return i;
1159 }
1160 }
1162 return -1;
1163 }
1164
1165 CompareFunction FunctionOf(int index) const { return functions_[index]; }
1166
1167 private:
1168 std::vector<const char*> labels_;
1169 std::vector<CompareFunction> functions_;
1170};
1171
1174 return data;
1175}
1176
1177TEST_P(RendererTest, StencilMask) {
1178 using VS = BoxFadeVertexShader;
1179 using FS = BoxFadeFragmentShader;
1180 auto context = GetContext();
1181 ASSERT_TRUE(context);
1182 using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1183 auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1184 ASSERT_TRUE(desc.has_value());
1185
1186 // Vertex buffer.
1188 vertex_builder.SetLabel("Box");
1189 vertex_builder.AddVertices({
1190 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1191 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1192 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1193 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1194 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1195 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1196 });
1197 auto vertex_buffer =
1198 vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator());
1199 ASSERT_TRUE(vertex_buffer);
1200
1201 desc->SetSampleCount(SampleCount::kCount4);
1202 desc->SetStencilAttachmentDescriptors(std::nullopt);
1203
1204 auto bridge = CreateTextureForFixture("bay_bridge.jpg");
1205 auto boston = CreateTextureForFixture("boston.jpg");
1206 ASSERT_TRUE(bridge && boston);
1207 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
1208 ASSERT_TRUE(sampler);
1209
1210 static bool mirror = false;
1211 static int stencil_reference_write = 0xFF;
1212 static int stencil_reference_read = 0x1;
1213 std::vector<uint8_t> stencil_contents;
1214 static int last_stencil_contents_reference_value = 0;
1215 static int current_front_compare =
1217 static int current_back_compare =
1219
1220 auto [data_host_buffer, indexes_host_buffer] = createHostBuffers(context);
1221 Playground::RenderCallback callback = [&](RenderTarget& render_target) {
1222 auto buffer = context->CreateCommandBuffer();
1223 if (!buffer) {
1224 return false;
1225 }
1226 buffer->SetLabel("Playground Command Buffer");
1227
1228 {
1229 // Configure the stencil attachment for the test.
1230 RenderTarget::AttachmentConfig stencil_config;
1231 stencil_config.load_action = LoadAction::kLoad;
1232 stencil_config.store_action = StoreAction::kDontCare;
1233 stencil_config.storage_mode = StorageMode::kHostVisible;
1234 render_target.SetupDepthStencilAttachments(
1235 *context, *context->GetResourceAllocator(),
1236 render_target.GetRenderTargetSize(), true, "stencil", stencil_config);
1237 // Fill the stencil buffer with an checkerboard pattern.
1238 const auto target_width = render_target.GetRenderTargetSize().width;
1239 const auto target_height = render_target.GetRenderTargetSize().height;
1240 const size_t target_size = target_width * target_height;
1241 if (stencil_contents.size() != target_size ||
1242 last_stencil_contents_reference_value != stencil_reference_write) {
1243 stencil_contents.resize(target_size);
1244 last_stencil_contents_reference_value = stencil_reference_write;
1245 for (int y = 0; y < target_height; y++) {
1246 for (int x = 0; x < target_width; x++) {
1247 const auto index = y * target_width + x;
1248 const auto kCheckSize = 64;
1249 const auto value =
1250 (((y / kCheckSize) + (x / kCheckSize)) % 2 == 0) *
1251 stencil_reference_write;
1252 stencil_contents[index] = value;
1253 }
1254 }
1255 }
1256 if (!render_target.GetStencilAttachment()->texture->SetContents(
1257 stencil_contents.data(), stencil_contents.size(), 0, false)) {
1258 VALIDATION_LOG << "Could not upload stencil contents to device memory";
1259 return false;
1260 }
1261 auto pass = buffer->CreateRenderPass(render_target);
1262 if (!pass) {
1263 return false;
1264 }
1265 pass->SetLabel("Stencil Buffer");
1266 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1267 ImGui::SliderInt("Stencil Write Value", &stencil_reference_write, 0,
1268 0xFF);
1269 ImGui::SliderInt("Stencil Compare Value", &stencil_reference_read, 0,
1270 0xFF);
1271 ImGui::Checkbox("Back face mode", &mirror);
1272 ImGui::ListBox("Front face compare function", &current_front_compare,
1273 CompareFunctionUI().labels(), CompareFunctionUI().size());
1274 ImGui::ListBox("Back face compare function", &current_back_compare,
1275 CompareFunctionUI().labels(), CompareFunctionUI().size());
1276 ImGui::End();
1277
1279 front.stencil_compare =
1280 CompareFunctionUI().FunctionOf(current_front_compare);
1282 back.stencil_compare =
1283 CompareFunctionUI().FunctionOf(current_back_compare);
1284 desc->SetStencilAttachmentDescriptors(front, back);
1285 auto pipeline = context->GetPipelineLibrary()->GetPipeline(desc).Get();
1286
1287 assert(pipeline && pipeline->IsValid());
1288
1289 pass->SetCommandLabel("Box");
1290 pass->SetPipeline(pipeline);
1291 pass->SetStencilReference(stencil_reference_read);
1292 pass->SetVertexBuffer(vertex_buffer);
1293
1294 VS::UniformBuffer uniforms;
1295 EXPECT_EQ(pass->GetOrthographicTransform(),
1296 Matrix::MakeOrthographic(pass->GetRenderTargetSize()));
1297 uniforms.mvp = pass->GetOrthographicTransform() *
1298 Matrix::MakeScale(GetContentScale());
1299 if (mirror) {
1300 uniforms.mvp = Matrix::MakeScale(Vector2(-1, 1)) * uniforms.mvp;
1301 }
1302 VS::BindUniformBuffer(*pass, data_host_buffer->EmplaceUniform(uniforms));
1303
1304 FS::FrameInfo frame_info;
1305 frame_info.current_time = GetSecondsElapsed();
1306 frame_info.cursor_position = GetCursorPosition();
1307 frame_info.window_size.x = GetWindowSize().width;
1308 frame_info.window_size.y = GetWindowSize().height;
1309
1310 FS::BindFrameInfo(*pass, data_host_buffer->EmplaceUniform(frame_info));
1311 FS::BindContents1(*pass, boston, sampler);
1312 FS::BindContents2(*pass, bridge, sampler);
1313 if (!pass->Draw().ok()) {
1314 return false;
1315 }
1316 pass->EncodeCommands();
1317 }
1318
1319 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
1320 return false;
1321 }
1322 data_host_buffer->Reset();
1323 return true;
1324 };
1325 OpenPlaygroundHere(callback);
1326}
1327
1328TEST_P(RendererTest, CanLookupRenderTargetProperties) {
1329 auto context = GetContext();
1330 auto cmd_buffer = context->CreateCommandBuffer();
1331 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1332 GetContext()->GetResourceAllocator());
1333
1334 auto render_target = render_target_cache->CreateOffscreen(
1335 *context, {100, 100}, /*mip_count=*/1);
1336 auto render_pass = cmd_buffer->CreateRenderPass(render_target);
1337
1338 EXPECT_EQ(render_pass->GetSampleCount(), render_target.GetSampleCount());
1339 EXPECT_EQ(render_pass->GetRenderTargetPixelFormat(),
1340 render_target.GetRenderTargetPixelFormat());
1341 EXPECT_EQ(render_pass->HasStencilAttachment(),
1342 render_target.GetStencilAttachment().has_value());
1343 EXPECT_EQ(render_pass->GetRenderTargetSize(),
1344 render_target.GetRenderTargetSize());
1345 render_pass->EncodeCommands();
1346}
1347
1349 RenderTargetCreateOffscreenMSAASetsDefaultDepthStencilFormat) {
1350 auto context = GetContext();
1351 auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1352 GetContext()->GetResourceAllocator());
1353
1354 RenderTarget render_target = render_target_cache->CreateOffscreenMSAA(
1355 *context, {100, 100}, /*mip_count=*/1);
1356 EXPECT_EQ(render_target.GetDepthAttachment()
1357 ->texture->GetTextureDescriptor()
1358 .format,
1359 GetContext()->GetCapabilities()->GetDefaultDepthStencilFormat());
1360}
1361
1362template <class VertexShader, class FragmentShader>
1363std::shared_ptr<Pipeline<PipelineDescriptor>> CreateDefaultPipeline(
1364 const std::shared_ptr<Context>& context) {
1365 using TexturePipelineBuilder = PipelineBuilder<VertexShader, FragmentShader>;
1366 auto pipeline_desc =
1367 TexturePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
1368 if (!pipeline_desc.has_value()) {
1369 return nullptr;
1370 }
1371 pipeline_desc->SetSampleCount(SampleCount::kCount4);
1372 pipeline_desc->SetStencilAttachmentDescriptors(std::nullopt);
1373 auto pipeline =
1374 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
1375 if (!pipeline || !pipeline->IsValid()) {
1376 return nullptr;
1377 }
1378 return pipeline;
1379}
1380
1381TEST_P(RendererTest, CanSepiaToneWithSubpasses) {
1382 // Define shader types
1383 using TextureVS = TextureVertexShader;
1384 using TextureFS = TextureFragmentShader;
1385
1386 using SepiaVS = SepiaVertexShader;
1387 using SepiaFS = SepiaFragmentShader;
1388
1389 auto context = GetContext();
1390 ASSERT_TRUE(context);
1391
1392 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1393 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1394 "support it.";
1395 return;
1396 }
1397
1398 // Create pipelines.
1399 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1400 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1401
1402 ASSERT_TRUE(texture_pipeline);
1403 ASSERT_TRUE(sepia_pipeline);
1404
1405 // Vertex buffer builders.
1407 texture_vtx_builder.AddVertices({
1408 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1409 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1410 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1411 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1412 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1413 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1414 });
1415
1417 sepia_vtx_builder.AddVertices({
1418 {{100, 100, 0.0}}, // 1
1419 {{800, 100, 0.0}}, // 2
1420 {{800, 800, 0.0}}, // 3
1421 {{100, 100, 0.0}}, // 1
1422 {{800, 800, 0.0}}, // 3
1423 {{100, 800, 0.0}}, // 4
1424 });
1425
1426 auto boston = CreateTextureForFixture("boston.jpg");
1427 ASSERT_TRUE(boston);
1428
1429 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1430 ASSERT_TRUE(sampler);
1431
1433 context->GetResourceAllocator(), context->GetIdleWaiter(),
1434 context->GetCapabilities()->GetMinimumUniformAlignment());
1435 SinglePassCallback callback = [&](RenderPass& pass) {
1436 // Draw the texture.
1437 {
1438 pass.SetPipeline(texture_pipeline);
1439 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1440 *context->GetResourceAllocator()));
1441 TextureVS::UniformBuffer uniforms;
1442 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1443 Matrix::MakeScale(GetContentScale());
1444 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1445 TextureFS::BindTextureContents(pass, boston, sampler);
1446 if (!pass.Draw().ok()) {
1447 return false;
1448 }
1449 }
1450
1451 // Draw the sepia toner.
1452 {
1453 pass.SetPipeline(sepia_pipeline);
1454 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1455 *context->GetResourceAllocator()));
1456 SepiaVS::UniformBuffer uniforms;
1457 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1458 Matrix::MakeScale(GetContentScale());
1459 SepiaVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
1460 if (!pass.Draw().ok()) {
1461 return false;
1462 }
1463 }
1464
1465 return true;
1466 };
1467 OpenPlaygroundHere(callback);
1468}
1469
1470TEST_P(RendererTest, CanSepiaToneThenSwizzleWithSubpasses) {
1471 // Define shader types
1472 using TextureVS = TextureVertexShader;
1473 using TextureFS = TextureFragmentShader;
1474
1475 using SwizzleVS = SepiaVertexShader;
1476 using SwizzleFS = SwizzleFragmentShader;
1477
1478 using SepiaVS = SepiaVertexShader;
1479 using SepiaFS = SepiaFragmentShader;
1480
1481 auto context = GetContext();
1482 ASSERT_TRUE(context);
1483
1484 if (!context->GetCapabilities()->SupportsFramebufferFetch()) {
1485 GTEST_SKIP() << "This test uses framebuffer fetch and the backend doesn't "
1486 "support it.";
1487 return;
1488 }
1489
1490 // Create pipelines.
1491 auto texture_pipeline = CreateDefaultPipeline<TextureVS, TextureFS>(context);
1492 auto swizzle_pipeline = CreateDefaultPipeline<SwizzleVS, SwizzleFS>(context);
1493 auto sepia_pipeline = CreateDefaultPipeline<SepiaVS, SepiaFS>(context);
1494
1495 ASSERT_TRUE(texture_pipeline);
1496 ASSERT_TRUE(swizzle_pipeline);
1497 ASSERT_TRUE(sepia_pipeline);
1498
1499 // Vertex buffer builders.
1501 texture_vtx_builder.AddVertices({
1502 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1503 {{800, 100, 0.0}, {1.0, 0.0}}, // 2
1504 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1505 {{100, 100, 0.0}, {0.0, 0.0}}, // 1
1506 {{800, 800, 0.0}, {1.0, 1.0}}, // 3
1507 {{100, 800, 0.0}, {0.0, 1.0}}, // 4
1508 });
1509
1511 sepia_vtx_builder.AddVertices({
1512 {{100, 100, 0.0}}, // 1
1513 {{800, 100, 0.0}}, // 2
1514 {{800, 800, 0.0}}, // 3
1515 {{100, 100, 0.0}}, // 1
1516 {{800, 800, 0.0}}, // 3
1517 {{100, 800, 0.0}}, // 4
1518 });
1519
1520 auto boston = CreateTextureForFixture("boston.jpg");
1521 ASSERT_TRUE(boston);
1522
1523 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
1524 ASSERT_TRUE(sampler);
1525
1526 auto data_buffer = HostBuffer::Create(
1527 context->GetResourceAllocator(), context->GetIdleWaiter(),
1528 context->GetCapabilities()->GetMinimumUniformAlignment());
1529 SinglePassCallback callback = [&](RenderPass& pass) {
1530 // Draw the texture.
1531 {
1532 pass.SetPipeline(texture_pipeline);
1533 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
1534 *context->GetResourceAllocator()));
1535 TextureVS::UniformBuffer uniforms;
1536 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1537 Matrix::MakeScale(GetContentScale());
1538 TextureVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1539 TextureFS::BindTextureContents(pass, boston, sampler);
1540 if (!pass.Draw().ok()) {
1541 return false;
1542 }
1543 }
1544
1545 // Draw the sepia toner.
1546 {
1547 pass.SetPipeline(sepia_pipeline);
1548 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1549 *context->GetResourceAllocator()));
1550 SepiaVS::UniformBuffer uniforms;
1551 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1552 Matrix::MakeScale(GetContentScale());
1553 SepiaVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1554 if (!pass.Draw().ok()) {
1555 return false;
1556 }
1557 }
1558
1559 // Draw the swizzle.
1560 {
1561 pass.SetPipeline(swizzle_pipeline);
1562 pass.SetVertexBuffer(sepia_vtx_builder.CreateVertexBuffer(
1563 *context->GetResourceAllocator()));
1564 SwizzleVS::UniformBuffer uniforms;
1565 uniforms.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
1566 Matrix::MakeScale(GetContentScale());
1567 SwizzleVS::BindUniformBuffer(pass, data_buffer->EmplaceUniform(uniforms));
1568 if (!pass.Draw().ok()) {
1569 return false;
1570 }
1571 }
1572
1573 return true;
1574 };
1575 OpenPlaygroundHere(callback);
1576}
1577
1578TEST_P(RendererTest, BindingNullTexturesDoesNotCrash) {
1579 using FS = BoxFadeFragmentShader;
1580
1581 auto context = GetContext();
1582 raw_ptr<const Sampler> sampler = context->GetSamplerLibrary()->GetSampler({});
1583 auto command_buffer = context->CreateCommandBuffer();
1584
1585 RenderTargetAllocator allocator(context->GetResourceAllocator());
1586 RenderTarget target = allocator.CreateOffscreen(*context, {1, 1}, 1);
1587
1588 auto pass = command_buffer->CreateRenderPass(target);
1589 EXPECT_FALSE(FS::BindContents2(*pass, nullptr, sampler));
1590}
1591
1592// Clears a single cube map face by attaching it as a render target slice.
1593// Rendering to cube faces is portable down to OpenGL ES 2.0, so this runs on
1594// every backend.
1595TEST_P(RendererTest, CanRenderToTextureSlice) {
1596 auto context = GetContext();
1597 ASSERT_TRUE(context);
1598
1599 TextureDescriptor desc;
1603 desc.size = {100, 100};
1605 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1606 ASSERT_TRUE(texture);
1607
1608 ColorAttachment color0;
1609 color0.texture = texture;
1610 color0.slice = 3u; // +Y face.
1613 color0.clear_color = Color::Green();
1615 target.SetColorAttachment(color0, 0u);
1616
1617 auto buffer = context->CreateCommandBuffer();
1618 auto pass = buffer->CreateRenderPass(target);
1619 ASSERT_TRUE(pass && pass->IsValid());
1620 pass->EncodeCommands();
1621 EXPECT_TRUE(context->GetCommandQueue()->Submit({buffer}).ok());
1622}
1623
1624// Clears mip level 1 of a texture by attaching it as a render target. Skipped
1625// on OpenGL ES, where rendering to non-zero mip levels needs ES 3.0 or
1626// GL_OES_fbo_render_mipmap.
1627TEST_P(RendererTest, CanRenderToMipLevel) {
1628 if (GetBackend() == PlaygroundBackend::kOpenGLES ||
1629 GetBackend() == PlaygroundBackend::kOpenGLESSDF) {
1630 GTEST_SKIP() << "Rendering to non-zero mip levels is gated on a GLES "
1631 "capability; covered by the Metal and Vulkan backends.";
1632 }
1633 auto context = GetContext();
1634 ASSERT_TRUE(context);
1635
1636 TextureDescriptor desc;
1639 desc.size = {100, 100};
1640 desc.mip_count = 2u;
1642 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1643 ASSERT_TRUE(texture);
1644
1645 ColorAttachment color0;
1646 color0.texture = texture;
1647 color0.mip_level = 1u;
1650 color0.clear_color = Color::Green();
1652 target.SetColorAttachment(color0, 0u);
1653 // The render area follows the mip level dimensions.
1654 EXPECT_EQ(target.GetRenderTargetSize(), ISize(50, 50));
1655
1656 auto buffer = context->CreateCommandBuffer();
1657 auto pass = buffer->CreateRenderPass(target);
1658 ASSERT_TRUE(pass && pass->IsValid());
1659 pass->EncodeCommands();
1660 EXPECT_TRUE(context->GetCommandQueue()->Submit({buffer}).ok());
1661}
1662
1663// Attachment validation rejects out-of-range mip levels and slices.
1664TEST_P(RendererTest, AttachmentRejectsOutOfRangeSubresource) {
1665 auto context = GetContext();
1666 ASSERT_TRUE(context);
1667
1668 TextureDescriptor desc;
1671 desc.size = {100, 100};
1672 desc.mip_count = 2u;
1674 auto texture = context->GetResourceAllocator()->CreateTexture(desc);
1675 ASSERT_TRUE(texture);
1676
1677 ColorAttachment color0;
1678 color0.texture = texture;
1681 EXPECT_TRUE(color0.IsValid());
1682
1683 // The out-of-range cases log validation errors on purpose.
1684 ScopedValidationDisable disable_validation;
1685
1686 color0.mip_level = 2u; // Only levels 0 and 1 exist.
1687 EXPECT_FALSE(color0.IsValid());
1688
1689 color0.mip_level = 0u;
1690 color0.slice = 1u; // A 2D texture has a single slice.
1691 EXPECT_FALSE(color0.IsValid());
1692}
1693
1694} // namespace testing
1695} // namespace impeller
1696
1697// 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:70
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