blob: e3b016ba855e4e9c9c28f8522ea129a187b00a12 [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"
#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 <ctime>
#include <cwchar>
#include <functional>
#include <iomanip>
#include <sstream>
#include <string>
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<void()> 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;
}