DM: Add --skps.

This does render_pictures, plus checks SkRecord optimizations.

Disable an SkRecord optimization that draws several bot SKPs wrong.  (To be investigated.)

BUG=skia:2378
R=reed@google.com, mtklein@google.com

Author: mtklein@chromium.org

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

git-svn-id: http://skia.googlecode.com/svn/trunk@14739 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-05-14 17:55:32 +00:00
parent ddb9331443
commit 90b5a2a653
16 changed files with 182 additions and 47 deletions

View File

@ -5,6 +5,7 @@
#include "SkCommandLineFlags.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkPicture.h"
#include "SkString.h"
#include "Test.h"
#include "gm.h"
@ -14,6 +15,7 @@
#include "DMGpuGMTask.h"
#include "DMGpuSupport.h"
#include "DMReporter.h"
#include "DMSKPTask.h"
#include "DMTask.h"
#include "DMTaskRunner.h"
#include "DMTestTask.h"
@ -43,6 +45,7 @@ DEFINE_string(match, "", "[~][^]substring[$] [...] of GM name to run.\n"
DEFINE_string(config, "565 8888 gpu nonrendering",
"Options: 565 8888 gpu nonrendering msaa4 msaa16 nvprmsaa4 nvprmsaa16 gpunull gpudebug angle mesa");
DEFINE_bool(leaks, false, "Print leaked instance-counted objects at exit?");
DEFINE_string(skps, "", "Directory to read skps from.");
DEFINE_bool(gms, true, "Run GMs?");
DEFINE_bool(benches, true, "Run benches? Does not run GMs-as-benches.");
@ -143,6 +146,35 @@ static void kick_off_tests(const SkTDArray<TestRegistry::Factory>& tests,
}
}
static void kick_off_skps(DM::Reporter* reporter, DM::TaskRunner* tasks) {
if (FLAGS_skps.isEmpty()) {
return;
}
SkOSFile::Iter it(FLAGS_skps[0], ".skp");
SkString filename;
while (it.next(&filename)) {
if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
continue;
}
const SkString path = SkOSPath::SkPathJoin(FLAGS_skps[0], filename.c_str());
SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path.c_str()));
if (stream.get() == NULL) {
SkDebugf("Could not read %s.\n", path.c_str());
exit(1);
}
SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream.get()));
if (pic.get() == NULL) {
SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
exit(1);
}
tasks->add(SkNEW_ARGS(DM::SKPTask, (reporter, tasks, pic.detach(), filename)));
}
}
static void report_failures(const DM::Reporter& reporter) {
SkTArray<SkString> failures;
reporter.getFailures(&failures);
@ -215,6 +247,7 @@ int tool_main(int argc, char** argv) {
kick_off_gms(gms, configs, *expectations, &reporter, &tasks);
kick_off_benches(benches, configs, &reporter, &tasks);
kick_off_tests(tests, &reporter, &tasks);
kick_off_skps(&reporter, &tasks);
tasks.wait();
SkDebugf("\n");

View File

@ -36,14 +36,14 @@ void CpuGMTask::draw() {
#define SPAWN(ChildTask, ...) this->spawnChild(SkNEW_ARGS(ChildTask, (*this, __VA_ARGS__)))
SPAWN(ExpectationsTask, fExpectations, bitmap);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, false, false);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, true, false);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, true, true);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, PipeTask::kInProcess_Mode);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, PipeTask::kCrossProcess_Mode);
SPAWN(PipeTask, fGMFactory(NULL), bitmap, PipeTask::kSharedAddress_Mode);
SPAWN(QuiltTask, fGMFactory(NULL), bitmap);
SPAWN(RecordTask, fGMFactory(NULL), bitmap, true);
SPAWN(RecordTask, fGMFactory(NULL), bitmap, false);
SPAWN(ReplayTask, fGMFactory(NULL), bitmap, false);
SPAWN(ReplayTask, fGMFactory(NULL), bitmap, true);
SPAWN(RecordTask, fGMFactory(NULL), bitmap, RecordTask::kOptimize_Mode);
SPAWN(RecordTask, fGMFactory(NULL), bitmap, RecordTask::kNoOptimize_Mode);
SPAWN(ReplayTask, fGMFactory(NULL), bitmap, ReplayTask::kNormal_Mode);
SPAWN(ReplayTask, fGMFactory(NULL), bitmap, ReplayTask::kRTree_Mode);
SPAWN(SerializeTask, fGMFactory(NULL), bitmap);
SPAWN(WriteTask, bitmap);

View File

@ -10,14 +10,13 @@ DEFINE_bool(pipe, true, "If true, check several pipe variants against the refere
namespace DM {
static uint32_t get_flags(bool crossProcess, bool sharedAddressSpace) {
SkASSERT(!(!crossProcess && sharedAddressSpace));
static uint32_t get_flags(PipeTask::Mode mode) {
uint32_t flags = 0;
if (crossProcess) {
if (mode != PipeTask::kInProcess_Mode) {
flags |= SkGPipeWriter::kCrossProcess_Flag;
if (sharedAddressSpace) {
flags |= SkGPipeWriter::kSharedAddressSpace_Flag;
}
}
if (mode == PipeTask::kSharedAddress_Mode) {
flags |= SkGPipeWriter::kSharedAddressSpace_Flag;
}
return flags;
}
@ -25,7 +24,7 @@ static uint32_t get_flags(bool crossProcess, bool sharedAddressSpace) {
static const char* get_name(const uint32_t flags) {
if (flags & SkGPipeWriter::kCrossProcess_Flag &&
flags & SkGPipeWriter::kSharedAddressSpace_Flag) {
return "cross_process_shared_address_space_pipe";
return "shared_address_space_pipe";
} else if (flags & SkGPipeWriter::kCrossProcess_Flag) {
return "cross_process_pipe";
} else {
@ -36,10 +35,9 @@ static const char* get_name(const uint32_t flags) {
PipeTask::PipeTask(const Task& parent,
skiagm::GM* gm,
SkBitmap reference,
bool crossProcess,
bool sharedAddressSpace)
Mode mode)
: CpuTask(parent)
, fFlags(get_flags(crossProcess, sharedAddressSpace))
, fFlags(get_flags(mode))
, fName(UnderJoin(parent.name().c_str(), get_name(fFlags)))
, fGM(gm)
, fReference(reference)

View File

@ -14,11 +14,16 @@ namespace DM {
class PipeTask : public CpuTask {
public:
enum Mode {
kInProcess_Mode,
kCrossProcess_Mode,
kSharedAddress_Mode,
};
PipeTask(const Task& parent, // PipeTask must be a child task. Pass its parent here.
skiagm::GM*, // GM to run through a pipe. Takes ownership.
SkBitmap reference, // Bitmap to compare pipe results to.
bool crossProcess, // Should we set up a cross process pipe?
bool sharedAddressSpace); // If cross process, should it assume shared address space?
Mode);
virtual void draw() SK_OVERRIDE;
virtual bool shouldSkip() const SK_OVERRIDE;

View File

@ -11,21 +11,35 @@ DEFINE_bool(skr, true, "If true, run SKR tests.");
namespace DM {
RecordTask::RecordTask(const Task& parent, skiagm::GM* gm, SkBitmap reference, bool optimize)
RecordTask::RecordTask(const Task& parent, skiagm::GM* gm, SkBitmap reference, Mode mode)
: CpuTask(parent)
, fName(UnderJoin(parent.name().c_str(), optimize ? "skr" : "skr-noopt"))
, fOptimize(mode == kOptimize_Mode)
, fName(UnderJoin(parent.name().c_str(), fOptimize ? "skr" : "skr-noopt"))
, fGM(gm)
, fReference(reference)
, fOptimize(optimize)
{}
RecordTask::RecordTask(const Task& parent, SkPicture* pic, SkBitmap reference, Mode mode)
: CpuTask(parent)
, fOptimize(mode == kOptimize_Mode)
, fName(UnderJoin(parent.name().c_str(), fOptimize ? "skr" : "skr-noopt"))
, fPicture(SkRef(pic))
, fReference(reference)
{}
void RecordTask::draw() {
// Record the GM into an SkRecord.
// Record into an SkRecord.
SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record,
fReference.width(), fReference.height());
recorder.concat(fGM->getInitialTransform());
fGM->draw(&recorder);
if (fGM.get()) {
recorder.concat(fGM->getInitialTransform());
fGM->draw(&recorder);
} else {
fPicture->draw(&recorder);
}
if (fOptimize) {
SkRecordOptimize(&record);
@ -33,7 +47,11 @@ void RecordTask::draw() {
// Draw the SkRecord back into a bitmap.
SkBitmap bitmap;
SetupBitmap(fReference.colorType(), fGM.get(), &bitmap);
if (fGM.get()) {
SetupBitmap(fReference.colorType(), fGM.get(), &bitmap);
} else {
SetupBitmap(fReference.colorType(), *fPicture, &bitmap);
}
SkCanvas target(bitmap);
SkRecordDraw(record, &target);

View File

@ -3,28 +3,35 @@
#include "DMTask.h"
#include "SkBitmap.h"
#include "SkPicture.h"
#include "SkString.h"
#include "SkTemplates.h"
#include "gm.h"
// Records a GM through an SkRecord, draws it, and compares against the reference bitmap.
// Records a GM or SKP through an SkRecord, draws it, and compares against the reference bitmap.
namespace DM {
class RecordTask : public CpuTask {
public:
RecordTask(const Task& parent, skiagm::GM*, SkBitmap reference, bool optimize);
enum Mode {
kNoOptimize_Mode,
kOptimize_Mode,
};
RecordTask(const Task& parent, skiagm::GM*, SkBitmap reference, Mode);
RecordTask(const Task& parent, SkPicture*, SkBitmap reference, Mode);
virtual void draw() SK_OVERRIDE;
virtual bool shouldSkip() const SK_OVERRIDE;
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
bool fOptimize;
const SkString fName;
SkAutoTUnref<SkPicture> fPicture;
SkAutoTDelete<skiagm::GM> fGM;
const SkBitmap fReference;
bool fOptimize;
};
} // namespace DM

View File

@ -14,12 +14,12 @@ namespace DM {
ReplayTask::ReplayTask(const Task& parent,
skiagm::GM* gm,
SkBitmap reference,
bool useRTree)
Mode mode)
: CpuTask(parent)
, fName(UnderJoin(parent.name().c_str(), useRTree ? "rtree" : "replay"))
, fUseRTree(mode == kRTree_Mode)
, fName(UnderJoin(parent.name().c_str(), fUseRTree ? "rtree" : "replay"))
, fGM(gm)
, fReference(reference)
, fUseRTree(useRTree)
{}
void ReplayTask::draw() {

View File

@ -14,20 +14,24 @@ namespace DM {
class ReplayTask : public CpuTask {
public:
enum Mode {
kNormal_Mode,
kRTree_Mode,
};
ReplayTask(const Task& parent, // ReplayTask must be a child task. Pass its parent here.
skiagm::GM*, // GM to run through a picture. Takes ownership.
SkBitmap reference, // Bitmap to compare picture replay results to.
bool useRTree); // Record with an RTree?
Mode);
virtual void draw() SK_OVERRIDE;
virtual bool shouldSkip() const SK_OVERRIDE;
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
const bool fUseRTree;
const SkString fName;
SkAutoTDelete<skiagm::GM> fGM;
const SkBitmap fReference;
const bool fUseRTree;
};
} // namespace DM

23
dm/DMSKPTask.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "DMRecordTask.h"
#include "DMSKPTask.h"
#include "DMUtil.h"
#include "DMWriteTask.h"
namespace DM {
SKPTask::SKPTask(Reporter* r, TaskRunner* tr, SkPicture* pic, SkString name)
: CpuTask(r, tr), fPicture(SkRef(pic)), fName(name) {}
void SKPTask::draw() {
SkBitmap bitmap;
SetupBitmap(kN32_SkColorType, *fPicture, &bitmap);
DrawPicture(fPicture, &bitmap);
this->spawnChild(SkNEW_ARGS(RecordTask,
(*this, fPicture, bitmap, RecordTask::kNoOptimize_Mode)));
this->spawnChild(SkNEW_ARGS(RecordTask,
(*this, fPicture, bitmap, RecordTask::kOptimize_Mode)));
this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap, WriteTask::kVerbatim_Mode)));
}
} // namespace DM

30
dm/DMSKPTask.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef DMSKPTask_DEFINED
#define DMSKPTask_DEFINED
#include "DMReporter.h"
#include "DMTask.h"
#include "DMTaskRunner.h"
#include "SkPicture.h"
#include "SkString.h"
#include "SkTemplates.h"
// Draws an SKP to a raster canvas, then compares it with some other modes.
namespace DM {
class SKPTask : public CpuTask {
public:
SKPTask(Reporter*, TaskRunner*, SkPicture*, SkString name);
virtual void draw() SK_OVERRIDE;
virtual bool shouldSkip() const SK_OVERRIDE { return false; }
virtual SkString name() const SK_OVERRIDE { return fName; }
private:
SkAutoTUnref<SkPicture> fPicture;
const SkString fName;
};
} // namespace DM
#endif // DMSKPTask_DEFINED

View File

@ -26,14 +26,18 @@ static void setup_bitmap(SkColorType ct, int width, int height, SkBitmap* bitmap
bitmap->eraseColor(0x00000000);
}
void SetupBitmap(const SkColorType ct, skiagm::GM* gm, SkBitmap* bitmap) {
void SetupBitmap(SkColorType ct, skiagm::GM* gm, SkBitmap* bitmap) {
setup_bitmap(ct, gm->getISize().width(), gm->getISize().height(), bitmap);
}
void SetupBitmap(const SkColorType ct, SkBenchmark* bench, SkBitmap* bitmap) {
void SetupBitmap(SkColorType ct, SkBenchmark* bench, SkBitmap* bitmap) {
setup_bitmap(ct, bench->getSize().x(), bench->getSize().y(), bitmap);
}
void SetupBitmap(SkColorType ct, const SkPicture& pic, SkBitmap* bitmap) {
setup_bitmap(ct, pic.width(), pic.height(), bitmap);
}
void DrawPicture(SkPicture* picture, SkBitmap* bitmap) {
SkASSERT(picture != NULL);
SkASSERT(bitmap != NULL);

View File

@ -20,10 +20,11 @@ SkPicture* RecordPicture(skiagm::GM* gm,
uint32_t recordFlags = 0,
SkBBHFactory* factory = NULL);
// Prepare bitmap to have gm or bench draw into it with this config.
// Prepare bitmap to have gm, bench or picture draw into it with this config.
// TODO(mtklein): make SkBenchmark::getSize()/GM::getISize() const.
void SetupBitmap(const SkColorType, skiagm::GM* gm, SkBitmap* bitmap);
void SetupBitmap(const SkColorType, SkBenchmark* bench, SkBitmap* bitmap);
void SetupBitmap(SkColorType, skiagm::GM* gm, SkBitmap* bitmap);
void SetupBitmap(SkColorType, SkBenchmark* bench, SkBitmap* bitmap);
void SetupBitmap(SkColorType, const SkPicture& picture, SkBitmap* bitmap);
// Draw picture to bitmap.
void DrawPicture(SkPicture* picture, SkBitmap* bitmap);

View File

@ -26,11 +26,16 @@ static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) {
return consumed;
}
WriteTask::WriteTask(const Task& parent, SkBitmap bitmap) : CpuTask(parent), fBitmap(bitmap) {
const int suffixes = parent.depth() + 1;
const SkString& name = parent.name();
const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffixes);
fGmName.set(name.c_str(), name.size()-totalSuffixLength);
WriteTask::WriteTask(const Task& parent, SkBitmap bitmap, Mode mode)
: CpuTask(parent), fBitmap(bitmap) {
if (mode == kVerbatim_Mode) {
fGmName.set(parent.name());
} else {
const int suffixes = parent.depth() + 1;
const SkString& name = parent.name();
const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffixes);
fGmName.set(name.c_str(), name.size()-totalSuffixLength);
}
}
void WriteTask::makeDirOrFail(SkString dir) {

View File

@ -15,8 +15,13 @@ namespace DM {
class WriteTask : public CpuTask {
public:
WriteTask(const Task& parent, // WriteTask must be a child Task. Pass its parent here.
SkBitmap bitmap); // Bitmap to write.
enum Mode {
kParseName_Mode, // Parse the parent's name into directories by underscores.
kVerbatim_Mode, // Don't parse the name at all.
};
WriteTask(const Task& parent, // WriteTask must be a child Task. Pass its parent here.
SkBitmap bitmap, // Bitmap to write.
Mode = kParseName_Mode);
virtual void draw() SK_OVERRIDE;
virtual bool shouldSkip() const SK_OVERRIDE;

View File

@ -38,6 +38,7 @@
'../dm/DMReplayTask.cpp',
'../dm/DMReporter.cpp',
'../dm/DMSerializeTask.cpp',
'../dm/DMSKPTask.cpp',
'../dm/DMTask.cpp',
'../dm/DMTaskRunner.cpp',
'../dm/DMTestTask.cpp',

View File

@ -17,7 +17,8 @@ void SkRecordOptimize(SkRecord* record) {
// TODO(mtklein): fuse independent optimizations to reduce number of passes?
SkRecordNoopCulls(record);
SkRecordNoopSaveRestores(record);
SkRecordNoopSaveLayerDrawRestores(record);
// TODO(mtklein): figure out why we draw differently and reenable
//SkRecordNoopSaveLayerDrawRestores(record);
SkRecordAnnotateCullingPairs(record);
SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before BoundDrawPosTextH.