Remove SkRecorder's kWriteOnly mode.

I'm soon going to have SkRecorder start calling getTotalMatrix(), which
would be broken in write-only mode.  That change is big and nebulous,
but it's clear kWriteOnly needs to go, so we might as well kill it now.

My notes in bench_playback about kWriteOnly mode being important were
probably overly cautious.  I now think this is a fair enough comparison
even re-recording into a read-write canvas.

BUG=skia:2378
R=fmalita@chromium.org, mtklein@google.com

Author: mtklein@chromium.org

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

git-svn-id: http://skia.googlecode.com/svn/trunk@14963 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-05-29 16:52:40 +00:00
parent cac02e52cd
commit a095041f51
10 changed files with 55 additions and 69 deletions

View File

@ -30,8 +30,7 @@ RecordTask::RecordTask(const Task& parent, SkPicture* pic, SkBitmap reference, M
void RecordTask::draw() { void RecordTask::draw() {
// Record into an SkRecord. // Record into an SkRecord.
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, SkRecorder recorder(&record, fReference.width(), fReference.height());
fReference.width(), fReference.height());
if (fGM.get()) { if (fGM.get()) {
recorder.concat(fGM->getInitialTransform()); recorder.concat(fGM->getInitialTransform());

View File

@ -9,8 +9,8 @@
#include "SkPicture.h" #include "SkPicture.h"
// SkCanvas will fail in mysterious ways if it doesn't know the real width and height. // SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
SkRecorder::SkRecorder(SkRecorder::Mode mode, SkRecord* record, int width, int height) SkRecorder::SkRecorder(SkRecord* record, int width, int height)
: SkCanvas(width, height), fMode(mode), fRecord(record) {} : SkCanvas(width, height), fRecord(record) {}
void SkRecorder::forgetRecord() { void SkRecorder::forgetRecord() {
fRecord = NULL; fRecord = NULL;
@ -20,8 +20,8 @@ void SkRecorder::forgetRecord() {
#define APPEND(T, ...) \ #define APPEND(T, ...) \
SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__)) SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
// For methods which must call back into SkCanvas in kReadWrite_Mode. // For methods which must call back into SkCanvas.
#define INHERITED(method, ...) if (fMode == kReadWrite_Mode) this->SkCanvas::method(__VA_ARGS__) #define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
// The structs we're creating all copy their constructor arguments. Given the way the SkRecords // The structs we're creating all copy their constructor arguments. Given the way the SkRecords
// framework works, sometimes they happen to technically be copied twice, which is fine and elided // framework works, sometimes they happen to technically be copied twice, which is fine and elided

View File

@ -16,17 +16,8 @@
class SkRecorder : public SkCanvas { class SkRecorder : public SkCanvas {
public: public:
// SkRecorder can work in two modes:
// write-only: only a core subset of SkCanvas operations (save/restore, clip, transform, draw)
// are supported, and all of the readback methods on SkCanvas will probably fail or lie.
//
// read-write: all methods should behave with similar semantics to SkCanvas.
//
// Write-only averages 10-20% faster, but you can't sensibly inspect the canvas while recording.
enum Mode { kWriteOnly_Mode, kReadWrite_Mode };
// Does not take ownership of the SkRecord. // Does not take ownership of the SkRecord.
SkRecorder(Mode mode, SkRecord*, int width, int height); SkRecorder(SkRecord*, int width, int height);
// Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail. // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
void forgetRecord(); void forgetRecord();
@ -114,7 +105,6 @@ private:
template <typename T> template <typename T>
T* copy(const T[], unsigned count); T* copy(const T[], unsigned count);
const Mode fMode;
SkRecord* fRecord; SkRecord* fRecord;
}; };

View File

@ -25,7 +25,7 @@ void SkPlayback::draw(SkCanvas* canvas) const {
SkRecording::SkRecording(int width, int height) SkRecording::SkRecording(int width, int height)
: fRecord(SkNEW(SkRecord)) : fRecord(SkNEW(SkRecord))
, fRecorder(SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, fRecord.get(), width, height))) , fRecorder(SkNEW_ARGS(SkRecorder, (fRecord.get(), width, height)))
{} {}
SkPlayback* SkRecording::releasePlayback() { SkPlayback* SkRecording::releasePlayback() {

View File

@ -29,14 +29,14 @@ static void draw_pos_text_h(SkCanvas* canvas, const char* text, SkScalar y) {
// Rerecord into another SkRecord using full SkCanvas semantics, // Rerecord into another SkRecord using full SkCanvas semantics,
// tracking clips and allowing SkRecordDraw's quickReject() calls to work. // tracking clips and allowing SkRecordDraw's quickReject() calls to work.
static void record_clipped(const SkRecord& record, SkRect clip, SkRecord* clipped) { static void record_clipped(const SkRecord& record, SkRect clip, SkRecord* clipped) {
SkRecorder recorder(SkRecorder::kReadWrite_Mode, clipped, W, H); SkRecorder recorder(clipped, W, H);
recorder.clipRect(clip); recorder.clipRect(clip);
SkRecordDraw(record, &recorder); SkRecordDraw(record, &recorder);
} }
DEF_TEST(RecordDraw_PosTextHQuickReject, r) { DEF_TEST(RecordDraw_PosTextHQuickReject, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
draw_pos_text_h(&recorder, "This will draw.", 20); draw_pos_text_h(&recorder, "This will draw.", 20);
draw_pos_text_h(&recorder, "This won't.", 5000); draw_pos_text_h(&recorder, "This won't.", 5000);
@ -53,7 +53,7 @@ DEF_TEST(RecordDraw_PosTextHQuickReject, r) {
DEF_TEST(RecordDraw_Culling, r) { DEF_TEST(RecordDraw_Culling, r) {
// Record these 7 drawing commands verbatim. // Record these 7 drawing commands verbatim.
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
recorder.pushCull(SkRect::MakeWH(100, 100)); recorder.pushCull(SkRect::MakeWH(100, 100));
recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint()); recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint());
@ -78,14 +78,14 @@ DEF_TEST(RecordDraw_Culling, r) {
DEF_TEST(RecordDraw_SetMatrixClobber, r) { DEF_TEST(RecordDraw_SetMatrixClobber, r) {
// Set up an SkRecord that just scales by 2x,3x. // Set up an SkRecord that just scales by 2x,3x.
SkRecord scaleRecord; SkRecord scaleRecord;
SkRecorder scaleCanvas(SkRecorder::kReadWrite_Mode, &scaleRecord, W, H); SkRecorder scaleCanvas(&scaleRecord, W, H);
SkMatrix scale; SkMatrix scale;
scale.setScale(2, 3); scale.setScale(2, 3);
scaleCanvas.setMatrix(scale); scaleCanvas.setMatrix(scale);
// Set up an SkRecord with an initial +20, +20 translate. // Set up an SkRecord with an initial +20, +20 translate.
SkRecord translateRecord; SkRecord translateRecord;
SkRecorder translateCanvas(SkRecorder::kReadWrite_Mode, &translateRecord, W, H); SkRecorder translateCanvas(&translateRecord, W, H);
SkMatrix translate; SkMatrix translate;
translate.setTranslate(20, 20); translate.setTranslate(20, 20);
translateCanvas.setMatrix(translate); translateCanvas.setMatrix(translate);

View File

@ -18,7 +18,7 @@ static const int W = 1920, H = 1080;
DEF_TEST(RecordOpts_Culling, r) { DEF_TEST(RecordOpts_Culling, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
recorder.drawRect(SkRect::MakeWH(1000, 10000), SkPaint()); recorder.drawRect(SkRect::MakeWH(1000, 10000), SkPaint());
@ -38,7 +38,7 @@ DEF_TEST(RecordOpts_Culling, r) {
DEF_TEST(RecordOpts_NoopCulls, r) { DEF_TEST(RecordOpts_NoopCulls, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
// All should be nooped. // All should be nooped.
recorder.pushCull(SkRect::MakeWH(200, 200)); recorder.pushCull(SkRect::MakeWH(200, 200));
@ -77,7 +77,7 @@ static void draw_pos_text(SkCanvas* canvas, const char* text, bool constantY) {
DEF_TEST(RecordOpts_StrengthReduction, r) { DEF_TEST(RecordOpts_StrengthReduction, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
// We can convert a drawPosText into a drawPosTextH when all the Ys are the same. // We can convert a drawPosText into a drawPosTextH when all the Ys are the same.
draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true); draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true);
@ -91,7 +91,7 @@ DEF_TEST(RecordOpts_StrengthReduction, r) {
DEF_TEST(RecordOpts_TextBounding, r) { DEF_TEST(RecordOpts_TextBounding, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
// First, get a drawPosTextH. Here's a handy way. Its text size will be the default (12). // First, get a drawPosTextH. Here's a handy way. Its text size will be the default (12).
draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true); draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true);
@ -114,7 +114,7 @@ DEF_TEST(RecordOpts_TextBounding, r) {
DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) { DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
// The save and restore are pointless if there's only draw commands in the middle. // The save and restore are pointless if there's only draw commands in the middle.
recorder.save(); recorder.save();
@ -136,7 +136,7 @@ DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) {
DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) { DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
recorder.save(); recorder.save();
recorder.clipRect(SkRect::MakeWH(200, 200)); recorder.clipRect(SkRect::MakeWH(200, 200));
@ -150,7 +150,7 @@ DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
DEF_TEST(RecordOpts_NoopSaveRestores, r) { DEF_TEST(RecordOpts_NoopSaveRestores, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
// The second pass will clean up this pair after the first pass noops all the innards. // The second pass will clean up this pair after the first pass noops all the innards.
recorder.save(); recorder.save();
@ -187,7 +187,7 @@ static void assert_savelayer_restore(skiatest::Reporter* r,
DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) { DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, W, H); SkRecorder recorder(&record, W, H);
SkRect bounds = SkRect::MakeWH(100, 200); SkRect bounds = SkRect::MakeWH(100, 200);
SkRect draw = SkRect::MakeWH(50, 60); SkRect draw = SkRect::MakeWH(50, 60);

View File

@ -17,7 +17,7 @@ DEF_TEST(RecordPattern_Simple, r) {
SkRecord record; SkRecord record;
REPORTER_ASSERT(r, !pattern.match(&record, 0)); REPORTER_ASSERT(r, !pattern.match(&record, 0));
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
// Build up a save-clip-restore block. The pattern will match only it's complete. // Build up a save-clip-restore block. The pattern will match only it's complete.
recorder.save(); recorder.save();
@ -37,7 +37,7 @@ DEF_TEST(RecordPattern_StartingIndex, r) {
SaveClipRectRestore pattern; SaveClipRectRestore pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
// There will be two save-clipRect-restore blocks [0,3) and [3,6). // There will be two save-clipRect-restore blocks [0,3) and [3,6).
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
@ -60,7 +60,7 @@ DEF_TEST(RecordPattern_DontMatchSubsequences, r) {
SaveClipRectRestore pattern; SaveClipRectRestore pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
recorder.save(); recorder.save();
recorder.clipRect(SkRect::MakeWH(300, 200)); recorder.clipRect(SkRect::MakeWH(300, 200));
@ -74,7 +74,7 @@ DEF_TEST(RecordPattern_Star, r) {
Pattern3<Is<Save>, Star<Is<ClipRect> >, Is<Restore> > pattern; Pattern3<Is<Save>, Star<Is<ClipRect> >, Is<Restore> > pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
recorder.save(); recorder.save();
recorder.restore(); recorder.restore();
@ -96,7 +96,7 @@ DEF_TEST(RecordPattern_IsDraw, r) {
Pattern3<Is<Save>, IsDraw, Is<Restore> > pattern; Pattern3<Is<Save>, IsDraw, Is<Restore> > pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
recorder.save(); recorder.save();
recorder.clipRect(SkRect::MakeWH(300, 200)); recorder.clipRect(SkRect::MakeWH(300, 200));
@ -135,7 +135,7 @@ DEF_TEST(RecordPattern_Complex, r) {
Is<Restore> > pattern; Is<Restore> > pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
recorder.save(); recorder.save();
recorder.restore(); recorder.restore();
@ -192,7 +192,7 @@ DEF_TEST(RecordPattern_SaveLayerIsNotADraw, r) {
Pattern1<IsDraw> pattern; Pattern1<IsDraw> pattern;
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1200); SkRecorder recorder(&record, 1920, 1200);
recorder.saveLayer(NULL, NULL); recorder.saveLayer(NULL, NULL);
REPORTER_ASSERT(r, !pattern.match(&record, 0)); REPORTER_ASSERT(r, !pattern.match(&record, 0));

View File

@ -40,7 +40,7 @@ private:
DEF_TEST(Recorder, r) { DEF_TEST(Recorder, r) {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1080); SkRecorder recorder(&record, 1920, 1080);
recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint()); recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint());
@ -62,7 +62,7 @@ DEF_TEST(Recorder_RefLeaking, r) {
REPORTER_ASSERT(r, paint.getShader()->unique()); REPORTER_ASSERT(r, paint.getShader()->unique());
{ {
SkRecord record; SkRecord record;
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, 1920, 1080); SkRecorder recorder(&record, 1920, 1080);
recorder.saveLayer(&bounds, &paint); recorder.saveLayer(&bounds, &paint);
REPORTER_ASSERT(r, !paint.getShader()->unique()); REPORTER_ASSERT(r, !paint.getShader()->unique());
} }

View File

@ -12,9 +12,7 @@
#include "SkOSFile.h" #include "SkOSFile.h"
#include "SkPicture.h" #include "SkPicture.h"
#include "SkPictureRecorder.h" #include "SkPictureRecorder.h"
#include "SkRecordDraw.h" #include "SkRecording.h"
#include "SkRecordOpts.h"
#include "SkRecorder.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkString.h" #include "SkString.h"
@ -33,14 +31,28 @@ static double scale_time(double ms) {
return ms; return ms;
} }
static void bench(SkPMColor* scratch, SkPicture& src, const char* name) { static SkPicture* rerecord_with_tilegrid(SkPicture& src) {
// We don't use the public SkRecording interface here because we need kWriteOnly_Mode. SkTileGridFactory::TileGridInfo info;
// (We don't want SkPicturePlayback to be able to optimize playing into our SkRecord.) info.fTileInterval.set(FLAGS_tile, FLAGS_tile);
SkRecord record; info.fMargin.setEmpty();
SkRecorder recorder(SkRecorder::kWriteOnly_Mode, &record, src.width(), src.height()); info.fOffset.setZero();
src.draw(&recorder); SkTileGridFactory factory(info);
SkRecordOptimize(&record); SkPictureRecorder recorder;
src.draw(recorder.beginRecording(src.width(), src.height(), &factory,
SkPicture::kUsePathBoundsForClip_RecordingFlag));
return recorder.endRecording();
}
static EXPERIMENTAL::SkPlayback* rerecord_with_skr(SkPicture& src) {
EXPERIMENTAL::SkRecording recording(src.width(), src.height());
src.draw(recording.canvas());
return recording.releasePlayback();
}
static void bench(SkPMColor* scratch, SkPicture& src, const char* name) {
SkAutoTUnref<SkPicture> picture(rerecord_with_tilegrid(src));
SkAutoTDelete<EXPERIMENTAL::SkPlayback> record(rerecord_with_skr(src));
SkAutoTDelete<SkCanvas> canvas(SkCanvas::NewRasterDirectN32(src.width(), SkAutoTDelete<SkCanvas> canvas(SkCanvas::NewRasterDirectN32(src.width(),
src.height(), src.height(),
@ -52,9 +64,9 @@ static void bench(SkPMColor* scratch, SkPicture& src, const char* name) {
timer.start(); timer.start();
for (int i = 0; i < FLAGS_loops; i++) { for (int i = 0; i < FLAGS_loops; i++) {
if (FLAGS_skr) { if (FLAGS_skr) {
SkRecordDraw(record, canvas.get()); record->draw(canvas.get());
} else { } else {
src.draw(canvas.get()); picture->draw(canvas.get());
} }
} }
timer.end(); timer.end();
@ -102,21 +114,7 @@ int tool_main(int argc, char** argv) {
continue; continue;
} }
// Rerecord into a picture using a tile grid. bench(scratch.get(), *src, filename.c_str());
SkTileGridFactory::TileGridInfo info;
info.fTileInterval.set(FLAGS_tile, FLAGS_tile);
info.fMargin.setEmpty();
info.fOffset.setZero();
SkTileGridFactory factory(info);
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(src->width(), src->height(),
&factory,
SkPicture::kUsePathBoundsForClip_RecordingFlag);
src->draw(canvas);
SkAutoTUnref<SkPicture> replay(recorder.endRecording());
bench(scratch.get(), *replay, filename.c_str());
} }
return failed ? 1 : 0; return failed ? 1 : 0;
} }

View File

@ -60,10 +60,9 @@ int tool_main(int argc, char** argv) {
const int w = src->width(), h = src->height(); const int w = src->width(), h = src->height();
SkRecord record; SkRecord record;
SkRecorder canvas(SkRecorder::kWriteOnly_Mode, &record, w, h); SkRecorder canvas(&record, w, h);
src->draw(&canvas); src->draw(&canvas);
if (FLAGS_optimize) { if (FLAGS_optimize) {
SkRecordOptimize(&record); SkRecordOptimize(&record);
} }