103 {
104
105
107
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
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}
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;
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
172 context->DisposeThreadLocalCachedResources();
173 }
174}
175
176namespace {
177bool DoesSupportWideGamutTests() {
178#ifdef __arm64__
179 return true;
180#else
181 return false;
182#endif
183}
184}
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(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
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
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) {
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
304
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, 1,
"Golden Render Pass",
310 RenderTarget::kDefaultColorAttachmentConfig,
311 std::nullopt);
312 if (!render_target.IsValid()) {
313 return false;
314 }
316 context->CreateCommandBuffer();
318 return false;
319 }
323 return false;
324 }
326 return false;
327 }
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
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 {
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
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(
449}
450
452 return pimpl_->screenshotter->GetPlayground().GetRuntimeStageBackend();
453}
454
455}
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define IMP_AIKSTEST(name)
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.
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
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.
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< CommandBuffer > command_buffer