27#include "third_party/abseil-cpp/absl/base/no_destructor.h"
29#define GLFW_INCLUDE_NONE
30#include "third_party/glfw/include/GLFW/glfw3.h"
35std::unique_ptr<PlaygroundImpl> MakeVulkanPlayground(
bool enable_validations) {
37 PlaygroundSwitches playground_switches;
38 playground_switches.enable_vulkan_validation = enable_validations;
44const std::unique_ptr<PlaygroundImpl>& GetSharedVulkanPlayground(
45 bool enable_validations) {
46 if (enable_validations) {
47 static absl::NoDestructor<std::unique_ptr<PlaygroundImpl>>
48 vulkan_validation_playground(
49 MakeVulkanPlayground(
true));
53 [&] { (*vulkan_validation_playground)->GetContext()->Shutdown(); });
54 return *vulkan_validation_playground;
56 static absl::NoDestructor<std::unique_ptr<PlaygroundImpl>>
57 vulkan_playground(MakeVulkanPlayground(
false));
61 [&] { (*vulkan_playground)->GetContext()->Shutdown(); });
62 return *vulkan_playground;
66std::unique_ptr<PlaygroundImpl> MakeOpenGLESPlayground(
bool use_sdfs =
false) {
68 PlaygroundSwitches playground_switches;
69 playground_switches.use_angle =
true;
70 playground_switches.flags.use_sdfs = use_sdfs;
78const std::unique_ptr<PlaygroundImpl>& GetSharedOpenGLESPlayground(
81 static absl::NoDestructor<std::unique_ptr<PlaygroundImpl>>
82 opengl_playground(MakeOpenGLESPlayground(
true));
84 [&] { (*opengl_playground)->GetContext()->Shutdown(); });
85 return *opengl_playground;
87 static absl::NoDestructor<std::unique_ptr<PlaygroundImpl>>
88 opengl_playground(MakeOpenGLESPlayground(
false));
92 [&] { (*opengl_playground)->GetContext()->Shutdown(); });
93 return *opengl_playground;
99#define IMP_AIKSTEST(name) \
100 "impeller_Play_AiksTest_" #name "_Metal", \
101 "impeller_Play_AiksTest_" #name "_OpenGLES", \
102 "impeller_Play_AiksTest_" #name "_Vulkan"
111 "impeller_Play_AiksTest_CanRenderClippedRuntimeEffects_Vulkan",
115std::string GetTestName() {
116 std::string suite_name =
117 ::testing::UnitTest::GetInstance()->current_test_suite()->name();
118 std::string test_name =
119 ::testing::UnitTest::GetInstance()->current_test_info()->name();
120 std::stringstream ss;
121 ss <<
"impeller_" << suite_name <<
"_" << test_name;
122 std::string result = ss.str();
124 std::replace(result.begin(), result.end(),
'/',
'_');
128std::string GetGoldenFilename(
const std::string& postfix) {
129 return GetTestName() + postfix +
".png";
134 std::unique_ptr<testing::Screenshot> screenshot,
135 const std::string& postfix) {
136 if (!screenshot || !screenshot->GetBytes()) {
137 FML_LOG(ERROR) <<
"Failed to collect screenshot for test " << GetTestName();
140 std::string test_name = GetTestName();
141 std::string filename = GetGoldenFilename(postfix);
143 test_name, filename, screenshot->GetWidth(), screenshot->GetHeight());
144 if (!screenshot->WriteToPNG(
146 FML_LOG(ERROR) <<
"Failed to write screenshot to " << filename;
166 std::shared_ptr<TypographerContext> typographer_context) {
167 typographer_context_ = std::move(typographer_context);
171 ASSERT_FALSE(dlopen(
"/usr/local/lib/libMoltenVK.dylib", RTLD_NOLOAD));
175 context->DisposeThreadLocalCachedResources();
180bool DoesSupportWideGamutTests() {
190 std::filesystem::path testing_assets_path =
192 std::filesystem::path target_path = testing_assets_path.parent_path()
196 std::filesystem::path icd_path = target_path /
"vk_swiftshader_icd.json";
197 setenv(
"VK_ICD_FILENAMES", icd_path.c_str(), 1);
199 std::string test_name = GetTestName();
202 test_name.find(
"WideGamut_") != std::string::npos;
203 switch (GetParam()) {
208 if (!DoesSupportWideGamutTests()) {
210 <<
"This metal device doesn't support wide gamut golden tests.";
212 pimpl_->screenshotter =
213 std::make_unique<testing::MetalGoldenScreenshotter>(switches);
217 GTEST_SKIP() <<
"Vulkan doesn't support wide gamut golden tests.";
219 const std::unique_ptr<PlaygroundImpl>& playground =
220 GetSharedVulkanPlayground(
true);
221 pimpl_->screenshotter =
222 std::make_unique<testing::VulkanGoldenScreenshotter>(playground);
230 GTEST_SKIP() <<
"OpenGLES doesn't support wide gamut golden tests.";
232 const std::unique_ptr<PlaygroundImpl>& playground =
234 ::glfwMakeContextCurrent(
235 reinterpret_cast<GLFWwindow*
>(playground->GetWindowHandle()));
236 pimpl_->screenshotter =
237 std::make_unique<testing::VulkanGoldenScreenshotter>(playground);
245 <<
"GoldenPlaygroundTest doesn't support interactive playground tests "
250 "gpu_string",
GetContext()->DescribeGpuModel());
261 std::unique_ptr<testing::Screenshot> screenshot;
262 Point content_scale =
263 pimpl_->screenshotter->GetPlayground().GetContentScale();
265 ISize physical_window_size(
266 std::round(pimpl_->window_size.width * content_scale.
x),
267 std::round(pimpl_->window_size.height * content_scale.
y));
268 for (
int i = 0;
i < 2; ++
i) {
272 screenshot = pimpl_->screenshotter->MakeScreenshot(renderer,
texture);
278 const sk_sp<flutter::DisplayList>& list) {
286 Point content_scale =
287 pimpl_->screenshotter->GetPlayground().GetContentScale();
288 ISize size(std::round(pimpl_->window_size.width * content_scale.
x),
289 std::round(pimpl_->window_size.height * content_scale.
y));
291 std::unique_ptr<testing::Screenshot> screenshot;
294 for (
int i = 0;
i < 2; ++
i) {
296 context->GetResourceAllocator());
298 *
context, size, 1,
"Golden Render Pass",
301 if (!render_target.
IsValid()) {
305 context->CreateCommandBuffer();
320 if (!
context->GetCommandQueue()->Submit({command_buffer}).ok()) {
323 screenshot = pimpl_->screenshotter->MakeScreenshot(
330 const char* fixture_name,
331 bool enable_mipmapping)
const {
332 std::shared_ptr<fml::Mapping> mapping =
337 result->SetLabel(fixture_name);
343 const char* fixture_name,
344 bool enable_mipmapping)
const {
345 std::shared_ptr<Texture>
texture =
351 const char* asset_name)
const {
352 const std::shared_ptr<fml::Mapping> fixture =
354 if (!fixture || fixture->GetSize() == 0) {
355 return absl::NotFoundError(
"Asset not found or empty.");
361 if (!pimpl_->screenshotter) {
364 return pimpl_->screenshotter->GetPlayground().GetContext();
373 bool enable_vulkan_validations =
true;
374 FML_CHECK(!pimpl_->test_vulkan_playground)
375 <<
"We don't support creating multiple contexts for one test";
376 pimpl_->test_vulkan_playground =
377 MakeVulkanPlayground(enable_vulkan_validations);
378 pimpl_->screenshotter =
379 std::make_unique<testing::VulkanGoldenScreenshotter>(
380 pimpl_->test_vulkan_playground);
381 return pimpl_->test_vulkan_playground->GetContext();
384 FML_CHECK(!pimpl_->test_opengl_playground)
385 <<
"We don't support creating multiple contexts for one test";
387 pimpl_->test_opengl_playground = MakeOpenGLESPlayground(use_sdfs);
388 pimpl_->screenshotter =
389 std::make_unique<testing::VulkanGoldenScreenshotter>(
390 pimpl_->test_opengl_playground);
391 return pimpl_->test_opengl_playground->GetContext();
399 return pimpl_->screenshotter->GetPlayground().GetContentScale();
407 return pimpl_->window_size;
414void GoldenPlaygroundTest::GoldenPlaygroundTest::SetWindowSize(
ISize size) {
415 pimpl_->window_size = size;
419 const std::shared_ptr<Capabilities>& capabilities) {
420 return pimpl_->screenshotter->GetPlayground().SetCapabilities(capabilities);
424 const sk_sp<flutter::DisplayList>& list) {
426 Point content_scale =
427 pimpl_->screenshotter->GetPlayground().GetContentScale();
429 ISize physical_window_size(
430 std::round(pimpl_->window_size.width * content_scale.
x),
431 std::round(pimpl_->window_size.height * content_scale.
y));
432 return pimpl_->screenshotter->MakeScreenshot(
437 return pimpl_->screenshotter->GetPlayground().GetRuntimeStageBackend();
443 GTEST_SKIP() <<
"Test does not want a golden image written";
Wraps a closure that is invoked in the destructor unless released by the caller.
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
IRect GetWindowBounds() const
PlaygroundBackend GetBackend() const
ISize GetWindowSize() const
RuntimeStageBackend GetRuntimeStageBackend() const
sk_sp< flutter::DlImage > CreateDlImageForFixture(const char *fixture_name, bool enable_mipmapping=false) const
Point GetContentScale() const
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities)
void SetTypographerContext(std::shared_ptr< TypographerContext > typographer_context)
std::shared_ptr< Context > MakeContext() const
void SetEnableWriteGolden(bool write_golden)
Sets a particular test to either write a golden or not.
static bool SaveScreenshot(std::unique_ptr< testing::Screenshot > screenshot, const std::string &postfix="")
bool InitializePipelineDescriptorForRendering(PipelineDescriptor &desc) const
Initializes the provided |PipelineDescriptor| with appropriate default values to match the conditions...
std::unique_ptr< testing::Screenshot > MakeScreenshot(const sk_sp< flutter::DisplayList > &list)
Scalar GetSecondsElapsed() const
bool OpenPlaygroundHere(Picture picture)
std::function< sk_sp< flutter::DisplayList >()> AiksDlPlaygroundCallback
~GoldenPlaygroundTest() override
absl::StatusOr< RuntimeStage::Map > OpenAssetAsRuntimeStage(const char *asset_name) const
std::shared_ptr< Context > GetContext() const
std::shared_ptr< Texture > CreateTextureForFixture(const char *fixture_name, bool enable_mipmapping=false) const
void ClearStencilAttachments()
PipelineDescriptor & SetSampleCount(SampleCount samples)
void ClearDepthAttachment()
std::function< bool(RenderPass &pass)> SinglePassCallback
static std::shared_ptr< Texture > CreateTextureForMapping(const std::shared_ptr< Context > &context, std::shared_ptr< fml::Mapping > mapping, bool enable_mipmapping=false)
static std::unique_ptr< PlaygroundImpl > Create(PlaygroundBackend backend, PlaygroundSwitches switches)
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
virtual RenderTarget CreateOffscreen(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen", RenderTarget::AttachmentConfig color_attachment_config=RenderTarget::kDefaultColorAttachmentConfig, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
std::shared_ptr< Texture > GetRenderTargetTexture() const
static constexpr AttachmentConfig kDefaultColorAttachmentConfig
static absl::StatusOr< Map > DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
static GoldenDigest * Instance()
void AddDimension(const std::string &name, const std::string &value)
void AddImage(const std::string &test_name, const std::string &filename, int32_t width, int32_t height)
std::string GetFilenamePath(const std::string &filename) const
static WorkingDirectory * Instance()
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.
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
bool use_sdfs
Use SDFs for rendering.
std::unique_ptr< PlaygroundImpl > test_vulkan_playground
std::unique_ptr< PlaygroundImpl > test_opengl_playground
std::unique_ptr< testing::GoldenScreenshotter > screenshotter
static constexpr TRect MakeSize(const TSize< U > &size)