48 "Space-separated list of test cases (regexps) to run. Will run all tests if omitted.");
60 "Directory where to write any output .png and .json files. "
61 "Optional when running under Bazel "
62 "(e.g. \"bazel test //path/to:test\") as it defaults to "
63 "$TEST_UNDECLARED_OUTPUTS_DIR.");
67 "Plaintext file with one MD5 hash per line. This test runner will omit from "
68 "the output directory any images with an MD5 hash in this file.");
77 "Name of the Surface configuration to use (e.g. \"8888\"). This determines "
78 "how we construct the SkSurface from which we get the SkCanvas that GMs will "
79 "draw on. See file //tools/testrunners/common/surface_manager/SurfaceManager.h for "
85 "Contents of the \"cpu_or_gpu_value\" dimension for CPU-bound traces (e.g. \"AVX512\").");
90 "Contents of the \"cpu_or_gpu_value\" dimension for GPU-bound traces (e.g. \"RTX3060\").");
94 "Name of the \"via\" to use (e.g. \"picture_serialization\"). Optional.");
103 "Ignored by this test runner.",
116 std::map<std::string, std::string> commonKeys,
117 std::map<std::string, std::string> gmGoldKeys,
118 std::map<std::string, std::string> surfaceGoldKeys,
121 const char* jsonPath,
122 std::set<std::string> knownDigests) {
132 if (knownDigests.find(
md5.c_str()) != knownDigests.end()) {
135 .skippedDigest =
md5.c_str(),
148 .errorMsg =
"Error encoding or writing PNG to " + std::string(pngPath),
153 if (gmGoldKeys.find(
"name") == gmGoldKeys.end()) {
154 SK_ABORT(
"gmGoldKeys does not contain key \"name\"");
156 if (gmGoldKeys.find(
"source_type") == gmGoldKeys.end()) {
157 SK_ABORT(
"gmGoldKeys does not contain key \"source_type\"");
161 if (surfaceGoldKeys.find(
"surface_config") == surfaceGoldKeys.end()) {
162 SK_ABORT(
"surfaceGoldKeys does not contain key \"surface_config\"");
166 std::map<std::string, std::string> keys = {
167 {
"build_system",
"bazel"},
170 keys.merge(commonKeys);
171 keys.merge(surfaceGoldKeys);
172 keys.merge(gmGoldKeys);
180 for (
auto const& [param,
value] : keys) {
210void run_gm(std::unique_ptr<skiagm::GM> gm,
212 std::map<std::string, std::string> keyValuePairs,
215 std::string outputDir,
216 std::set<std::string> knownDigests) {
222 if (surfaceManager ==
nullptr) {
223 SK_ABORT(
"Unknown --surfaceConfig flag value: %s.", config.c_str());
230 "\tWarning: The surface is CPU-bound, but flag --cpuName was not provided. "
231 "Gold traces will omit keys \"cpu_or_gpu\" and \"cpu_or_gpu_value\".");
237 "\tWarning: The surface is GPU-bound, but flag --gpuName was not provided. "
238 "Gold traces will omit keys \"cpu_or_gpu\" and \"cpu_or_gpu_value\".");
251 std::string viaName = FLAGS_via.size() == 0 ?
"" : (FLAGS_via[0]);
253 output =
draw(gm.get(), surfaceManager->getSurface().get(), viaName);
265 surfaceManager->flush();
285 std::string
name = std::string(gm->getName().c_str());
293 surfaceManager->getGoldKeyValuePairs(cpuName, gpuName),
314 std::set<std::string>
hashes;
316 std::ifstream
f(
path);
318 for (
int lineNum = 1; std::getline(
f,
line); lineNum++) {
320 auto isSpace = [](
unsigned char c) {
return !std::isspace(c); };
322 md5.erase(
md5.begin(), std::find_if(
md5.begin(),
md5.end(), isSpace));
323 md5.erase(std::find_if(
md5.rbegin(),
md5.rend(), isSpace).base(),
md5.end());
325 if (
md5 ==
"")
continue;
327 if (!std::regex_match(
md5, md5HashRegex)) {
329 "File '%s' passed via --knownDigestsFile contains an invalid entry on line "
347 std::string testUndeclaredOutputsDir;
348 if (
char* envVar =
std::getenv(
"TEST_UNDECLARED_OUTPUTS_DIR")) {
349 testUndeclaredOutputsDir = envVar;
351 bool isBazelTest = !testUndeclaredOutputsDir.empty();
367 std::string outputDir =
368 FLAGS_outputDir.isEmpty() ? testUndeclaredOutputsDir : FLAGS_outputDir[0];
370 auto knownDigests = std::set<std::string>();
371 if (!FLAGS_knownDigestsFile.isEmpty()) {
374 "Read %zu known digests from: %s", knownDigests.size(), FLAGS_knownDigestsFile[0]);
377 std::map<std::string, std::string> keyValuePairs;
378 for (
int i = 1;
i < FLAGS_key.size();
i += 2) {
379 keyValuePairs[FLAGS_key[
i - 1]] = FLAGS_key[
i];
381 std::string config = FLAGS_surfaceConfig[0];
382 std::string cpuName = FLAGS_cpuName.isEmpty() ?
"" : FLAGS_cpuName[0];
383 std::string gpuName = FLAGS_gpuName.isEmpty() ?
"" : FLAGS_gpuName[0];
387 std::string errorMsg =
f();
388 if (errorMsg !=
"") {
389 SK_ABORT(
"Error while gathering GMs: %s", errorMsg.c_str());
393 std::unique_ptr<skiagm::GM> gm =
f();
401 run_gm(std::move(gm), config, keyValuePairs, cpuName, gpuName, outputDir, knownDigests);
408 "%d successful GMs (images written to %s).",
gNumSuccessfulGMs, outputDir.c_str());
void run_gm(std::unique_ptr< skiagm::GM > gm, std::string config, std::map< std::string, std::string > keyValuePairs, std::string cpuName, std::string gpuName, std::string outputDir, std::set< std::string > knownDigests)
int main(int argc, char **argv)
static int gNumSkippedGMs
static int gNumSuccessfulGMs
std::set< std::string > read_known_digests_file(std::string path)
static bool gMissingCpuOrGpuWarningLogged
static WritePNGAndJSONFilesResult write_png_and_json_files(std::string name, std::map< std::string, std::string > commonKeys, std::map< std::string, std::string > gmGoldKeys, std::map< std::string, std::string > surfaceGoldKeys, const SkBitmap &bitmap, const char *pngPath, const char *jsonPath, std::set< std::string > knownDigests)
static std::string draw_result_to_string(skiagm::DrawResult result)
static DEFINE_string(skip, "", "Space-separated list of test cases (regexps) to skip.")
static SkMD5::Digest md5(const SkBitmap &bm)
std::map< std::string, std::string > GetCompilationModeGoldAndPerfKeyValuePairs()
#define SK_ABORT(message,...)
static bool skip(SkStream *stream, size_t amount)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
static void Parse(int argc, const char *const *argv)
bool encodePNG(SkWStream *, const char *md5, CommandLineFlags::StringArray key, CommandLineFlags::StringArray properties) const
void feedHash(SkWStream *) const
static bool CreateStringFlag(const char *name, const char *shortName, CommandLineFlags::StringArray *pStrings, const char *defaultValue, const char *helpString, const char *extendedHelpString)
void beginObject(const char *name=nullptr, bool multiline=true)
void appendString(const char *value, size_t size)
static SkString Join(const char *rootPath, const char *relativePath)
const char * c_str() const
static std::unique_ptr< SurfaceManager > FromConfig(std::string config, SurfaceOptions surfaceOptions)
void StringEven(std::string name, CommandLineFlags::StringArray flag)
void StringNonEmpty(std::string name, CommandLineFlags::StringArray flag)
void StringAtMostOne(std::string name, CommandLineFlags::StringArray flag)
bool ShouldRunTestCase(const char *name, CommandLineFlags::StringArray &matchFlag, CommandLineFlags::StringArray &skipFlag)
void Log(const char *format,...) SK_PRINTF_LIKE(1
void InitAndLogCmdlineArgs(int argc, char **argv)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
std::function< std::unique_ptr< skiagm::GM >()> GMFactory
std::function< std::string()> GMRegistererFn
SkString toLowercaseHexString() const
enum WritePNGAndJSONFilesResult::@445 status
std::string skippedDigest