blob: 7af9103ae07bf65202b0857cdca8032f2b91ad83 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This runs *all* the tests registered via the Test registry in series. If one or more fail, those
* error messages will be printed out and a non-zero exit code will be returned. Otherwise, the
* exit code will be 0.
*/
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkDebug.h"
#include "tests/Test.h"
#include "tests/TestHarness.h"
#include "tools/flags/CommandLineFlags.h"
#include "tools/testrunners/common/TestRunner.h"
#if defined(SK_GANESH)
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/GrTypes.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "tools/gpu/ContextType.h"
#include "tools/gpu/TestContext.h"
#endif
#include <ctime>
#include <cwchar>
#include <functional>
#include <iomanip>
#include <sstream>
#include <string>
struct tm;
static DEFINE_string(skip, "", "Space-separated list of test cases (regexps) to skip.");
static DEFINE_string(
match,
"",
"Space-separated list of test cases (regexps) to run. Will run all tests if omitted.");
// Set in //bazel/devicesrc but consumed by other C++ test runners.
static DEFINE_string(key, "", "Ignored by this test runner.");
static DEFINE_string(cpuName, "", "Ignored by this test runner.");
static DEFINE_string(gpuName, "", "Ignored by this test runner.");
// Set in //bazel/devicesrc but only consumed by adb_test_runner.go. We cannot use the
// DEFINE_string macro because the flag name includes dashes.
[[maybe_unused]] static bool unused =
SkFlagInfo::CreateStringFlag("device-specific-bazel-config",
nullptr,
new CommandLineFlags::StringArray(),
nullptr,
"Ignored by this test runner.",
nullptr);
class BazelReporter : public skiatest::Reporter {
public:
void reportFailed(const skiatest::Failure& failure) override {
TestRunner::Log("FAIL: %s", failure.toString().c_str());
fFailed = true;
}
bool allowExtendedTest() const override { return false; }
bool verbose() const override { return false; }
bool ok() { return !fFailed; }
private:
bool fFailed = false;
};
#if defined(SK_GANESH)
namespace skiatest {
bool IsGLContextType(skgpu::ContextType type) {
return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kOpenGL;
}
bool IsVulkanContextType(skgpu::ContextType type) {
return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kVulkan;
}
bool IsMetalContextType(skgpu::ContextType type) {
return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kMetal;
}
bool IsDirect3DContextType(skgpu::ContextType type) {
return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kDirect3D;
}
bool IsMockContextType(skgpu::ContextType type) { return type == skgpu::ContextType::kMock; }
skgpu::ContextType compiledInContextTypes[] = {
#if defined(SK_GL)
// Use "native" instead of explicitly trying both OpenGL and OpenGL ES. Do not use GLES on
// desktop since tests do not account for not fixing http://skbug.com/2809
#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
skgpu::ContextType::kGL,
#else
skgpu::ContextType::kGLES,
#endif
#endif // defined(SK_GL)
#if defined(SK_VULKAN)
skgpu::ContextType::kVulkan,
#endif
#if defined(SK_DAWN)
skgpu::ContextType::kDawn,
#endif
// TODO(kjlubick) Other Ganesh backends
skgpu::ContextType::kMock,
};
// The macros defined in Test.h eventually call into this function. For each GPU backend that is
// compiled in, we run the testFn with a freshly created
void RunWithGaneshTestContexts(GrContextTestFn* testFn,
ContextTypeFilterFn* filter,
Reporter* reporter,
const GrContextOptions& options) {
sk_gpu_test::GrContextFactory factory(options);
for (skgpu::ContextType ctxType : compiledInContextTypes) {
if (filter && !(*filter)(ctxType)) {
continue;
}
sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(ctxType);
if (ctxInfo.directContext()) {
(*testFn)(reporter, ctxInfo);
// In case the test changed the current context make sure we move it back before
// calling flush.
ctxInfo.testContext()->makeCurrent();
// Sync so any release/finished procs get called.
ctxInfo.directContext()->flushAndSubmit(GrSyncCpu::kYes);
} else {
TestRunner::Log("Unable to make direct context for Ganesh test.");
SkASSERT(false);
return;
}
}
}
} // namespace skiatest
#endif // #if defined(SK_GANESH)
TestHarness CurrentTestHarness() { return TestHarness::kBazelUnitTestRunner; }
void maybeRunTest(const char* name, std::function<void()> testFn) {
if (!TestRunner::ShouldRunTestCase(name, FLAGS_match, FLAGS_skip)) {
TestRunner::Log("Skipping %s", name);
return;
}
TestRunner::Log("Running %s", name);
testFn();
TestRunner::Log("\tDone");
}
int main(int argc, char** argv) {
TestRunner::InitAndLogCmdlineArgs(argc, argv);
CommandLineFlags::Parse(argc, argv);
BazelReporter reporter;
for (skiatest::Test test : skiatest::TestRegistry::Range()) {
if (test.fTestType == skiatest::TestType::kCPU) {
maybeRunTest(test.fName, [&]() { test.cpu(&reporter); });
}
}
#if defined(SK_GANESH)
GrContextOptions grCtxOptions;
// TODO(kjlubick) DM has grContextOptions set via flags. Should this runner have that too?
grCtxOptions.fExecutor = nullptr;
grCtxOptions.fAllowPathMaskCaching = true;
grCtxOptions.fFailFlushTimeCallbacks = false;
grCtxOptions.fAllPathsVolatile = false;
grCtxOptions.fGpuPathRenderers = GpuPathRenderers::kDefault;
grCtxOptions.fDisableDriverCorrectnessWorkarounds = false;
grCtxOptions.fResourceCacheLimitOverride = -1;
grCtxOptions.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
for (skiatest::Test test : skiatest::TestRegistry::Range()) {
if (test.fTestType == skiatest::TestType::kGanesh) {
maybeRunTest(test.fName, [&]() { test.ganesh(&reporter, grCtxOptions); });
}
}
#endif
// TODO(kjlubick) Graphite support
if (reporter.ok()) {
TestRunner::Log("PASS");
return 0;
}
TestRunner::Log("FAIL");
return 1;
}