Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
golden_playground_test_mac.cc File Reference

Go to the source code of this file.

Classes

struct  impeller::GoldenPlaygroundTest::GoldenPlaygroundTestImpl
 

Namespaces

namespace  impeller
 

Macros

#define GLFW_INCLUDE_NONE
 
#define IMP_AIKSTEST(name)
 

Variables

static const std::vector< std::string > impeller::kSkipTests
 

Macro Definition Documentation

◆ GLFW_INCLUDE_NONE

#define GLFW_INCLUDE_NONE

Definition at line 29 of file golden_playground_test_mac.cc.

◆ IMP_AIKSTEST

#define IMP_AIKSTEST (   name)
Value:
"impeller_Play_AiksTest_" #name "_Metal", \
"impeller_Play_AiksTest_" #name "_OpenGLES", \
"impeller_Play_AiksTest_" #name "_Vulkan"
const char * name
Definition fuchsia.cc:50

Definition at line 99 of file golden_playground_test_mac.cc.

105 {
106 // TextRotated is flakey and we can't seem to get it to stabilize on Skia
107 // Gold.
108 IMP_AIKSTEST(TextRotated),
109 // Runtime stage based tests get confused with a Metal context.
110 "impeller_Play_AiksTest_CanRenderClippedRuntimeEffects_Vulkan",
111};
112
113namespace {
114std::string GetTestName() {
115 std::string suite_name =
116 ::testing::UnitTest::GetInstance()->current_test_suite()->name();
117 std::string test_name =
118 ::testing::UnitTest::GetInstance()->current_test_info()->name();
119 std::stringstream ss;
120 ss << "impeller_" << suite_name << "_" << test_name;
121 std::string result = ss.str();
122 // Make sure there are no slashes in the test name.
123 std::replace(result.begin(), result.end(), '/', '_');
124 return result;
125}
126
127std::string GetGoldenFilename(const std::string& postfix) {
128 return GetTestName() + postfix + ".png";
129}
130} // namespace
131
132bool GoldenPlaygroundTest::SaveScreenshot(
133 std::unique_ptr<testing::Screenshot> screenshot,
134 const std::string& postfix) {
135 if (!screenshot || !screenshot->GetBytes()) {
136 FML_LOG(ERROR) << "Failed to collect screenshot for test " << GetTestName();
137 return false;
138 }
139 std::string test_name = GetTestName();
140 std::string filename = GetGoldenFilename(postfix);
141 testing::GoldenDigest::Instance()->AddImage(
142 test_name, filename, screenshot->GetWidth(), screenshot->GetHeight());
143 if (!screenshot->WriteToPNG(
144 testing::WorkingDirectory::Instance()->GetFilenamePath(filename))) {
145 FML_LOG(ERROR) << "Failed to write screenshot to " << filename;
146 return false;
147 }
148 return true;
149}
150
151struct GoldenPlaygroundTest::GoldenPlaygroundTestImpl {
152 std::unique_ptr<PlaygroundImpl> test_vulkan_playground;
153 std::unique_ptr<PlaygroundImpl> test_opengl_playground;
154 std::unique_ptr<testing::GoldenScreenshotter> screenshotter;
155 ISize window_size = ISize{1024, 768};
156};
157
158GoldenPlaygroundTest::GoldenPlaygroundTest()
159 : typographer_context_(TypographerContextSkia::Make()),
160 pimpl_(new GoldenPlaygroundTest::GoldenPlaygroundTestImpl()) {}
161
162GoldenPlaygroundTest::~GoldenPlaygroundTest() = default;
163
164void GoldenPlaygroundTest::SetTypographerContext(
165 std::shared_ptr<TypographerContext> typographer_context) {
166 typographer_context_ = std::move(typographer_context);
167};
168
169void GoldenPlaygroundTest::TearDown() {
170 ASSERT_FALSE(dlopen("/usr/local/lib/libMoltenVK.dylib", RTLD_NOLOAD));
171
172 auto context = GetContext();
173 if (context) {
174 context->DisposeThreadLocalCachedResources();
175 }
176}
177
178namespace {
179bool DoesSupportWideGamutTests() {
180#ifdef __arm64__
181 return true;
182#else
183 return false;
184#endif
185}
186} // namespace
187
188void GoldenPlaygroundTest::SetUp() {
189 std::filesystem::path testing_assets_path =
191 std::filesystem::path target_path = testing_assets_path.parent_path()
192 .parent_path()
193 .parent_path()
194 .parent_path();
195 std::filesystem::path icd_path = target_path / "vk_swiftshader_icd.json";
196 setenv("VK_ICD_FILENAMES", icd_path.c_str(), 1);
197
198 std::string test_name = GetTestName();
199 PlaygroundSwitches switches;
200 switches.enable_wide_gamut =
201 test_name.find("WideGamut_") != std::string::npos;
202 switch (GetParam()) {
203 case PlaygroundBackend::kMetalSDF:
204 switches.flags.use_sdfs = true;
205 [[fallthrough]];
206 case PlaygroundBackend::kMetal:
207 if (!DoesSupportWideGamutTests()) {
208 GTEST_SKIP()
209 << "This metal device doesn't support wide gamut golden tests.";
210 }
211 pimpl_->screenshotter =
212 std::make_unique<testing::MetalGoldenScreenshotter>(switches);
213 break;
214 case PlaygroundBackend::kVulkan: {
215 if (switches.enable_wide_gamut) {
216 GTEST_SKIP() << "Vulkan doesn't support wide gamut golden tests.";
217 }
218 const std::unique_ptr<PlaygroundImpl>& playground =
219 GetSharedVulkanPlayground(/*enable_validations=*/true);
220 pimpl_->screenshotter =
221 std::make_unique<testing::VulkanGoldenScreenshotter>(playground);
222 break;
223 }
224 case PlaygroundBackend::kOpenGLESSDF:
225 switches.flags.use_sdfs = true;
226 [[fallthrough]];
227 case PlaygroundBackend::kOpenGLES: {
228 if (switches.enable_wide_gamut) {
229 GTEST_SKIP() << "OpenGLES doesn't support wide gamut golden tests.";
230 }
231 const std::unique_ptr<PlaygroundImpl>& playground =
232 GetSharedOpenGLESPlayground(switches.flags.use_sdfs);
233 ::glfwMakeContextCurrent(
234 reinterpret_cast<GLFWwindow*>(playground->GetWindowHandle()));
235 pimpl_->screenshotter =
236 std::make_unique<testing::VulkanGoldenScreenshotter>(playground);
237 break;
238 }
239 }
240
241 if (std::find(kSkipTests.begin(), kSkipTests.end(), test_name) !=
242 kSkipTests.end()) {
243 GTEST_SKIP()
244 << "GoldenPlaygroundTest doesn't support interactive playground tests "
245 "yet.";
246 }
247
248 testing::GoldenDigest::Instance()->AddDimension(
249 "gpu_string", GetContext()->DescribeGpuModel());
250}
251
252PlaygroundBackend GoldenPlaygroundTest::GetBackend() const {
253 return GetParam();
254}
255
256bool GoldenPlaygroundTest::OpenPlaygroundHere(
257 const AiksDlPlaygroundCallback& callback) {
258 AiksContext renderer(GetContext(), typographer_context_);
259
260 std::unique_ptr<testing::Screenshot> screenshot;
261 Point content_scale =
262 pimpl_->screenshotter->GetPlayground().GetContentScale();
263
264 ISize physical_window_size(
265 std::round(pimpl_->window_size.width * content_scale.x),
266 std::round(pimpl_->window_size.height * content_scale.y));
267 for (int i = 0; i < 2; ++i) {
268 auto display_list = callback();
269 auto texture =
270 DisplayListToTexture(display_list, physical_window_size, renderer);
271 screenshot = pimpl_->screenshotter->MakeScreenshot(renderer, texture);
272 }
273 return SaveScreenshot(std::move(screenshot));
274}
275
276bool GoldenPlaygroundTest::OpenPlaygroundHere(
277 const sk_sp<flutter::DisplayList>& list) {
278 return OpenPlaygroundHere([&list]() { return list; });
279}
280
281bool GoldenPlaygroundTest::OpenPlaygroundHere(
282 const Playground::SinglePassCallback& callback) {
283 AiksContext renderer(GetContext(), typographer_context_);
284 std::shared_ptr<Context> context = GetContext();
285 Point content_scale =
286 pimpl_->screenshotter->GetPlayground().GetContentScale();
287 ISize size(std::round(pimpl_->window_size.width * content_scale.x),
288 std::round(pimpl_->window_size.height * content_scale.y));
289
290 std::unique_ptr<testing::Screenshot> screenshot;
291 // Render twice so the second pass observes warmed pipeline and resource
292 // caches, matching the display list path above.
293 for (int i = 0; i < 2; ++i) {
294 RenderTargetAllocator render_target_allocator(
295 context->GetResourceAllocator());
296 RenderTarget render_target = render_target_allocator.CreateOffscreen(
297 *context, size, /*mip_count=*/1, "Golden Render Pass",
298 RenderTarget::kDefaultColorAttachmentConfig,
299 /*stencil_attachment_config=*/std::nullopt);
300 if (!render_target.IsValid()) {
301 return false;
302 }
303 std::shared_ptr<CommandBuffer> command_buffer =
304 context->CreateCommandBuffer();
305 if (!command_buffer) {
306 return false;
307 }
308 std::shared_ptr<RenderPass> render_pass =
309 command_buffer->CreateRenderPass(render_target);
310 if (!render_pass) {
311 return false;
312 }
313 if (!callback(*render_pass)) {
314 return false;
315 }
316 if (!render_pass->EncodeCommands()) {
317 return false;
318 }
319 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
320 return false;
321 }
322 screenshot = pimpl_->screenshotter->MakeScreenshot(
323 renderer, render_target.GetRenderTargetTexture());
324 }
325 return SaveScreenshot(std::move(screenshot));
326}
327
328std::shared_ptr<Texture> GoldenPlaygroundTest::CreateTextureForFixture(
329 const char* fixture_name,
330 bool enable_mipmapping) const {
331 std::shared_ptr<fml::Mapping> mapping =
333 auto result = Playground::CreateTextureForMapping(GetContext(), mapping,
334 enable_mipmapping);
335 if (result) {
336 result->SetLabel(fixture_name);
337 }
338 return result;
339}
340
341sk_sp<flutter::DlImage> GoldenPlaygroundTest::CreateDlImageForFixture(
342 const char* fixture_name,
343 bool enable_mipmapping) const {
344 std::shared_ptr<Texture> texture =
345 CreateTextureForFixture(fixture_name, enable_mipmapping);
346 return DlImageImpeller::Make(texture);
347}
348
349absl::StatusOr<RuntimeStage::Map> GoldenPlaygroundTest::OpenAssetAsRuntimeStage(
350 const char* asset_name) const {
351 const std::shared_ptr<fml::Mapping> fixture =
353 if (!fixture || fixture->GetSize() == 0) {
354 return absl::NotFoundError("Asset not found or empty.");
355 }
356 return RuntimeStage::DecodeRuntimeStages(fixture);
357}
358
359std::shared_ptr<Context> GoldenPlaygroundTest::GetContext() const {
360 if (!pimpl_->screenshotter) {
361 return nullptr;
362 }
363 return pimpl_->screenshotter->GetPlayground().GetContext();
364}
365
366std::shared_ptr<Context> GoldenPlaygroundTest::MakeContext() const {
367 if (GetParam() == PlaygroundBackend::kMetal ||
368 GetParam() == PlaygroundBackend::kMetalSDF) {
369 /// On Metal we create a context for each test.
370 return GetContext();
371 } else if (GetParam() == PlaygroundBackend::kVulkan) {
372 bool enable_vulkan_validations = true;
373 FML_CHECK(!pimpl_->test_vulkan_playground)
374 << "We don't support creating multiple contexts for one test";
375 pimpl_->test_vulkan_playground =
376 MakeVulkanPlayground(enable_vulkan_validations);
377 pimpl_->screenshotter =
378 std::make_unique<testing::VulkanGoldenScreenshotter>(
379 pimpl_->test_vulkan_playground);
380 return pimpl_->test_vulkan_playground->GetContext();
381 } else if (GetParam() == PlaygroundBackend::kOpenGLES ||
382 GetParam() == PlaygroundBackend::kOpenGLESSDF) {
383 FML_CHECK(!pimpl_->test_opengl_playground)
384 << "We don't support creating multiple contexts for one test";
385 bool use_sdfs = (GetParam() == PlaygroundBackend::kOpenGLESSDF);
386 pimpl_->test_opengl_playground = MakeOpenGLESPlayground(use_sdfs);
387 pimpl_->screenshotter =
388 std::make_unique<testing::VulkanGoldenScreenshotter>(
389 pimpl_->test_opengl_playground);
390 return pimpl_->test_opengl_playground->GetContext();
391 } else {
392 FML_CHECK(false);
393 return nullptr;
394 }
395}
396
397Point GoldenPlaygroundTest::GetContentScale() const {
398 return pimpl_->screenshotter->GetPlayground().GetContentScale();
399}
400
401Scalar GoldenPlaygroundTest::GetSecondsElapsed() const {
402 return 0.0f;
403}
404
405ISize GoldenPlaygroundTest::GetWindowSize() const {
406 return pimpl_->window_size;
407}
408
409IRect GoldenPlaygroundTest::GetWindowBounds() const {
410 return IRect::MakeSize(pimpl_->window_size);
411}
412
413void GoldenPlaygroundTest::GoldenPlaygroundTest::SetWindowSize(ISize size) {
414 pimpl_->window_size = size;
415}
416
417fml::Status GoldenPlaygroundTest::SetCapabilities(
418 const std::shared_ptr<Capabilities>& capabilities) {
419 return pimpl_->screenshotter->GetPlayground().SetCapabilities(capabilities);
420}
421
422std::unique_ptr<testing::Screenshot> GoldenPlaygroundTest::MakeScreenshot(
423 const sk_sp<flutter::DisplayList>& list) {
424 AiksContext renderer(GetContext(), typographer_context_);
425 Point content_scale =
426 pimpl_->screenshotter->GetPlayground().GetContentScale();
427
428 ISize physical_window_size(
429 std::round(pimpl_->window_size.width * content_scale.x),
430 std::round(pimpl_->window_size.height * content_scale.y));
431 return pimpl_->screenshotter->MakeScreenshot(
432 renderer, DisplayListToTexture(list, physical_window_size, renderer));
433}
434
435RuntimeStageBackend GoldenPlaygroundTest::GetRuntimeStageBackend() const {
436 return pimpl_->screenshotter->GetPlayground().GetRuntimeStageBackend();
437}
438
439void GoldenPlaygroundTest::SetEnableWriteGolden(bool write_golden) {
440 if (!write_golden) {
441 // If we don't write a golden, we really don't have anything to do.
442 GTEST_SKIP() << "Test does not want a golden image written";
443 }
444}
445
446bool GoldenPlaygroundTest::InitializePipelineDescriptorForRendering(
447 PipelineDescriptor& desc) const {
448 // Match the golden harness render target: single-sampled, no depth/stencil.
449 // `ClearStencilAttachments` also resets the stencil pixel format on the
450 // pipeline, which Metal validation requires to match the target's lack of a
451 // stencil texture; `SetStencilAttachmentDescriptors(nullopt)` alone leaves
452 // the format set and trips that validation.
453 desc.SetSampleCount(SampleCount::kCount1);
454 desc.ClearStencilAttachments();
455 desc.ClearDepthAttachment();
456 return true;
457}
458
459} // namespace impeller
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define IMP_AIKSTEST(name)
FlTexture * texture
const char * GetTestingAssetsPath()
Returns the directory containing assets shared across all tests.
std::unique_ptr< fml::Mapping > OpenFixtureAsMapping(const std::string &fixture_name)
Opens a fixture of the given file name and returns a mapping to its contents.
Definition testing.cc:58
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
static const std::vector< std::string > kSkipTests
float Scalar
Definition scalar.h:19
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
TPoint< Scalar > Point
Definition point.h:426
IRect64 IRect
Definition rect.h:860
PlaygroundBackend
Definition playground.h:32
ISize64 ISize
Definition size.h:162
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< CommandBuffer > command_buffer