/* * 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" #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/TestContext.h" #endif #include #include #include #include #include #include struct tm; static DEFINE_string(skip, "", "Space-separated list of test cases to skip."); class BazelReporter : public skiatest::Reporter { public: void reportFailed(const skiatest::Failure& failure) override { SkDebugf("FAIL: %s\n", 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(sk_gpu_test::GrContextFactory::ContextType type) { return GrBackendApi::kOpenGL == sk_gpu_test::GrContextFactory::ContextTypeBackend(type); } bool IsVulkanContextType(sk_gpu_test::GrContextFactory::ContextType type) { return GrBackendApi::kVulkan == sk_gpu_test::GrContextFactory::ContextTypeBackend(type); } bool IsMetalContextType(sk_gpu_test::GrContextFactory::ContextType type) { return GrBackendApi::kMetal == sk_gpu_test::GrContextFactory::ContextTypeBackend(type); } bool IsDirect3DContextType(sk_gpu_test::GrContextFactory::ContextType type) { return GrBackendApi::kDirect3D == sk_gpu_test::GrContextFactory::ContextTypeBackend(type); } bool IsDawnContextType(sk_gpu_test::GrContextFactory::ContextType type) { return GrBackendApi::kDawn == sk_gpu_test::GrContextFactory::ContextTypeBackend(type); } bool IsRenderingGLContextType(sk_gpu_test::GrContextFactory::ContextType type) { return IsGLContextType(type) && sk_gpu_test::GrContextFactory::IsRenderingContext(type); } bool IsMockContextType(sk_gpu_test::GrContextFactory::ContextType type) { return type == sk_gpu_test::GrContextFactory::kMock_ContextType; } sk_gpu_test::GrContextFactory::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) sk_gpu_test::GrContextFactory::kGL_ContextType, #else sk_gpu_test::GrContextFactory::kGLES_ContextType, #endif #endif // defined(SK_GL) #if defined(SK_VULKAN) sk_gpu_test::GrContextFactory::kVulkan_ContextType, #endif #if defined(SK_DAWN) sk_gpu_test::GrContextFactory::kDawn_ContextType, #endif // TODO(kjlubick) Other Ganesh backends sk_gpu_test::GrContextFactory::kMock_ContextType, }; // 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, GrContextTypeFilterFn* filter, Reporter* reporter, const GrContextOptions& options) { sk_gpu_test::GrContextFactory factory(options); for (sk_gpu_test::GrContextFactory::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(/*syncCPU=*/true); } else { SkDebugf("Unable to make direct context for Ganesh test.\n"); SkASSERT(false); return; } } } } // namespace skiatest #endif // #if defined(SK_GANESH) TestHarness CurrentTestHarness() { return TestHarness::kBazelTestRunner; } std::string now() { std::time_t t = std::time(nullptr); std::tm *now = std::gmtime(&t); std::ostringstream oss; oss << std::put_time(now, "%Y-%m-%d %H:%M:%S UTC"); return oss.str(); } void maybeRunTest(const char* name, std::function testFn) { if (FLAGS_skip.contains(name)) { SkDebugf("[%s] Skipping %s\n", now().c_str(), name); return; } SkDebugf("[%s] Running %s\n", now().c_str(), name); testFn(); SkDebugf("[%s]\tDone\n", now().c_str()); } int main(int argc, char** argv) { #ifdef SK_BUILD_FOR_ANDROID extern bool gSkDebugToStdOut; // If true, sends SkDebugf to stdout as well. gSkDebugToStdOut = true; #endif if (argc < 2) { SkDebugf("Test runner invoked with no arguments.\n"); } else { std::ostringstream oss; oss << "Test runner invoked with arguments:"; for (int i = 1; i < argc; i++) { oss << " " << argv[i]; } SkDebugf("%s\n", oss.str().c_str()); } 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()) { SkDebugf("PASS\n"); return 0; } SkDebugf("FAIL\n"); return 1; }