From 1bb5fecbea494d77d7d5633522be1cdc76d043ae Mon Sep 17 00:00:00 2001 From: mtklein Date: Mon, 1 Aug 2016 13:17:47 -0700 Subject: [PATCH] Sketch SkPictureRecorder::optimizeFor(GrContext*). I'm open to API suggestions. We can pass this in finishAs(), up front, whatever. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2203453002 Review-Url: https://codereview.chromium.org/2203453002 --- include/core/SkPictureRecorder.h | 6 +++++ include/private/SkRecords.h | 47 ++++++++++++++++++------------------ src/core/SkPictureCommon.h | 10 ++------ src/core/SkPictureRecorder.cpp | 51 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 31 deletions(-) diff --git a/include/core/SkPictureRecorder.h b/include/core/SkPictureRecorder.h index 82efcf0..f20a06a 100644 --- a/include/core/SkPictureRecorder.h +++ b/include/core/SkPictureRecorder.h @@ -19,6 +19,7 @@ namespace android { }; #endif +class GrContext; class SkCanvas; class SkDrawable; class SkPictureRecord; @@ -111,6 +112,9 @@ public: SkPicture* SK_WARN_UNUSED_RESULT endRecording() { return this->endRecordingAsPicture(); } #endif + // Strawman API. + void optimizeFor(GrContext* ctx) { fGrContextToOptimizeFor = ctx; } + private: void reset(); @@ -131,6 +135,8 @@ private: SkAutoTUnref fRecord; SkMiniRecorder fMiniRecorder; + GrContext* fGrContextToOptimizeFor = nullptr; + typedef SkNoncopyable INHERITED; }; diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h index 0b50d11..32da3dd 100644 --- a/include/private/SkRecords.h +++ b/include/private/SkRecords.h @@ -153,6 +153,7 @@ enum Tags { kDraw_Tag = 1, // May draw something (usually named DrawFoo). kHasImage_Tag = 2, // Contains an SkImage or SkBitmap. kHasText_Tag = 4, // Contains text. + kHasPaint_Tag = 8, // May have an SkPaint field, at least optionally. }; // A macro to make it a little easier to define a struct that can be stored in SkRecord. @@ -169,7 +170,7 @@ RECORD(Restore, 0, TypedMatrix matrix); RECORD(Save, 0); -RECORD(SaveLayer, 0, +RECORD(SaveLayer, kHasPaint_Tag, Optional bounds; Optional paint; sk_sp backdrop; @@ -208,7 +209,7 @@ RECORD(ClipRegion, 0, SkRegion::Op op); // While not strictly required, if you have an SkPaint, it's fastest to put it first. -RECORD(DrawDRRect, kDraw_Tag, +RECORD(DrawDRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect outer; SkRRect inner); @@ -216,90 +217,90 @@ RECORD(DrawDrawable, kDraw_Tag, Optional matrix; SkRect worstCaseBounds; int32_t index); -RECORD(DrawImage, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImage, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; sk_sp image; SkScalar left; SkScalar top); -RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; sk_sp image; Optional src; SkRect dst; SkCanvas::SrcRectConstraint constraint); -RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; sk_sp image; SkIRect center; SkRect dst); -RECORD(DrawOval, kDraw_Tag, +RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect oval); -RECORD(DrawPaint, kDraw_Tag, +RECORD(DrawPaint, kDraw_Tag|kHasPaint_Tag, SkPaint paint); -RECORD(DrawPath, kDraw_Tag, +RECORD(DrawPath, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PreCachedPath path); -RECORD(DrawPicture, kDraw_Tag, +RECORD(DrawPicture, kDraw_Tag|kHasPaint_Tag, Optional paint; sk_sp picture; TypedMatrix matrix); -RECORD(DrawShadowedPicture, kDraw_Tag, +RECORD(DrawShadowedPicture, kDraw_Tag|kHasPaint_Tag, Optional paint; sk_sp picture; TypedMatrix matrix); -RECORD(DrawPoints, kDraw_Tag, +RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::PointMode mode; unsigned count; SkPoint* pts); -RECORD(DrawPosText, kDraw_Tag|kHasText_Tag, +RECORD(DrawPosText, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; PODArray pos); -RECORD(DrawPosTextH, kDraw_Tag|kHasText_Tag, +RECORD(DrawPosTextH, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; unsigned byteLength; SkScalar y; PODArray xpos); -RECORD(DrawRRect, kDraw_Tag, +RECORD(DrawRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect rrect); -RECORD(DrawRect, kDraw_Tag, +RECORD(DrawRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect rect); -RECORD(DrawText, kDraw_Tag|kHasText_Tag, +RECORD(DrawText, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; SkScalar x; SkScalar y); -RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag, +RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; sk_sp blob; SkScalar x; SkScalar y); -RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag, +RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; PreCachedPath path; TypedMatrix matrix); -RECORD(DrawTextRSXform, kDraw_Tag|kHasText_Tag, +RECORD(DrawTextRSXform, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; PODArray xforms; Optional cull); -RECORD(DrawPatch, kDraw_Tag, +RECORD(DrawPatch, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PODArray cubics; PODArray colors; PODArray texCoords; sk_sp xmode); -RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag, +RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; sk_sp atlas; PODArray xforms; @@ -308,7 +309,7 @@ RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag, int count; SkXfermode::Mode mode; Optional cull); -RECORD(DrawVertices, kDraw_Tag, +RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::VertexMode vmode; int vertexCount; @@ -318,7 +319,7 @@ RECORD(DrawVertices, kDraw_Tag, sk_sp xmode; PODArray indices; int indexCount); -RECORD(DrawAnnotation, 0, +RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548 SkRect rect; SkString key; sk_sp value); diff --git a/src/core/SkPictureCommon.h b/src/core/SkPictureCommon.h index 1c38b04..0a0c6b5 100644 --- a/src/core/SkPictureCommon.h +++ b/src/core/SkPictureCommon.h @@ -45,18 +45,12 @@ struct SkBitmapHunter { // Most draws-type ops have paints. template - static SK_WHEN(T::kTags & SkRecords::kDraw_Tag, bool) CheckPaint(const T& op) { + static SK_WHEN(T::kTags & SkRecords::kHasPaint_Tag, bool) CheckPaint(const T& op) { return PaintHasBitmap(AsPtr(op.paint)); } - // SaveLayers also have a paint to check. - static bool CheckPaint(const SkRecords::SaveLayer& op) { - return PaintHasBitmap(AsPtr(op.paint)); - } - - // Shouldn't be any non-Draw non-SaveLayer ops with paints. template - static SK_WHEN(!(T::kTags & SkRecords::kDraw_Tag), bool) CheckPaint(const T&) { + static SK_WHEN(!(T::kTags & SkRecords::kHasPaint_Tag), bool) CheckPaint(const T&) { return false; } diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp index 5631a08..8e7c7f3 100644 --- a/src/core/SkPictureRecorder.cpp +++ b/src/core/SkPictureRecorder.cpp @@ -8,6 +8,7 @@ #include "SkBigPicture.h" #include "SkData.h" #include "SkDrawable.h" +#include "SkImage.h" #include "SkPictureRecorder.h" #include "SkPictureUtils.h" #include "SkRecord.h" @@ -16,6 +17,54 @@ #include "SkRecordedDrawable.h" #include "SkRecorder.h" #include "SkTypes.h" +#include "SkTLogic.h" + +namespace SkRecords { + + struct OptimizeFor { + GrContext* fCtx; + + // A few ops have a top-level SkImage: + void operator()(DrawAtlas* op) { this->make_texture(&op->atlas); } + void operator()(DrawImage* op) { this->make_texture(&op->image); } + void operator()(DrawImageNine* op) { this->make_texture(&op->image); } + void operator()(DrawImageRect* op) { this->make_texture(&op->image); } + void make_texture(sk_sp* img) const { + *img = (*img)->makeTextureImage(fCtx); + } + + // Some ops have a paint, some have an optional paint. + // Either way, get back a pointer. + static SkPaint* AsPtr(SkPaint& p) { return &p; } + static SkPaint* AsPtr(SkRecords::Optional& p) { return p; } + + // For all other types of ops, look for images inside the paint. + template + SK_WHEN(T::kTags & kHasPaint_Tag, void) operator()(T* op) { + SkMatrix matrix; + SkShader::TileMode xy[2]; + + if (auto paint = AsPtr(op->paint)) + if (auto shader = paint->getShader()) + if (auto image = shader->isAImage(&matrix, xy)) { + paint->setShader(image->makeTextureImage(fCtx)->makeShader(xy[0], xy[1], &matrix)); + } + + // TODO: re-build compose shaders + } + + // Control ops, etc. Nothing to do for these. + template + SK_WHEN(!(T::kTags & kHasPaint_Tag), void) operator()(T*) {} + }; + +} // namespace SkRecords + +static void optimize_for(GrContext* ctx, SkRecord* record) { + for (int i = 0; ctx && i < record->count(); i++) { + record->mutate(i, SkRecords::OptimizeFor{ctx}); + } +} SkPictureRecorder::SkPictureRecorder() { fActivelyRecording = false; @@ -63,6 +112,7 @@ sk_sp SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlag // TODO: delay as much of this work until just before first playback? SkRecordOptimize(fRecord); + optimize_for(fGrContextToOptimizeFor, fRecord); if (fRecord->count() == 0) { if (finishFlags & kReturnNullForEmpty_FinishFlag) { @@ -123,6 +173,7 @@ sk_sp SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFl fRecorder->restoreToCount(1); // If we were missing any restores, add them now. SkRecordOptimize(fRecord); + optimize_for(fGrContextToOptimizeFor, fRecord); if (fRecord->count() == 0) { if (finishFlags & kReturnNullForEmpty_FinishFlag) { -- 2.7.4