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
186void GoldenPlaygroundTest::SetUp() {
187 std::filesystem::path testing_assets_path =
189 std::filesystem::path target_path = testing_assets_path.parent_path()
190 .parent_path()
191 .parent_path()
192 .parent_path();
193 std::filesystem::path icd_path = target_path / "vk_swiftshader_icd.json";
194 setenv("VK_ICD_FILENAMES", icd_path.c_str(), 1);
195
196 std::string test_name = GetTestName();
197 PlaygroundSwitches switches;
198 switches.enable_wide_gamut =
199 test_name.find("WideGamut_") != std::string::npos;
200 switches.flags.antialiased_lines =
201 test_name.find("ExperimentAntialiasLines_") != 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::MetalScreenshotter>(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 if (switches.flags.antialiased_lines) {
219 GTEST_SKIP()
220 << "Vulkan doesn't support antialiased lines golden tests.";
221 }
222 const std::unique_ptr<PlaygroundImpl>& playground =
223 GetSharedVulkanPlayground(/*enable_validations=*/true);
224 pimpl_->screenshotter =
225 std::make_unique<testing::VulkanScreenshotter>(playground);
226 break;
227 }
228 case PlaygroundBackend::kOpenGLESSDF:
229 switches.flags.use_sdfs = true;
230 [[fallthrough]];
231 case PlaygroundBackend::kOpenGLES: {
232 if (switches.enable_wide_gamut) {
233 GTEST_SKIP() << "OpenGLES doesn't support wide gamut golden tests.";
234 }
235 if (switches.flags.antialiased_lines) {
236 GTEST_SKIP()
237 << "OpenGLES doesn't support antialiased lines golden tests.";
238 }
239 const std::unique_ptr<PlaygroundImpl>& playground =
240 GetSharedOpenGLESPlayground(switches.flags.use_sdfs);
241 ::glfwMakeContextCurrent(
242 reinterpret_cast<GLFWwindow*>(playground->GetWindowHandle()));
243 pimpl_->screenshotter =
244 std::make_unique<testing::VulkanScreenshotter>(playground);
245 break;
246 }
247 }
248
249 if (std::find(kSkipTests.begin(), kSkipTests.end(), test_name) !=
250 kSkipTests.end()) {
251 GTEST_SKIP()
252 << "GoldenPlaygroundTest doesn't support interactive playground tests "
253 "yet.";
254 }
255
256 testing::GoldenDigest::Instance()->AddDimension(
257 "gpu_string", GetContext()->DescribeGpuModel());
258}
259
260PlaygroundBackend GoldenPlaygroundTest::GetBackend() const {
261 return GetParam();
262}
263
264bool GoldenPlaygroundTest::OpenPlaygroundHere(
265 const AiksDlPlaygroundCallback& callback) {
266 AiksContext renderer(GetContext(), typographer_context_);
267
268 std::unique_ptr<testing::Screenshot> screenshot;
269 Point content_scale =
270 pimpl_->screenshotter->GetPlayground().GetContentScale();
271
272 ISize physical_window_size(
273 std::round(pimpl_->window_size.width * content_scale.x),
274 std::round(pimpl_->window_size.height * content_scale.y));
275 for (int i = 0; i < 2; ++i) {
276 auto display_list = callback();
277 auto texture =
278 DisplayListToTexture(display_list, physical_window_size, renderer);
279 screenshot = pimpl_->screenshotter->MakeScreenshot(renderer, texture);
280 }
281 return SaveScreenshot(std::move(screenshot));
282}
283
284bool GoldenPlaygroundTest::OpenPlaygroundHere(
285 const sk_sp<flutter::DisplayList>& list) {
286 return OpenPlaygroundHere([&list]() { return list; });
287}
288
289bool GoldenPlaygroundTest::OpenPlaygroundHere(
290 const Playground::SinglePassCallback& callback) {
291 AiksContext renderer(GetContext(), typographer_context_);
292 std::shared_ptr<Context> context = GetContext();
293 Point content_scale =
294 pimpl_->screenshotter->GetPlayground().GetContentScale();
295 ISize size(std::round(pimpl_->window_size.width * content_scale.x),
296 std::round(pimpl_->window_size.height * content_scale.y));
297
298 std::unique_ptr<testing::Screenshot> screenshot;
299 // Render twice so the second pass observes warmed pipeline and resource
300 // caches, matching the display list path above.
301 for (int i = 0; i < 2; ++i) {
302 RenderTargetAllocator render_target_allocator(
303 context->GetResourceAllocator());
304 RenderTarget render_target = render_target_allocator.CreateOffscreen(
305 *context, size, /*mip_count=*/1, "Golden Render Pass",
306 RenderTarget::kDefaultColorAttachmentConfig,
307 /*stencil_attachment_config=*/std::nullopt);
308 if (!render_target.IsValid()) {
309 return false;
310 }
311 std::shared_ptr<CommandBuffer> command_buffer =
312 context->CreateCommandBuffer();
313 if (!command_buffer) {
314 return false;
315 }
316 std::shared_ptr<RenderPass> render_pass =
317 command_buffer->CreateRenderPass(render_target);
318 if (!render_pass) {
319 return false;
320 }
321 if (!callback(*render_pass)) {
322 return false;
323 }
324 if (!render_pass->EncodeCommands()) {
325 return false;
326 }
327 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
328 return false;
329 }
330 screenshot = pimpl_->screenshotter->MakeScreenshot(
331 renderer, render_target.GetRenderTargetTexture());
332 }
333 return SaveScreenshot(std::move(screenshot));
334}
335
336bool GoldenPlaygroundTest::ImGuiBegin(const char* name,
337 bool* p_open,
338 ImGuiWindowFlags flags) {
339 return false;
340}
341
342std::shared_ptr<Texture> GoldenPlaygroundTest::CreateTextureForFixture(
343 const char* fixture_name,
344 bool enable_mipmapping) const {
345 std::shared_ptr<fml::Mapping> mapping =
347 auto result = Playground::CreateTextureForMapping(GetContext(), mapping,
348 enable_mipmapping);
349 if (result) {
350 result->SetLabel(fixture_name);
351 }
352 return result;
353}
354
355sk_sp<flutter::DlImage> GoldenPlaygroundTest::CreateDlImageForFixture(
356 const char* fixture_name,
357 bool enable_mipmapping) const {
358 std::shared_ptr<Texture> texture =
359 CreateTextureForFixture(fixture_name, enable_mipmapping);
360 return DlImageImpeller::Make(texture);
361}
362
363absl::StatusOr<RuntimeStage::Map> GoldenPlaygroundTest::OpenAssetAsRuntimeStage(
364 const char* asset_name) const {
365 const std::shared_ptr<fml::Mapping> fixture =
367 if (!fixture || fixture->GetSize() == 0) {
368 return absl::NotFoundError("Asset not found or empty.");
369 }
370 return RuntimeStage::DecodeRuntimeStages(fixture);
371}
372
373std::shared_ptr<Context> GoldenPlaygroundTest::GetContext() const {
374 if (!pimpl_->screenshotter) {
375 return nullptr;
376 }
377 return pimpl_->screenshotter->GetPlayground().GetContext();
378}
379
380std::shared_ptr<Context> GoldenPlaygroundTest::MakeContext() const {
381 if (GetParam() == PlaygroundBackend::kMetal ||
382 GetParam() == PlaygroundBackend::kMetalSDF) {
383 /// On Metal we create a context for each test.
384 return GetContext();
385 } else if (GetParam() == PlaygroundBackend::kVulkan) {
386 bool enable_vulkan_validations = true;
387 FML_CHECK(!pimpl_->test_vulkan_playground)
388 << "We don't support creating multiple contexts for one test";
389 pimpl_->test_vulkan_playground =
390 MakeVulkanPlayground(enable_vulkan_validations);
391 pimpl_->screenshotter = std::make_unique<testing::VulkanScreenshotter>(
392 pimpl_->test_vulkan_playground);
393 return pimpl_->test_vulkan_playground->GetContext();
394 } else if (GetParam() == PlaygroundBackend::kOpenGLES ||
395 GetParam() == PlaygroundBackend::kOpenGLESSDF) {
396 FML_CHECK(!pimpl_->test_opengl_playground)
397 << "We don't support creating multiple contexts for one test";
398 bool use_sdfs = (GetParam() == PlaygroundBackend::kOpenGLESSDF);
399 pimpl_->test_opengl_playground = MakeOpenGLESPlayground(use_sdfs);
400 pimpl_->screenshotter = std::make_unique<testing::VulkanScreenshotter>(
401 pimpl_->test_opengl_playground);
402 return pimpl_->test_opengl_playground->GetContext();
403 } else {
404 FML_CHECK(false);
405 return nullptr;
406 }
407}
408
409Point GoldenPlaygroundTest::GetContentScale() const {
410 return pimpl_->screenshotter->GetPlayground().GetContentScale();
411}
412
413Scalar GoldenPlaygroundTest::GetSecondsElapsed() const {
414 return 0.0f;
415}
416
417ISize GoldenPlaygroundTest::GetWindowSize() const {
418 return pimpl_->window_size;
419}
420
421IRect GoldenPlaygroundTest::GetWindowBounds() const {
422 return IRect::MakeSize(pimpl_->window_size);
423}
424
425void GoldenPlaygroundTest::GoldenPlaygroundTest::SetWindowSize(ISize size) {
426 pimpl_->window_size = size;
427}
428
429fml::Status GoldenPlaygroundTest::SetCapabilities(
430 const std::shared_ptr<Capabilities>& capabilities) {
431 return pimpl_->screenshotter->GetPlayground().SetCapabilities(capabilities);
432}
433
434std::unique_ptr<testing::Screenshot> GoldenPlaygroundTest::MakeScreenshot(
435 const sk_sp<flutter::DisplayList>& list) {
436 AiksContext renderer(GetContext(), typographer_context_);
437 Point content_scale =
438 pimpl_->screenshotter->GetPlayground().GetContentScale();
439
440 ISize physical_window_size(
441 std::round(pimpl_->window_size.width * content_scale.x),
442 std::round(pimpl_->window_size.height * content_scale.y));
443 return pimpl_->screenshotter->MakeScreenshot(
444 renderer, DisplayListToTexture(list, physical_window_size, renderer));
445}
446
447RuntimeStageBackend GoldenPlaygroundTest::GetRuntimeStageBackend() const {
448 return pimpl_->screenshotter->GetPlayground().GetRuntimeStageBackend();
449}
450
451} // 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:26
ISize64 ISize
Definition size.h:162
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< CommandBuffer > command_buffer