Experiment: add flag for finish-recording to return null

BUG=skia:5495
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2106843004

Review-Url: https://codereview.chromium.org/2106843004
This commit is contained in:
reed 2016-07-06 09:29:16 -07:00 committed by Commit bot
parent 7ec9241330
commit 41c27e15ec
5 changed files with 96 additions and 11 deletions

View File

@ -33,11 +33,15 @@ public:
enum RecordFlags {
// This flag indicates that, if some BHH is being computed, saveLayer
// information should also be extracted at the same time.
kComputeSaveLayerInfo_RecordFlag = 0x01,
kComputeSaveLayerInfo_RecordFlag = 1 << 0,
// If you call drawPicture() or drawDrawable() on the recording canvas, this flag forces
// that object to playback its contents immediately rather than reffing the object.
kPlaybackDrawPicture_RecordFlag = 0x02,
kPlaybackDrawPicture_RecordFlag = 1 << 1,
};
enum FinishFlags {
kReturnNullForEmpty_FinishFlag = 1 << 0, // no draw-ops will return nullptr
};
/** Returns the canvas that records the drawing commands.
@ -72,7 +76,7 @@ public:
* reflect their current state, but will not contain a live reference to the drawables
* themselves.
*/
sk_sp<SkPicture> finishRecordingAsPicture();
sk_sp<SkPicture> finishRecordingAsPicture(uint32_t endFlags = 0);
/**
* Signal that the caller is done recording, and update the cull rect to use for bounding
@ -83,7 +87,8 @@ public:
* and subsequent culling operations.
* @return the picture containing the recorded content.
*/
sk_sp<SkPicture> finishRecordingAsPictureWithCull(const SkRect& cullRect);
sk_sp<SkPicture> finishRecordingAsPictureWithCull(const SkRect& cullRect,
uint32_t endFlags = 0);
/**
* Signal that the caller is done recording. This invalidates the canvas returned by
@ -95,7 +100,7 @@ public:
* and therefore this drawable will reflect the current state of those nested drawables anytime
* it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()).
*/
sk_sp<SkDrawable> finishRecordingAsDrawable();
sk_sp<SkDrawable> finishRecordingAsDrawable(uint32_t endFlags = 0);
#ifdef SK_SUPPORT_LEGACY_PICTURE_PTR
SkPicture* SK_WARN_UNUSED_RESULT endRecordingAsPicture() {

View File

@ -51,17 +51,26 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
return fActivelyRecording ? fRecorder.get() : nullptr;
}
sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture() {
sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
fActivelyRecording = false;
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
if (fRecord->count() == 0) {
if (finishFlags & kReturnNullForEmpty_FinishFlag) {
return nullptr;
}
return fMiniRecorder.detachAsPicture(fCullRect);
}
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);
if (fRecord->count() == 0) {
if (finishFlags & kReturnNullForEmpty_FinishFlag) {
return nullptr;
}
}
SkAutoTUnref<SkLayerInfo> saveLayerData;
if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) {
@ -97,9 +106,10 @@ sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture() {
saveLayerData.release(), subPictureBytes);
}
sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect) {
sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
uint32_t finishFlags) {
fCullRect = cullRect;
return this->finishRecordingAsPicture();
return this->finishRecordingAsPicture(finishFlags);
}
@ -118,14 +128,19 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
}
sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable() {
sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
fActivelyRecording = false;
fRecorder->flushMiniRecorder();
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);
if (fRecord->count() == 0) {
if (finishFlags & kReturnNullForEmpty_FinishFlag) {
return nullptr;
}
}
if (fBBH.get()) {
SkAutoTMalloc<SkRect> bounds(fRecord->count());
SkRecordFillBounds(fCullRect, *fRecord, bounds);

View File

@ -276,7 +276,7 @@ void SkRecordOptimize(SkRecord* record) {
// out junk for other optimization passes. Right now, nothing needs it,
// and the bounding box hierarchy will do the work of skipping no-op
// Save-NoDraw-Restore sequences better than we can here.
//SkRecordNoopSaveRestores(record);
SkRecordNoopSaveRestores(record);
SkRecordNoopSaveLayerDrawRestores(record);
SkRecordMergeSvgOpacityAndFilterLayers(record);

View File

@ -1447,3 +1447,63 @@ DEF_TEST(PictureGpuAnalyzer, r) {
}
#endif // SK_SUPPORT_GPU
///////////////////////////////////////////////////////////////////////////////////////////////////
static void empty_ops(SkCanvas* canvas) {
}
static void clip_ops(SkCanvas* canvas) {
canvas->save();
canvas->clipRect(SkRect::MakeWH(20, 20));
canvas->restore();
}
static void matrix_ops(SkCanvas* canvas) {
canvas->save();
canvas->scale(2, 3);
canvas->restore();
}
static void matrixclip_ops(SkCanvas* canvas) {
canvas->save();
canvas->scale(2, 3);
canvas->clipRect(SkRect::MakeWH(20, 20));
canvas->restore();
}
typedef void (*CanvasProc)(SkCanvas*);
// Test the kReturnNullForEmpty_FinishFlag option when recording
//
DEF_TEST(Picture_RecordEmpty, r) {
const SkRect cull = SkRect::MakeWH(100, 100);
CanvasProc procs[] { empty_ops, clip_ops, matrix_ops, matrixclip_ops };
for (auto proc : procs) {
{
SkPictureRecorder rec;
proc(rec.beginRecording(cull));
sk_sp<SkPicture> pic = rec.finishRecordingAsPicture(0);
REPORTER_ASSERT(r, pic.get());
REPORTER_ASSERT(r, pic->approximateOpCount() == 0);
}
{
SkPictureRecorder rec;
proc(rec.beginRecording(cull));
sk_sp<SkPicture> pic = rec.finishRecordingAsPicture(
SkPictureRecorder::kReturnNullForEmpty_FinishFlag);
REPORTER_ASSERT(r, !pic.get());
}
{
SkPictureRecorder rec;
proc(rec.beginRecording(cull));
sk_sp<SkDrawable> dr = rec.finishRecordingAsDrawable(0);
REPORTER_ASSERT(r, dr.get());
}
{
SkPictureRecorder rec;
proc(rec.beginRecording(cull));
sk_sp<SkDrawable> dr = rec.finishRecordingAsDrawable(
SkPictureRecorder::kReturnNullForEmpty_FinishFlag);
REPORTER_ASSERT(r, !dr.get());
}
}
}

View File

@ -78,6 +78,11 @@ DEF_TEST(RecordReplaceDraw_Unbalanced, r) {
canvas->save();
canvas->scale(2, 2);
pic = recorder.finishRecordingAsPicture();
// we may have optimized everything away. If so, just return
if (pic->approximateOpCount() == 0) {
return;
}
}
SkRecord rerecord;