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 27 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 97 of file golden_playground_test_mac.cc.

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