Let DM run unit tests.

- refactor GYPs and a few flags
  - make GPU tests grab a thread-local GrContextFactory when needed as we do in DM for GMs
  - add a few more UI features to make DM more like tests

I believe this makes the program 'tests' obsolete.

It should be somewhat faster to run the two sets together than running the old binaries serially:
  - serial: tests 20s (3m18s CPU), dm 21s (3m01s CPU)
  - together: 27s (6m21s CPU)

Next up is to incorporate benches.  I'm only planning there on a single-pass sanity check, so that won't obsolete the program 'bench' just yet.

Tested: out/Debug/tests && out/Debug/dm && echo ok
BUG=skia:

Committed: http://code.google.com/p/skia/source/detail?r=13586

R=reed@google.com, bsalomon@google.com, mtklein@google.com, tfarina@chromium.org

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/178273002

git-svn-id: http://skia.googlecode.com/svn/trunk@13592 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-02-26 16:31:22 +00:00
parent 1e762d39bb
commit 0dc5bd149a
17 changed files with 435 additions and 287 deletions

View File

@ -7,26 +7,29 @@
#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkString.h"
#include "Test.h"
#include "gm.h"
#include "DMCpuTask.h"
#include "DMGpuTask.h"
#include "DMReporter.h"
#include "DMTask.h"
#include "DMTaskRunner.h"
#include "DMCpuTask.h"
#include "DMGpuTask.h"
#include "DMTestTask.h"
#include "DMWriteTask.h"
#include <string.h>
using skiagm::GM;
using skiagm::GMRegistry;
using skiatest::Test;
using skiatest::TestRegistry;
DEFINE_int32(cpuThreads, -1, "Threads for CPU work. Default NUM_CPUS.");
DEFINE_int32(gpuThreads, 1, "Threads for GPU work.");
DEFINE_int32(threads, -1, "Threads for CPU work. Default NUM_CPUS.");
DEFINE_string2(expectations, r, "",
"If a directory, compare generated images against images under this path. "
"If a file, compare generated images against JSON expectations at this path.");
DEFINE_string(resources, "resources", "Path to resources directory.");
DEFINE_string2(resources, i, "resources", "Path to resources directory.");
DEFINE_string(match, "", "[~][^]substring[$] [...] of GM name to run.\n"
"Multiple matches may be separated by spaces.\n"
"~ causes a matching GM to always be skipped\n"
@ -37,6 +40,10 @@ DEFINE_string(match, "", "[~][^]substring[$] [...] of GM name to run.\n"
"it is skipped unless some list entry starts with ~");
DEFINE_string(config, "565 8888 gpu",
"Options: 565 8888 gpu msaa4 msaa16 gpunull gpudebug angle mesa"); // TODO(mtklein): pdf
DEFINE_bool(leaks, false, "Print leaked instance-counted objects at exit?");
DEFINE_bool(gms, true, "Run GMs?");
DEFINE_bool(tests, true, "Run tests?");
__SK_FORCE_IMAGE_DECODER_LINKING;
@ -48,11 +55,11 @@ static SkString lowercase(SkString s) {
return s;
}
static void kick_off_tasks(const SkTDArray<GMRegistry::Factory>& gms,
const SkTArray<SkString>& configs,
const DM::Expectations& expectations,
DM::Reporter* reporter,
DM::TaskRunner* tasks) {
static void kick_off_gms(const SkTDArray<GMRegistry::Factory>& gms,
const SkTArray<SkString>& configs,
const DM::Expectations& expectations,
DM::Reporter* reporter,
DM::TaskRunner* tasks) {
const SkColorType _565 = kRGB_565_SkColorType;
const SkColorType _8888 = kPMColor_SkColorType;
const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType;
@ -93,6 +100,14 @@ static void kick_off_tasks(const SkTDArray<GMRegistry::Factory>& gms,
#undef START
}
static void kick_off_tests(const SkTDArray<TestRegistry::Factory>& tests,
DM::Reporter* reporter,
DM::TaskRunner* tasks) {
for (int i = 0; i < tests.count(); i++) {
tasks->add(SkNEW_ARGS(DM::TestTask, (reporter, tasks, tests[i])));
}
}
static void report_failures(const DM::Reporter& reporter) {
SkTArray<SkString> failures;
reporter.getFailures(&failures);
@ -109,40 +124,57 @@ static void report_failures(const DM::Reporter& reporter) {
int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
#if SK_ENABLE_INST_COUNT
gPrintInstCount = FLAGS_leaks;
#endif
SkGraphics::Init();
SkCommandLineFlags::Parse(argc, argv);
GM::SetResourcePath(FLAGS_resources[0]);
Test::SetResourcePath(FLAGS_resources[0]);
SkTArray<SkString> configs;
for (int i = 0; i < FLAGS_config.count(); i++) {
SkStrSplit(FLAGS_config[i], ", ", &configs);
}
SkTDArray<GMRegistry::Factory> gms;
for (const GMRegistry* reg = GMRegistry::Head(); reg != NULL; reg = reg->next()) {
SkAutoTDelete<GM> gmForName(reg->factory()(NULL));
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gmForName->shortName())) {
*gms.append() = reg->factory();
}
}
SkDebugf("%d GMs x %d configs\n", gms.count(), configs.count());
SkAutoTDelete<DM::Expectations> expectations(SkNEW(DM::NoExpectations));
if (FLAGS_expectations.count() > 0) {
const char* path = FLAGS_expectations[0];
if (sk_isdir(path)) {
expectations.reset(SkNEW_ARGS(DM::WriteTask::Expectations, (path)));
} else {
expectations.reset(SkNEW_ARGS(DM::JsonExpectations, (path)));
if (FLAGS_gms) {
for (int i = 0; i < FLAGS_config.count(); i++) {
SkStrSplit(FLAGS_config[i], ", ", &configs);
}
for (const GMRegistry* reg = GMRegistry::Head(); reg != NULL; reg = reg->next()) {
SkAutoTDelete<GM> gmForName(reg->factory()(NULL));
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gmForName->shortName())) {
*gms.append() = reg->factory();
}
}
if (FLAGS_expectations.count() > 0) {
const char* path = FLAGS_expectations[0];
if (sk_isdir(path)) {
expectations.reset(SkNEW_ARGS(DM::WriteTask::Expectations, (path)));
} else {
expectations.reset(SkNEW_ARGS(DM::JsonExpectations, (path)));
}
}
}
SkTDArray<TestRegistry::Factory> tests;
if (FLAGS_tests) {
for (const TestRegistry* reg = TestRegistry::Head(); reg != NULL; reg = reg->next()) {
SkAutoTDelete<Test> testForName(reg->factory()(NULL));
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, testForName->getName())) {
*tests.append() = reg->factory();
}
}
}
SkDebugf("%d GMs x %d configs, %d tests\n", gms.count(), configs.count(), tests.count());
DM::Reporter reporter;
DM::TaskRunner tasks(FLAGS_cpuThreads, FLAGS_gpuThreads);
kick_off_tasks(gms, configs, *expectations, &reporter, &tasks);
DM::TaskRunner tasks(FLAGS_threads);
kick_off_gms(gms, configs, *expectations, &reporter, &tasks);
kick_off_tests(tests, &reporter, &tasks);
tasks.wait();
reporter.updateStatusLine();
SkDebugf("\n");
report_failures(reporter);

View File

@ -18,6 +18,7 @@ GpuTask::GpuTask(const char* name,
GrContextFactory::GLContextType contextType,
int sampleCount)
: Task(reporter, taskRunner)
, fTaskRunner(taskRunner)
, fGM(gmFactory(NULL))
, fName(UnderJoin(fGM->shortName(), name))
, fExpectations(expectations)
@ -26,24 +27,12 @@ GpuTask::GpuTask(const char* name,
, fSampleCount(sampleCount)
{}
static void* new_gr_context_factory() {
return SkNEW(GrContextFactory);
}
static void delete_gr_context_factory(void* factory) {
SkDELETE((GrContextFactory*) factory);
}
static GrContextFactory* get_gr_factory() {
return reinterpret_cast<GrContextFactory*>(SkTLS::Get(&new_gr_context_factory,
&delete_gr_context_factory));
}
void GpuTask::draw() {
GrContext* gr = get_gr_factory()->get(fContextType); // Will be owned by device.
SkImageInfo info = SkImageInfo::Make(SkScalarCeilToInt(fGM->width()),
SkScalarCeilToInt(fGM->height()),
fColorType, kPremul_SkAlphaType);
fColorType,
kPremul_SkAlphaType);
GrContext* gr = fTaskRunner->getGrContextFactory()->get(fContextType); // Owned by surface.
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(gr, info, fSampleCount));
SkCanvas* canvas = surface->getCanvas();

View File

@ -32,6 +32,7 @@ public:
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
TaskRunner* fTaskRunner;
SkAutoTDelete<skiagm::GM> fGM;
const SkString fName;
const Expectations& fExpectations;

View File

@ -3,21 +3,27 @@
#include "SkCommandLineFlags.h"
#include "OverwriteLine.h"
DEFINE_bool(quiet, false, "If true, don't print status updates.");
DEFINE_bool2(quiet, q, false, "If true, don't print status updates.");
DEFINE_bool2(verbose, v, false, "If true, print status updates one-per-line.");
namespace DM {
void Reporter::updateStatusLine() const {
void Reporter::finish(SkString name) {
sk_atomic_inc(&fFinished);
if (FLAGS_quiet) {
return;
}
SkString status;
status.printf("%s%d tasks left", kSkOverwriteLine, this->started() - this->finished());
status.printf("%s%d tasks left",
FLAGS_verbose ? "\n" : kSkOverwriteLine,
this->started() - this->finished());
const int failed = this->failed();
if (failed > 0) {
status.appendf(", %d failed", failed);
}
status.appendf("\t[%s done]", name.c_str());
SkDebugf(status.c_str());
}
@ -26,9 +32,9 @@ int32_t Reporter::failed() const {
return fFailures.count();
}
void Reporter::fail(SkString name) {
void Reporter::fail(SkString msg) {
SkAutoMutexAcquire writer(&fMutex);
fFailures.push_back(name);
fFailures.push_back(msg);
}
void Reporter::getFailures(SkTArray<SkString>* failures) const {

View File

@ -7,7 +7,6 @@
#include "SkTypes.h"
// Used to report status changes including failures. All public methods are threadsafe.
namespace DM {
class Reporter : SkNoncopyable {
@ -15,15 +14,13 @@ public:
Reporter() : fStarted(0), fFinished(0) {}
void start() { sk_atomic_inc(&fStarted); }
void finish() { sk_atomic_inc(&fFinished); }
void fail(SkString name);
void finish(SkString name);
void fail(SkString msg);
int32_t started() const { return fStarted; }
int32_t finished() const { return fFinished; }
int32_t failed() const;
void updateStatusLine() const;
void getFailures(SkTArray<SkString>*) const;
private:

View File

@ -26,8 +26,7 @@ void Task::run() {
if (!this->shouldSkip()) {
this->draw();
}
fReporter->finish();
fReporter->updateStatusLine();
fReporter->finish(this->name());
delete this;
}
@ -39,8 +38,12 @@ void Task::spawnChild(Task* task) {
}
}
void Task::fail() {
fReporter->fail(this->name());
void Task::fail(const char* msg) {
SkString failure(this->name());
if (msg) {
failure.appendf(": %s", msg);
}
fReporter->fail(failure);
}
} // namespace DM

View File

@ -34,7 +34,7 @@ public:
protected:
void spawnChild(Task* task);
void fail();
void fail(const char* msg = NULL);
private:
// Both unowned.

View File

@ -3,10 +3,21 @@
namespace DM {
TaskRunner::TaskRunner(int cputhreads, int gpuThreads)
TaskRunner::TaskRunner(int cputhreads)
: fMain(cputhreads)
, fGpu(gpuThreads)
{}
, fGpu(1) {
// Enqueue a task on the GPU thread to create a GrContextFactory.
struct Create : public SkRunnable {
Create(GrContextFactory** ptr) : fPtr(ptr) {}
void run() SK_OVERRIDE {
*fPtr = SkNEW(GrContextFactory);
delete this;
}
GrContextFactory** fPtr;
};
fGpu.add(SkNEW_ARGS(Create, (&fGrContextFactory)));
}
void TaskRunner::add(Task* task) {
if (task->usesGpu()) {
@ -17,6 +28,17 @@ void TaskRunner::add(Task* task) {
}
void TaskRunner::wait() {
// Enqueue a task on the GPU thread to destroy the GrContextFactory.
struct Delete : public SkRunnable {
Delete(GrContextFactory* ptr) : fPtr(ptr) {}
void run() SK_OVERRIDE {
delete fPtr;
delete this;
}
GrContextFactory* fPtr;
};
fGpu.add(SkNEW_ARGS(Delete, (fGrContextFactory)));
// These wait calls block until the threadpool is done. We don't allow
// children to spawn new GPU tasks so we can wait for that first knowing
// we'll never try to add to it later. Same can't be said of fMain: fGpu

View File

@ -1,12 +1,12 @@
#ifndef DMTaskRunner_DEFINED
#define DMTaskRunner_DEFINED
#include "GrContextFactory.h"
#include "SkThreadPool.h"
#include "SkTypes.h"
// TaskRunner runs Tasks on one of two threadpools depending on the Task's usesGpu() method.
// This lets us drive the GPU with a small number of threads (e.g. 2 or 4 can be faster than 1)
// while not swamping it with requests from the full fleet of threads that CPU-bound tasks run on.
// TaskRunner runs Tasks on one of two threadpools depending on the Task's usesGpu() method. This
// lets us drive the GPU from a single thread while parallelizing CPU-bound work.
namespace DM {
@ -14,13 +14,17 @@ class Task;
class TaskRunner : SkNoncopyable {
public:
TaskRunner(int cputhreads, int gpuThreads);
explicit TaskRunner(int cputhreads);
void add(Task* task);
void wait();
// This can only be safely called from a GPU task's draw() method.
GrContextFactory* getGrContextFactory() const { return fGrContextFactory; }
private:
SkThreadPool fMain, fGpu;
GrContextFactory* fGrContextFactory; // Created and destroyed on fGpu threadpool.
};
} // namespace DM

34
dm/DMTestTask.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "DMTestTask.h"
#include "DMUtil.h"
#include "SkCommandLineFlags.h"
DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.");
DEFINE_bool2(pathOpsSingleThread, z, false, "Disallow pathOps tests from using threads.");
DEFINE_bool2(pathOpsVerbose, V, false, "Tell pathOps tests to be verbose.");
namespace DM {
TestTask::TestTask(Reporter* reporter,
TaskRunner* taskRunner,
skiatest::TestRegistry::Factory factory)
: Task(reporter, taskRunner)
, fTaskRunner(taskRunner)
, fTest(factory(NULL))
, fName(UnderJoin("test", fTest->getName())) {}
void TestTask::draw() {
if (this->usesGpu()) {
fTest->setGrContextFactory(fTaskRunner->getGrContextFactory());
}
fTest->setReporter(&fTestReporter);
fTest->run();
if (!fTest->passed()) {
this->fail(fTestReporter.failure());
}
}
bool TestTask::TestReporter::allowExtendedTest() const { return FLAGS_pathOpsExtended; }
bool TestTask::TestReporter::allowThreaded() const { return !FLAGS_pathOpsSingleThread; }
bool TestTask::TestReporter::verbose() const { return FLAGS_pathOpsVerbose; }
} // namespace DM

50
dm/DMTestTask.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef DMTestTask_DEFINED
#define DMTestTask_DEFINED
#include "DMReporter.h"
#include "DMTask.h"
#include "DMTaskRunner.h"
#include "SkString.h"
#include "SkTemplates.h"
#include "Test.h"
// Runs a unit test.
namespace DM {
class TestTask : public Task {
public:
TestTask(Reporter*, TaskRunner*, skiatest::TestRegistry::Factory);
virtual void draw() SK_OVERRIDE;
virtual bool usesGpu() const SK_OVERRIDE { return fTest->isGPUTest(); }
virtual bool shouldSkip() const SK_OVERRIDE { return false; }
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
class TestReporter : public skiatest::Reporter {
public:
TestReporter() {}
const char* failure() const { return fFailure.c_str(); }
private:
virtual bool allowExtendedTest() const SK_OVERRIDE;
virtual bool allowThreaded() const SK_OVERRIDE;
virtual bool verbose() const SK_OVERRIDE;
virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
fFailure = desc;
}
SkString fFailure;
};
TaskRunner* fTaskRunner;
TestReporter fTestReporter;
SkAutoTDelete<skiatest::Test> fTest;
const SkString fName;
};
} // namespace DM
#endif // DMTestTask_DEFINED

View File

@ -9,6 +9,7 @@
'include_dirs': [
'../dm',
'../gm',
'../tests',
'../src/images',
'../src/lazy',
'../src/core',
@ -18,7 +19,11 @@
'../src/utils/debugger',
'../tools',
],
'includes': [ 'gmslides.gypi' ],
'includes': [
'gmslides.gypi',
'pathops_unittest.gypi',
'tests.gypi',
],
'sources': [
'../dm/DM.cpp',
'../dm/DMCpuTask.cpp',
@ -30,6 +35,7 @@
'../dm/DMSerializeTask.cpp',
'../dm/DMTask.cpp',
'../dm/DMTaskRunner.cpp',
'../dm/DMTestTask.cpp',
'../dm/DMTileGridTask.cpp',
'../dm/DMUtil.cpp',
'../dm/DMWriteTask.cpp',

View File

@ -7,188 +7,12 @@
{
'target_name': 'tests',
'type': 'executable',
'include_dirs' : [
'../src/core',
'../src/effects',
'../src/image',
'../src/lazy',
'../src/images',
'../src/pathops',
'../src/pdf',
'../src/pipe/utils',
'../src/utils',
'../src/utils/debugger',
'../tools/',
# Needed for TDStackNesterTest.
'../experimental/PdfViewer',
'../experimental/PdfViewer/src',
],
'includes': [
'pathops_unittest.gypi',
'tests.gypi',
],
'sources': [
'../tests/AAClipTest.cpp',
'../tests/ARGBImageEncoderTest.cpp',
'../tests/AndroidPaintTest.cpp',
'../tests/AnnotationTest.cpp',
'../tests/AtomicTest.cpp',
'../tests/BBoxHierarchyTest.cpp',
'../tests/BitSetTest.cpp',
'../tests/BitmapCopyTest.cpp',
'../tests/BitmapGetColorTest.cpp',
'../tests/BitmapHasherTest.cpp',
'../tests/BitmapHeapTest.cpp',
'../tests/BitmapTest.cpp',
'../tests/BlendTest.cpp',
'../tests/BlitRowTest.cpp',
'../tests/BlurTest.cpp',
'../tests/CachedDecodingPixelRefTest.cpp',
'../tests/CanvasStateTest.cpp',
'../tests/CanvasTest.cpp',
'../tests/ChecksumTest.cpp',
'../tests/ClampRangeTest.cpp',
'../tests/ClipCacheTest.cpp',
'../tests/ClipCubicTest.cpp',
'../tests/ClipStackTest.cpp',
'../tests/ClipperTest.cpp',
'../tests/ColorFilterTest.cpp',
'../tests/ColorPrivTest.cpp',
'../tests/ColorTest.cpp',
'../tests/DataRefTest.cpp',
'../tests/DeferredCanvasTest.cpp',
'../tests/DequeTest.cpp',
'../tests/DeviceLooperTest.cpp',
'../tests/DiscardableMemoryPool.cpp',
'../tests/DiscardableMemoryTest.cpp',
'../tests/DocumentTest.cpp',
'../tests/DrawBitmapRectTest.cpp',
'../tests/DrawPathTest.cpp',
'../tests/DrawTextTest.cpp',
'../tests/DynamicHashTest.cpp',
'../tests/EmptyPathTest.cpp',
'../tests/ErrorTest.cpp',
'../tests/FillPathTest.cpp',
'../tests/FitsInTest.cpp',
'../tests/FlatDataTest.cpp',
'../tests/FlateTest.cpp',
'../tests/FontHostStreamTest.cpp',
'../tests/FontHostTest.cpp',
'../tests/FontMgrTest.cpp',
'../tests/FontNamesTest.cpp',
'../tests/FrontBufferedStreamTest.cpp',
'../tests/GLInterfaceValidation.cpp',
'../tests/GLProgramsTest.cpp',
'../tests/GeometryTest.cpp',
'../tests/GifTest.cpp',
'../tests/GpuBitmapCopyTest.cpp',
'../tests/GpuColorFilterTest.cpp',
'../tests/GpuDrawPathTest.cpp',
'../tests/GrBinHashKeyTest.cpp',
'../tests/GrContextFactoryTest.cpp',
'../tests/GrDrawTargetTest.cpp',
'../tests/GrMemoryPoolTest.cpp',
'../tests/GrRedBlackTreeTest.cpp',
'../tests/GrSurfaceTest.cpp',
'../tests/GrTBSearchTest.cpp',
'../tests/GradientTest.cpp',
'../tests/HashCacheTest.cpp',
'../tests/ImageCacheTest.cpp',
'../tests/ImageDecodingTest.cpp',
'../tests/ImageFilterTest.cpp',
'../tests/InfRectTest.cpp',
'../tests/JpegTest.cpp',
'../tests/LListTest.cpp',
'../tests/LayerDrawLooperTest.cpp',
'../tests/MD5Test.cpp',
'../tests/MallocPixelRefTest.cpp',
'../tests/MathTest.cpp',
'../tests/Matrix44Test.cpp',
'../tests/MatrixClipCollapseTest.cpp',
'../tests/MatrixTest.cpp',
'../tests/MemoryTest.cpp',
'../tests/MemsetTest.cpp',
'../tests/MessageBusTest.cpp',
'../tests/MetaDataTest.cpp',
'../tests/MipMapTest.cpp',
'../tests/OSPathTest.cpp',
'../tests/OnceTest.cpp',
'../tests/PDFPrimitivesTest.cpp',
'../tests/PackBitsTest.cpp',
'../tests/PaintTest.cpp',
'../tests/ParsePathTest.cpp',
'../tests/PathCoverageTest.cpp',
'../tests/PathMeasureTest.cpp',
'../tests/PathTest.cpp',
'../tests/PathUtilsTest.cpp',
'../tests/PictureTest.cpp',
'../tests/PictureUtilsTest.cpp',
'../tests/PipeTest.cpp',
'../tests/PixelRefTest.cpp',
'../tests/PointTest.cpp',
'../tests/PremulAlphaRoundTripTest.cpp',
'../tests/QuickRejectTest.cpp',
'../tests/RTreeTest.cpp',
'../tests/RandomTest.cpp',
'../tests/ReadPixelsTest.cpp',
'../tests/ReadWriteAlphaTest.cpp',
'../tests/Reader32Test.cpp',
'../tests/RefCntTest.cpp',
'../tests/RefDictTest.cpp',
'../tests/RegionTest.cpp',
'../tests/ResourceCacheTest.cpp',
'../tests/RoundRectTest.cpp',
'../tests/RuntimeConfigTest.cpp',
'../tests/SHA1Test.cpp',
'../tests/ScalarTest.cpp',
'../tests/SerializationTest.cpp',
'../tests/ShaderImageFilterTest.cpp',
'../tests/ShaderOpacityTest.cpp',
'../tests/SkBase64Test.cpp',
'../tests/SortTest.cpp',
'../tests/SrcOverTest.cpp',
'../tests/StreamTest.cpp',
'../tests/StringTest.cpp',
'../tests/StrokeTest.cpp',
'../tests/SurfaceTest.cpp',
'../tests/TLSTest.cpp',
'../tests/TSetTest.cpp',
'../tests/Test.cpp',
'../tests/Test.h',
'../tests/TestSize.cpp',
'../tests/TileGridTest.cpp',
'../tests/TracingTest.cpp',
'../tests/ToUnicode.cpp',
'../tests/Typeface.cpp',
'../tests/UnicodeTest.cpp',
'../tests/UnitTestTest.cpp',
'../tests/UtilsTest.cpp',
'../tests/WArrayTest.cpp',
'../tests/WritePixelsTest.cpp',
'../tests/Writer32Test.cpp',
'../tests/XfermodeTest.cpp',
'../tests/skia_test.cpp',
'../experimental/PdfViewer/src/SkTDStackNester.h',
'../tests/TDStackNesterTest.cpp',
# Needed for PipeTest.
'../src/pipe/utils/SamplePipeControllers.cpp',
# Needed for MatrixClipCollapse test.
'../src/utils/debugger/SkDrawCommand.h',
'../src/utils/debugger/SkDrawCommand.cpp',
'../src/utils/debugger/SkDebugCanvas.h',
'../src/utils/debugger/SkDebugCanvas.cpp',
'../src/utils/debugger/SkObjectParser.h',
'../src/utils/debugger/SkObjectParser.cpp',
],
'dependencies': [
'skia_lib.gyp:skia_lib',
'flags.gyp:flags',
'experimental.gyp:experimental',
'pdf.gyp:pdf',
'tools.gyp:picture_utils',
],
'conditions': [
[ 'skia_gpu == 1', {

181
gyp/tests.gypi Normal file
View File

@ -0,0 +1,181 @@
{
'include_dirs': [
'../src/core',
'../src/effects',
'../src/image',
'../src/lazy',
'../src/images',
'../src/pathops',
'../src/pdf',
'../src/pipe/utils',
'../src/utils',
'../src/utils/debugger',
'../tools/',
# Needed for TDStackNesterTest.
'../experimental/PdfViewer',
'../experimental/PdfViewer/src',
],
'dependencies': [
'skia_lib.gyp:skia_lib',
'experimental.gyp:experimental',
'flags.gyp:flags',
'pdf.gyp:pdf',
'tools.gyp:picture_utils',
],
'sources': [
'../tests/Test.cpp',
'../tests/Test.h',
'../tests/AAClipTest.cpp',
'../tests/ARGBImageEncoderTest.cpp',
'../tests/AndroidPaintTest.cpp',
'../tests/AnnotationTest.cpp',
'../tests/AtomicTest.cpp',
'../tests/BBoxHierarchyTest.cpp',
'../tests/BitSetTest.cpp',
'../tests/BitmapCopyTest.cpp',
'../tests/BitmapGetColorTest.cpp',
'../tests/BitmapHasherTest.cpp',
'../tests/BitmapHeapTest.cpp',
'../tests/BitmapTest.cpp',
'../tests/BlendTest.cpp',
'../tests/BlitRowTest.cpp',
'../tests/BlurTest.cpp',
'../tests/CachedDecodingPixelRefTest.cpp',
'../tests/CanvasStateTest.cpp',
'../tests/CanvasTest.cpp',
'../tests/ChecksumTest.cpp',
'../tests/ClampRangeTest.cpp',
'../tests/ClipCacheTest.cpp',
'../tests/ClipCubicTest.cpp',
'../tests/ClipStackTest.cpp',
'../tests/ClipperTest.cpp',
'../tests/ColorFilterTest.cpp',
'../tests/ColorPrivTest.cpp',
'../tests/ColorTest.cpp',
'../tests/DataRefTest.cpp',
'../tests/DeferredCanvasTest.cpp',
'../tests/DequeTest.cpp',
'../tests/DeviceLooperTest.cpp',
'../tests/DiscardableMemoryPool.cpp',
'../tests/DiscardableMemoryTest.cpp',
'../tests/DocumentTest.cpp',
'../tests/DrawBitmapRectTest.cpp',
'../tests/DrawPathTest.cpp',
'../tests/DrawTextTest.cpp',
'../tests/DynamicHashTest.cpp',
'../tests/EmptyPathTest.cpp',
'../tests/ErrorTest.cpp',
'../tests/FillPathTest.cpp',
'../tests/FitsInTest.cpp',
'../tests/FlatDataTest.cpp',
'../tests/FlateTest.cpp',
'../tests/FontHostStreamTest.cpp',
'../tests/FontHostTest.cpp',
'../tests/FontMgrTest.cpp',
'../tests/FontNamesTest.cpp',
'../tests/FrontBufferedStreamTest.cpp',
'../tests/GLInterfaceValidation.cpp',
'../tests/GLProgramsTest.cpp',
'../tests/GeometryTest.cpp',
'../tests/GifTest.cpp',
'../tests/GpuBitmapCopyTest.cpp',
'../tests/GpuColorFilterTest.cpp',
'../tests/GpuDrawPathTest.cpp',
'../tests/GrBinHashKeyTest.cpp',
'../tests/GrContextFactoryTest.cpp',
'../tests/GrDrawTargetTest.cpp',
'../tests/GrMemoryPoolTest.cpp',
'../tests/GrRedBlackTreeTest.cpp',
'../tests/GrSurfaceTest.cpp',
'../tests/GrTBSearchTest.cpp',
'../tests/GradientTest.cpp',
'../tests/HashCacheTest.cpp',
'../tests/ImageCacheTest.cpp',
'../tests/ImageDecodingTest.cpp',
'../tests/ImageFilterTest.cpp',
'../tests/InfRectTest.cpp',
'../tests/JpegTest.cpp',
'../tests/LListTest.cpp',
'../tests/LayerDrawLooperTest.cpp',
'../tests/MD5Test.cpp',
'../tests/MallocPixelRefTest.cpp',
'../tests/MathTest.cpp',
'../tests/Matrix44Test.cpp',
'../tests/MatrixClipCollapseTest.cpp',
'../tests/MatrixTest.cpp',
'../tests/MemoryTest.cpp',
'../tests/MemsetTest.cpp',
'../tests/MessageBusTest.cpp',
'../tests/MetaDataTest.cpp',
'../tests/MipMapTest.cpp',
'../tests/OSPathTest.cpp',
'../tests/OnceTest.cpp',
'../tests/PDFPrimitivesTest.cpp',
'../tests/PackBitsTest.cpp',
'../tests/PaintTest.cpp',
'../tests/ParsePathTest.cpp',
'../tests/PathCoverageTest.cpp',
'../tests/PathMeasureTest.cpp',
'../tests/PathTest.cpp',
'../tests/PathUtilsTest.cpp',
'../tests/PictureTest.cpp',
'../tests/PictureUtilsTest.cpp',
'../tests/PixelRefTest.cpp',
'../tests/PointTest.cpp',
'../tests/PremulAlphaRoundTripTest.cpp',
'../tests/QuickRejectTest.cpp',
'../tests/RTreeTest.cpp',
'../tests/RandomTest.cpp',
'../tests/ReadPixelsTest.cpp',
'../tests/ReadWriteAlphaTest.cpp',
'../tests/Reader32Test.cpp',
'../tests/RefCntTest.cpp',
'../tests/RefDictTest.cpp',
'../tests/RegionTest.cpp',
'../tests/ResourceCacheTest.cpp',
'../tests/RoundRectTest.cpp',
'../tests/RuntimeConfigTest.cpp',
'../tests/SHA1Test.cpp',
'../tests/ScalarTest.cpp',
'../tests/SerializationTest.cpp',
'../tests/ShaderImageFilterTest.cpp',
'../tests/ShaderOpacityTest.cpp',
'../tests/SkBase64Test.cpp',
'../tests/SortTest.cpp',
'../tests/SrcOverTest.cpp',
'../tests/StreamTest.cpp',
'../tests/StringTest.cpp',
'../tests/StrokeTest.cpp',
'../tests/SurfaceTest.cpp',
'../tests/TLSTest.cpp',
'../tests/TSetTest.cpp',
'../tests/TestSize.cpp',
'../tests/TileGridTest.cpp',
'../tests/ToUnicode.cpp',
'../tests/TracingTest.cpp',
'../tests/Typeface.cpp',
'../tests/UnicodeTest.cpp',
'../tests/UnitTestTest.cpp',
'../tests/UtilsTest.cpp',
'../tests/WArrayTest.cpp',
'../tests/WritePixelsTest.cpp',
'../tests/Writer32Test.cpp',
'../tests/XfermodeTest.cpp',
'../tests/MatrixClipCollapseTest.cpp',
'../src/utils/debugger/SkDrawCommand.h',
'../src/utils/debugger/SkDrawCommand.cpp',
'../src/utils/debugger/SkDebugCanvas.h',
'../src/utils/debugger/SkDebugCanvas.cpp',
'../src/utils/debugger/SkObjectParser.h',
'../src/utils/debugger/SkObjectParser.cpp',
'../tests/PipeTest.cpp',
'../src/pipe/utils/SamplePipeControllers.cpp',
'../tests/TDStackNesterTest.cpp',
'../experimental/PdfViewer/src/SkTDStackNester.h',
],
}

View File

@ -7,6 +7,7 @@
*/
#include "Test.h"
#include "SkCommandLineFlags.h"
#include "SkError.h"
#include "SkString.h"
#include "SkTArray.h"
@ -19,6 +20,8 @@
class GrContext;
#endif
DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
using namespace skiatest;
Reporter::Reporter() : fTestCount(0) {
@ -114,23 +117,15 @@ void Test::run() {
}
///////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
GrContextFactory gGrContextFactory;
#endif
GrContextFactory* GpuTest::GetGrContextFactory() {
#if SK_SUPPORT_GPU
return &gGrContextFactory;
#else
return NULL;
#endif
SkString Test::GetTmpDir() {
const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
return SkString(tmpDir);
}
void GpuTest::DestroyContexts() {
#if SK_SUPPORT_GPU
gGrContextFactory.destroyContexts();
#endif
static const char* gResourcePath = NULL;
void Test::SetResourcePath(const char* resourcePath) { gResourcePath = resourcePath; }
SkString Test::GetResourcePath() {
return SkString(gResourcePath);
}

View File

@ -62,9 +62,11 @@ namespace skiatest {
static SkString GetTmpDir();
static void SetResourcePath(const char*);
static SkString GetResourcePath();
virtual bool isGPUTest() const { return false; }
virtual void setGrContextFactory(GrContextFactory* factory) {}
protected:
virtual void onGetName(SkString*) = 0;
@ -79,11 +81,15 @@ namespace skiatest {
class GpuTest : public Test{
public:
GpuTest() : Test() {}
static GrContextFactory* GetGrContextFactory();
static void DestroyContexts();
GpuTest() : Test(), fGrContextFactory(NULL) {}
virtual bool isGPUTest() const { return true; }
private:
virtual void setGrContextFactory(GrContextFactory* factory) {
fGrContextFactory = factory;
}
protected:
GrContextFactory* fGrContextFactory; // Unowned.
};
typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
@ -162,7 +168,7 @@ namespace skiatest {
name->set(#name); \
} \
virtual void onRun(Reporter* r) SK_OVERRIDE { \
name(r, GetGrContextFactory()); \
name(r, fGrContextFactory); \
} \
}; \
static TestRegistry gReg_##name##Class(name##Class::Factory); \

View File

@ -17,6 +17,7 @@
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "GrContextFactory.h"
#endif
using namespace skiatest;
@ -29,8 +30,6 @@ DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n"
"^ and $ requires an exact match\n" \
"If a test does not match any list entry,\n" \
"it is skipped unless some list entry starts with ~");
DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
DEFINE_string2(resourcePath, i, "resources", "directory for test resources.");
DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
@ -40,6 +39,7 @@ DEFINE_bool(cpu, true, "whether or not to run CPU tests.");
DEFINE_bool(gpu, true, "whether or not to run GPU tests.");
DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
"Run threadsafe tests on a threadpool with this many threads.");
DEFINE_string2(resourcePath, i, "resources", "directory for test resources.");
// need to explicitly declare this, or we get some weird infinite loop llist
template TestRegistry* TestRegistry::gHead;
@ -98,16 +98,6 @@ private:
const int fTotal;
};
SkString Test::GetTmpDir() {
const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
return SkString(tmpDir);
}
SkString Test::GetResourcePath() {
const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
return SkString(resourcePath);
}
// Deletes self when run.
class SkTestRunnable : public SkRunnable {
public:
@ -144,6 +134,7 @@ int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
SkCommandLineFlags::SetUsage("");
SkCommandLineFlags::Parse(argc, argv);
Test::SetResourcePath(FLAGS_resourcePath[0]);
#if SK_ENABLE_INST_COUNT
if (FLAGS_leaks) {
@ -199,7 +190,7 @@ int tool_main(int argc, char** argv) {
int skipCount = 0;
SkThreadPool threadpool(FLAGS_threads);
SkTArray<Test*> unsafeTests; // Always passes ownership to an SkTestRunnable
SkTArray<Test*> gpuTests; // Always passes ownership to an SkTestRunnable
DebugfReporter reporter(toRun);
for (int i = 0; i < total; i++) {
@ -207,15 +198,23 @@ int tool_main(int argc, char** argv) {
if (!should_run(test->getName(), test->isGPUTest())) {
++skipCount;
} else if (test->isGPUTest()) {
unsafeTests.push_back() = test.detach();
gpuTests.push_back() = test.detach();
} else {
threadpool.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
}
}
// Run the tests that aren't threadsafe.
for (int i = 0; i < unsafeTests.count(); i++) {
SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
#if SK_SUPPORT_GPU
// Give GPU tests a context factory if that makes sense on this machine.
GrContextFactory grContextFactory;
for (int i = 0; i < gpuTests.count(); i++) {
gpuTests[i]->setGrContextFactory(&grContextFactory);
}
#endif
// Run GPU tests on this thread.
for (int i = 0; i < gpuTests.count(); i++) {
SkNEW_ARGS(SkTestRunnable, (gpuTests[i], &failCount))->run();
}
// Block until threaded tests finish.
@ -226,7 +225,6 @@ int tool_main(int argc, char** argv) {
toRun, failCount, skipCount, reporter.countTests());
}
SkGraphics::Term();
GpuTest::DestroyContexts();
SkDebugf("\n");
return (failCount == 0) ? 0 : 1;