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:
parent
7ec9241330
commit
41c27e15ec
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user