Skip to content

Commit

Permalink
[Impeller] Adds golden image tests. (flutter#40366)
Browse files Browse the repository at this point in the history
Added golden image tests to impeller
  • Loading branch information
gaaclarke authored Mar 24, 2023
1 parent 274196e commit f598224
Show file tree
Hide file tree
Showing 27 changed files with 881 additions and 7 deletions.
4 changes: 4 additions & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ targets:
properties:
release_build: "true"
config_name: mac_host_engine
dependencies: >-
[
{"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}
]
$flutter/osx_sdk : >-
{ "sdk_version": "14a5294e" }
Expand Down
4 changes: 2 additions & 2 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ group("unittests") {
}

if (is_mac) {
public_deps +=
[ "//flutter/shell/platform/darwin:flutter_channels_unittests" ]
public_deps += [
"//flutter/impeller/golden_tests:impeller_golden_tests",
"//flutter/shell/platform/darwin:flutter_channels_unittests",
"//flutter/third_party/spring_animation:spring_animation_unittests",
]
}
Expand Down
21 changes: 19 additions & 2 deletions ci/builders/mac_host_engine.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@
"os=Mac-12",
"cpu=x86"
],
"dependencies": [
{"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}
],
"gclient_custom_vars": {
"download_android_deps": false
},
Expand All @@ -124,13 +127,27 @@
"ninja": {
"config": "host_release",
"targets": [
"flutter/shell/platform/darwin/macos:zip_macos_flutter_framework",
"flutter/build/archives:archive_gen_snapshot",
"flutter/build/archives:artifacts",
"flutter/impeller/golden_tests:impeller_golden_tests",
"flutter/shell/platform/darwin/macos:zip_macos_flutter_framework",
"flutter/tools/font-subset"
]
},
"tests": []
"tests": [
{
"language": "python3",
"name": "Impeller golden Tests for host_release",
"parameters": [
"--variant",
"host_release",
"--type",
"impeller-golden"
],
"script": "flutter/testing/run_tests.py",
"type": "local"
}
]
},
{
"archives": [
Expand Down
8 changes: 8 additions & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@
../../../flutter/impeller/geometry/README.md
../../../flutter/impeller/geometry/geometry_unittests.cc
../../../flutter/impeller/geometry/geometry_unittests.h
../../../flutter/impeller/golden_tests/README.md
../../../flutter/impeller/golden_tests_harvester/.dart_tool
../../../flutter/impeller/golden_tests_harvester/.gitignore
../../../flutter/impeller/golden_tests_harvester/README.md
../../../flutter/impeller/golden_tests_harvester/analysis_options.yaml
../../../flutter/impeller/golden_tests_harvester/pubspec.lock
../../../flutter/impeller/golden_tests_harvester/pubspec.yaml
../../../flutter/impeller/golden_tests_harvester/test
../../../flutter/impeller/image/README.md
../../../flutter/impeller/playground
../../../flutter/impeller/renderer/compute_subgroup_unittests.cc
Expand Down
26 changes: 26 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,19 @@ ORIGIN: ../../../flutter/impeller/geometry/type_traits.cc + ../../../flutter/LIC
ORIGIN: ../../../flutter/impeller/geometry/type_traits.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/geometry/vector.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/geometry/vector.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/golden_digest.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/golden_digest.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/golden_tests.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/main.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/metal_screenshot.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/metal_screenshot.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/metal_screenshoter.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/metal_screenshoter.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/working_directory.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests/working_directory.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests_harvester/bin/golden_tests_harvester.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests_harvester/lib/golden_tests_harvester.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/golden_tests_harvester/lib/logger.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/image/compressed_image.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -3856,6 +3869,19 @@ FILE: ../../../flutter/impeller/geometry/type_traits.cc
FILE: ../../../flutter/impeller/geometry/type_traits.h
FILE: ../../../flutter/impeller/geometry/vector.cc
FILE: ../../../flutter/impeller/geometry/vector.h
FILE: ../../../flutter/impeller/golden_tests/golden_digest.cc
FILE: ../../../flutter/impeller/golden_tests/golden_digest.h
FILE: ../../../flutter/impeller/golden_tests/golden_tests.cc
FILE: ../../../flutter/impeller/golden_tests/main.cc
FILE: ../../../flutter/impeller/golden_tests/metal_screenshot.h
FILE: ../../../flutter/impeller/golden_tests/metal_screenshot.mm
FILE: ../../../flutter/impeller/golden_tests/metal_screenshoter.h
FILE: ../../../flutter/impeller/golden_tests/metal_screenshoter.mm
FILE: ../../../flutter/impeller/golden_tests/working_directory.cc
FILE: ../../../flutter/impeller/golden_tests/working_directory.h
FILE: ../../../flutter/impeller/golden_tests_harvester/bin/golden_tests_harvester.dart
FILE: ../../../flutter/impeller/golden_tests_harvester/lib/golden_tests_harvester.dart
FILE: ../../../flutter/impeller/golden_tests_harvester/lib/logger.dart
FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.cc
FILE: ../../../flutter/impeller/image/backends/skia/compressed_image_skia.h
FILE: ../../../flutter/impeller/image/compressed_image.cc
Expand Down
39 changes: 39 additions & 0 deletions impeller/golden_tests/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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.

import("//flutter/common/config.gni")
import("//flutter/impeller/tools/impeller.gni")

if (is_mac) {
test_fixtures("impeller_golden_tests_fixtures") {
fixtures = []
}

impeller_component("impeller_golden_tests") {
target_type = "executable"

testonly = true

sources = [
"golden_digest.cc",
"golden_digest.h",
"golden_tests.cc",
"main.cc",
"metal_screenshot.h",
"metal_screenshot.mm",
"metal_screenshoter.h",
"metal_screenshoter.mm",
"working_directory.cc",
"working_directory.h",
]

deps = [
":impeller_golden_tests_fixtures",
"//flutter/impeller/aiks",
"//flutter/impeller/playground",
"//flutter/impeller/renderer/backend/metal:metal",
"//third_party/googletest:gtest",
]
}
}
20 changes: 20 additions & 0 deletions impeller/golden_tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Impeller Golden Tests

This is the executable that will generate the golden image results that can then
be sent to Skia Gold vial the
[golden_tests_harvester]("../golden_tests_harvester").

Running these tests should happen from
[//flutter/testing/run_tests.py](../../testing/run_tests.py). That will do all
the steps to generate the golden images and transmit them to Skia Gold. If you
run the tests locally it will not actually upload anything. That only happens if
the script is executed from LUCI.

Example invocation:

```sh
./run_tests.py --variant="host_debug_unopt_arm64" --type="impeller-golden"
```

Currently these tests are only supported on macOS and only test the Metal
backend to Impeller.
58 changes: 58 additions & 0 deletions impeller/golden_tests/golden_digest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 "impeller/golden_tests/golden_digest.h"

#include <fstream>

namespace impeller {
namespace testing {

GoldenDigest* GoldenDigest::instance_ = nullptr;

GoldenDigest* GoldenDigest::Instance() {
if (!instance_) {
instance_ = new GoldenDigest();
}
return instance_;
}

GoldenDigest::GoldenDigest() {}

void GoldenDigest::AddImage(const std::string& test_name,
const std::string& filename,
int32_t width,
int32_t height) {
entries_.push_back({test_name, filename, width, height});
}

bool GoldenDigest::Write(WorkingDirectory* working_directory) {
std::ofstream fout;
fout.open(working_directory->GetFilenamePath("digest.json"));
if (!fout.good()) {
return false;
}

fout << "[" << std::endl;
bool is_first = true;
for (const auto& entry : entries_) {
if (!is_first) {
fout << "," << std::endl;
is_first = false;
}
fout << " { "
<< "\"testName\" : \"" << entry.test_name << "\", "
<< "\"filename\" : \"" << entry.filename << "\", "
<< "\"width\" : " << entry.width << ", "
<< "\"height\" : " << entry.height << " "
<< "}";
}
fout << std::endl << "]" << std::endl;

fout.close();
return true;
}

} // namespace testing
} // namespace impeller
45 changes: 45 additions & 0 deletions impeller/golden_tests/golden_digest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.

#pragma once

#include <string>
#include <vector>

#include "flutter/fml/macros.h"
#include "flutter/impeller/golden_tests/working_directory.h"

namespace impeller {
namespace testing {

/// Manages a global variable for tracking instances of golden images.
class GoldenDigest {
public:
static GoldenDigest* Instance();

void AddImage(const std::string& test_name,
const std::string& filename,
int32_t width,
int32_t height);

/// Writes a "digest.json" file to `working_directory`.
///
/// Returns `true` on success.
bool Write(WorkingDirectory* working_directory);

private:
FML_DISALLOW_COPY_AND_ASSIGN(GoldenDigest);
GoldenDigest();
struct Entry {
std::string test_name;
std::string filename;
int32_t width;
int32_t height;
};

static GoldenDigest* instance_;
std::vector<Entry> entries_;
};
} // namespace testing
} // namespace impeller
79 changes: 79 additions & 0 deletions impeller/golden_tests/golden_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 "gtest/gtest.h"

#include <sstream>

#include "impeller/aiks/canvas.h"
#include "impeller/entity/contents/conical_gradient_contents.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/golden_tests/golden_digest.h"
#include "impeller/golden_tests/metal_screenshot.h"
#include "impeller/golden_tests/metal_screenshoter.h"
#include "impeller/golden_tests/working_directory.h"

namespace impeller {
namespace testing {

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;
return ss.str();
}

std::string GetGoldenFilename() {
return GetTestName() + ".png";
}

bool SaveScreenshot(std::unique_ptr<MetalScreenshot> screenshot) {
if (!screenshot || !screenshot->GetBytes()) {
return false;
}
std::string test_name = GetTestName();
std::string filename = GetGoldenFilename();
GoldenDigest::Instance()->AddImage(
test_name, filename, screenshot->GetWidth(), screenshot->GetHeight());
return screenshot->WriteToPNG(
WorkingDirectory::Instance()->GetFilenamePath(filename));
}
} // namespace

class GoldenTests : public ::testing::Test {
public:
GoldenTests() : screenshoter_(new MetalScreenshoter()) {}

MetalScreenshoter& Screenshoter() { return *screenshoter_; }

private:
std::unique_ptr<MetalScreenshoter> screenshoter_;
};

TEST_F(GoldenTests, ConicalGradient) {
Canvas canvas;
Paint paint;
paint.color_source_type = Paint::ColorSourceType::kConicalGradient;
paint.color_source = []() {
auto result = std::make_shared<ConicalGradientContents>();
result->SetCenterAndRadius(Point(125, 125), 125);
result->SetColors({Color(1.0, 0.0, 0.0, 1.0), Color(0.0, 0.0, 1.0, 1.0)});
result->SetStops({0, 1});
result->SetFocus(Point(180, 180), 0);
result->SetTileMode(Entity::TileMode::kClamp);
return result;
};
paint.stroke_width = 0.0;
paint.style = Paint::Style::kFill;
canvas.DrawRect(Rect(10, 10, 250, 250), paint);
Picture picture = canvas.EndRecordingAsPicture();
auto screenshot = Screenshoter().MakeScreenshot(std::move(picture));
ASSERT_TRUE(SaveScreenshot(std::move(screenshot)));
}
} // namespace testing
} // namespace impeller
Loading

0 comments on commit f598224

Please sign in to comment.