|  | /* | 
|  | * 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/ganesh/TestContext.h" | 
|  | #include "tools/gpu/ContextType.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 skbug.com/40033921 | 
|  | #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; | 
|  | } |