105 {
106
107
109
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
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}
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;
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
174 context->DisposeThreadLocalCachedResources();
175 }
176}
177
178namespace {
179bool DoesSupportWideGamutTests() {
180#ifdef __arm64__
181 return true;
182#else
183 return false;
184#endif
185}
186}
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(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
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
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) {
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
292
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, 1,
"Golden Render Pass",
298 RenderTarget::kDefaultColorAttachmentConfig,
299 std::nullopt);
300 if (!render_target.IsValid()) {
301 return false;
302 }
304 context->CreateCommandBuffer();
306 return false;
307 }
311 return false;
312 }
314 return false;
315 }
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
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 {
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
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(
433}
434
436 return pimpl_->screenshotter->GetPlayground().GetRuntimeStageBackend();
437}
438
439void GoldenPlaygroundTest::SetEnableWriteGolden(bool write_golden) {
440 if (!write_golden) {
441
442 GTEST_SKIP() << "Test does not want a golden image written";
443 }
444}
445
446bool GoldenPlaygroundTest::InitializePipelineDescriptorForRendering(
447 PipelineDescriptor& desc) const {
448
449
450
451
452
453 desc.SetSampleCount(SampleCount::kCount1);
454 desc.ClearStencilAttachments();
455 desc.ClearDepthAttachment();
456 return true;
457}
458
459}
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