| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <dlfcn.h> |
| #include <filesystem> |
| #include <memory> |
| |
| #include "flutter/impeller/golden_tests/golden_playground_test.h" |
| |
| #include "flutter/impeller/aiks/picture.h" |
| #include "flutter/impeller/golden_tests/golden_digest.h" |
| #include "flutter/impeller/golden_tests/metal_screenshoter.h" |
| #include "impeller/typographer/backends/skia/typographer_context_skia.h" |
| #include "impeller/typographer/typographer_context.h" |
| |
| namespace impeller { |
| |
| // If you add a new playground test to the aiks unittests and you do not want it |
| // to also be a golden test, then add the test name here. |
| static const std::vector<std::string> kSkipTests = { |
| "impeller_Play_AiksTest_CanDrawPaintMultipleTimesInteractive_Metal", |
| "impeller_Play_AiksTest_CanDrawPaintMultipleTimesInteractive_Vulkan", |
| "impeller_Play_AiksTest_CanRenderLinearGradientManyColorsUnevenStops_Metal", |
| "impeller_Play_AiksTest_CanRenderLinearGradientManyColorsUnevenStops_" |
| "Vulkan", |
| "impeller_Play_AiksTest_CanRenderRadialGradient_Metal", |
| "impeller_Play_AiksTest_CanRenderRadialGradient_Vulkan", |
| "impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Metal", |
| "impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Vulkan", |
| "impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_Metal", |
| "impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_Vulkan", |
| "impeller_Play_AiksTest_ClippedBlurFilterRendersCorrectlyInteractive_Metal", |
| "impeller_Play_AiksTest_ClippedBlurFilterRendersCorrectlyInteractive_" |
| "Vulkan", |
| "impeller_Play_AiksTest_TextFrameSubpixelAlignment_Metal", |
| "impeller_Play_AiksTest_TextFrameSubpixelAlignment_Vulkan", |
| "impeller_Play_AiksTest_ColorWheel_Metal", |
| "impeller_Play_AiksTest_ColorWheel_Vulkan", |
| "impeller_Play_AiksTest_SolidStrokesRenderCorrectly_Metal", |
| "impeller_Play_AiksTest_SolidStrokesRenderCorrectly_Vulkan", |
| "impeller_Play_AiksTest_GradientStrokesRenderCorrectly_Metal", |
| "impeller_Play_AiksTest_GradientStrokesRenderCorrectly_Vulkan", |
| "impeller_Play_AiksTest_CoverageOriginShouldBeAccountedForInSubpasses_" |
| "Metal", |
| "impeller_Play_AiksTest_CoverageOriginShouldBeAccountedForInSubpasses_" |
| "Vulkan", |
| "impeller_Play_AiksTest_SceneColorSource_Metal", |
| "impeller_Play_AiksTest_SceneColorSource_Vulkan", |
| // TextRotated is flakey and we can't seem to get it to stabilize on Skia |
| // Gold. |
| "impeller_Play_AiksTest_TextRotated_Metal", |
| "impeller_Play_AiksTest_TextRotated_Vulkan", |
| }; |
| |
| namespace { |
| std::string GetTestName() { |
| std::string suite_name = |
| ::testing::UnitTest::GetInstance()->current_test_suite()->name(); |
| std::string test_name = |
| ::testing::UnitTest::GetInstance()->current_test_info()->name(); |
| std::stringstream ss; |
| ss << "impeller_" << suite_name << "_" << test_name; |
| std::string result = ss.str(); |
| // Make sure there are no slashes in the test name. |
| std::replace(result.begin(), result.end(), '/', '_'); |
| return result; |
| } |
| |
| std::string GetGoldenFilename() { |
| return GetTestName() + ".png"; |
| } |
| |
| bool SaveScreenshot(std::unique_ptr<testing::MetalScreenshot> screenshot) { |
| if (!screenshot || !screenshot->GetBytes()) { |
| return false; |
| } |
| std::string test_name = GetTestName(); |
| std::string filename = GetGoldenFilename(); |
| testing::GoldenDigest::Instance()->AddImage( |
| test_name, filename, screenshot->GetWidth(), screenshot->GetHeight()); |
| return screenshot->WriteToPNG( |
| testing::WorkingDirectory::Instance()->GetFilenamePath(filename)); |
| } |
| } // namespace |
| |
| struct GoldenPlaygroundTest::GoldenPlaygroundTestImpl { |
| GoldenPlaygroundTestImpl() : screenshoter(new testing::MetalScreenshoter()) {} |
| std::unique_ptr<testing::MetalScreenshoter> screenshoter; |
| ISize window_size = ISize{1024, 768}; |
| }; |
| |
| GoldenPlaygroundTest::GoldenPlaygroundTest() |
| : typographer_context_(TypographerContextSkia::Make()), |
| pimpl_(new GoldenPlaygroundTest::GoldenPlaygroundTestImpl()) {} |
| |
| GoldenPlaygroundTest::~GoldenPlaygroundTest() = default; |
| |
| void GoldenPlaygroundTest::SetTypographerContext( |
| std::shared_ptr<TypographerContext> typographer_context) { |
| typographer_context_ = std::move(typographer_context); |
| }; |
| |
| void GoldenPlaygroundTest::TearDown() { |
| ASSERT_FALSE(dlopen("/usr/local/lib/libMoltenVK.dylib", RTLD_NOLOAD)); |
| } |
| |
| void GoldenPlaygroundTest::SetUp() { |
| std::filesystem::path testing_assets_path = |
| flutter::testing::GetTestingAssetsPath(); |
| std::filesystem::path target_path = testing_assets_path.parent_path() |
| .parent_path() |
| .parent_path() |
| .parent_path(); |
| std::filesystem::path icd_path = target_path / "vk_swiftshader_icd.json"; |
| setenv("VK_ICD_FILENAMES", icd_path.c_str(), 1); |
| |
| if (GetBackend() != PlaygroundBackend::kMetal && |
| GetBackend() != PlaygroundBackend::kVulkan) { |
| GTEST_SKIP_("GoldenPlaygroundTest doesn't support this backend type."); |
| return; |
| } |
| |
| std::string test_name = GetTestName(); |
| if (std::find(kSkipTests.begin(), kSkipTests.end(), test_name) != |
| kSkipTests.end()) { |
| GTEST_SKIP_( |
| "GoldenPlaygroundTest doesn't support interactive playground tests " |
| "yet."); |
| } |
| |
| testing::GoldenDigest::Instance()->AddDimension( |
| "gpu_string", GetContext()->DescribeGpuModel()); |
| } |
| |
| PlaygroundBackend GoldenPlaygroundTest::GetBackend() const { |
| return GetParam(); |
| } |
| |
| bool GoldenPlaygroundTest::OpenPlaygroundHere(Picture picture) { |
| AiksContext renderer(GetContext(), typographer_context_); |
| |
| auto screenshot = pimpl_->screenshoter->MakeScreenshot(renderer, picture, |
| pimpl_->window_size); |
| return SaveScreenshot(std::move(screenshot)); |
| } |
| |
| bool GoldenPlaygroundTest::OpenPlaygroundHere( |
| AiksPlaygroundCallback |
| callback) { // NOLINT(performance-unnecessary-value-param) |
| return false; |
| } |
| |
| std::shared_ptr<Texture> GoldenPlaygroundTest::CreateTextureForFixture( |
| const char* fixture_name, |
| bool enable_mipmapping) const { |
| std::shared_ptr<fml::Mapping> mapping = |
| flutter::testing::OpenFixtureAsMapping(fixture_name); |
| auto result = Playground::CreateTextureForMapping(GetContext(), mapping, |
| enable_mipmapping); |
| if (result) { |
| result->SetLabel(fixture_name); |
| } |
| return result; |
| } |
| |
| std::shared_ptr<RuntimeStage> GoldenPlaygroundTest::OpenAssetAsRuntimeStage( |
| const char* asset_name) const { |
| auto fixture = flutter::testing::OpenFixtureAsMapping(asset_name); |
| if (!fixture || fixture->GetSize() == 0) { |
| return nullptr; |
| } |
| auto stage = std::make_unique<RuntimeStage>(std::move(fixture)); |
| if (!stage->IsValid()) { |
| return nullptr; |
| } |
| return stage; |
| } |
| |
| std::shared_ptr<Context> GoldenPlaygroundTest::GetContext() const { |
| return pimpl_->screenshoter->GetPlayground().GetContext(); |
| } |
| |
| Point GoldenPlaygroundTest::GetContentScale() const { |
| return pimpl_->screenshoter->GetPlayground().GetContentScale(); |
| } |
| |
| Scalar GoldenPlaygroundTest::GetSecondsElapsed() const { |
| return 0.0f; |
| } |
| |
| ISize GoldenPlaygroundTest::GetWindowSize() const { |
| return pimpl_->window_size; |
| } |
| |
| } // namespace impeller |