ac7f23c807
* C++ code moved into tools/skqp/src/. * State held with single SkQP class. * gmkb functions moved to skqp_model.{h,cpp} * model no longer knows about report format. * skqp_main and skqp_lib no longer have globals * jni code has fewer globals. * skqp_main no longer uses googletest. * AssetMng returns SkData, not a SkStream. * Add jitter tool. * dump GPU information into grdump.txt * JUnit puts report in directory with timestamp. * Document SkQP Render Test Algorithm. * GPU driver correctness workarounds always off * cut_release tool for assembling models * make_rendertests_list.py to help cut_release * make_gmkb.go emits a list of models CQ_INCLUDE_TRYBOTS=skia.primary:Build-Debian9-Clang-x86-devrel-Android_SKQP Change-Id: I7d4f0c24592b1f64be0088578a3f1a0bc366dd4d Reviewed-on: https://skia-review.googlesource.com/c/110420 Reviewed-by: Hal Canary <halcanary@google.com> Commit-Queue: Hal Canary <halcanary@google.com>
146 lines
4.7 KiB
C++
146 lines
4.7 KiB
C++
/*
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <sys/stat.h>
|
|
|
|
#include "skqp.h"
|
|
|
|
#include "Resources.h"
|
|
#include "SkData.h"
|
|
#include "SkOSFile.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace {
|
|
class StdAssetManager : public SkQPAssetManager {
|
|
public:
|
|
StdAssetManager(const char* p) : fPrefix(p) {
|
|
SkASSERT(!fPrefix.empty());
|
|
//TODO(halcanary): does this need to be changed if I run SkQP in Windows?
|
|
fPrefix += "/";
|
|
}
|
|
sk_sp<SkData> open(const char* path) override {
|
|
return SkData::MakeFromFileName((fPrefix + path).c_str());
|
|
}
|
|
private:
|
|
std::string fPrefix;
|
|
};
|
|
}
|
|
|
|
static constexpr char kSkipUsage[] =
|
|
" TEST_MATCH_RULES:"
|
|
" [~][^]substring[$] [...] of name to run.\n"
|
|
" Multiple matches may be separated by spaces.\n"
|
|
" ~ causes a matching name to always be skipped\n"
|
|
" ^ requires the start of the name to match\n"
|
|
" $ requires the end of the name to match\n"
|
|
" ^ and $ requires an exact match\n"
|
|
" If a name does not match any list entry,\n"
|
|
" it is skipped unless some list entry starts with ~\n";
|
|
|
|
static bool should_skip(const char* const* rules, size_t count, const char* name) {
|
|
size_t testLen = strlen(name);
|
|
bool anyExclude = count == 0;
|
|
for (size_t i = 0; i < count; ++i) {
|
|
const char* matchName = rules[i];
|
|
size_t matchLen = strlen(matchName);
|
|
bool matchExclude, matchStart, matchEnd;
|
|
if ((matchExclude = matchName[0] == '~')) {
|
|
anyExclude = true;
|
|
matchName++;
|
|
matchLen--;
|
|
}
|
|
if ((matchStart = matchName[0] == '^')) {
|
|
matchName++;
|
|
matchLen--;
|
|
}
|
|
if ((matchEnd = matchName[matchLen - 1] == '$')) {
|
|
matchLen--;
|
|
}
|
|
if (matchStart ? (!matchEnd || matchLen == testLen)
|
|
&& strncmp(name, matchName, matchLen) == 0
|
|
: matchEnd ? matchLen <= testLen
|
|
&& strncmp(name + testLen - matchLen, matchName, matchLen) == 0
|
|
: strstr(name, matchName) != nullptr) {
|
|
return matchExclude;
|
|
}
|
|
}
|
|
return !anyExclude;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc < 3) {
|
|
std::cerr << "Usage:\n " << argv[0]
|
|
<< " ASSET_DIRECTORY_PATH SKQP_REPORT_PATH [TEST_MATCH_RULES]\n"
|
|
<< kSkipUsage << '\n';
|
|
return 1;
|
|
}
|
|
SetResourcePath((std::string(argv[1]) + "/resources").c_str());
|
|
if (!sk_mkdir(argv[2])) {
|
|
std::cerr << "sk_mkdir(" << argv[2] << ") failed.\n";
|
|
return 2;
|
|
}
|
|
StdAssetManager mgr(argv[1]);
|
|
SkQP skqp;
|
|
skqp.init(&mgr, argv[2]);
|
|
int ret = 0;
|
|
|
|
const char* const* matchRules = &argv[3];
|
|
size_t matchRulesCount = (size_t)(argc - 3);
|
|
|
|
// Rendering Tests
|
|
std::ostream& out = std::cout;
|
|
for (auto backend : skqp.getSupportedBackends()) {
|
|
auto testPrefix = std::string(SkQP::GetBackendName(backend)) + "_";
|
|
for (auto gmFactory : skqp.getGMs()) {
|
|
auto testName = testPrefix + SkQP::GetGMName(gmFactory);
|
|
if (should_skip(matchRules, matchRulesCount, testName.c_str())) {
|
|
continue;
|
|
}
|
|
out << "Starting: " << testName << std::endl;
|
|
SkQP::RenderOutcome outcome;
|
|
std::string except;
|
|
|
|
std::tie(outcome, except) = skqp.evaluateGM(backend, gmFactory);
|
|
if (!except.empty()) {
|
|
out << "ERROR: " << testName << " (" << except << ")\n";
|
|
ret = 1;
|
|
} else if (outcome.fMaxError != 0) {
|
|
out << "FAILED: " << testName << " (" << outcome.fMaxError << ")\n";
|
|
ret = 1;
|
|
} else {
|
|
out << "Passed: " << testName << "\n";
|
|
}
|
|
out.flush();
|
|
}
|
|
}
|
|
|
|
// Unit Tests
|
|
for (auto test : skqp.getUnitTests()) {
|
|
auto testName = std::string("unitTest_") + SkQP::GetUnitTestName(test);
|
|
if (should_skip(matchRules, matchRulesCount, testName.c_str())) {
|
|
continue;
|
|
}
|
|
out << "Starting test: " << testName << std::endl;
|
|
std::vector<std::string> errors = skqp.executeTest(test);
|
|
if (!errors.empty()) {
|
|
out << "TEST FAILED (" << errors.size() << "): " << testName << "\n";
|
|
for (const std::string& error : errors) {
|
|
out << error << "\n";
|
|
}
|
|
ret = 1;
|
|
} else {
|
|
out << "Test passed: " << testName << "\n";
|
|
}
|
|
out.flush();
|
|
}
|
|
skqp.makeReport();
|
|
|
|
return ret;
|
|
}
|