/* * 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/ganesh/GrContextOptions.h" #include "include/gpu/ganesh/GrDirectContext.h" #include "include/gpu/ganesh/GrTypes.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "tools/gpu/ContextType.h" #include "tools/gpu/TestContext.h" #endif #include #include #include #include #include #include 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 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; }