diff options
-rw-r--r-- | include/core/SkPicture.h | 61 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 21 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 13 | ||||
-rw-r--r-- | tests/PictureTest.cpp | 72 | ||||
-rw-r--r-- | tools/skpinfo.cpp | 4 |
5 files changed, 166 insertions, 5 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 8fa89656c9..f5d53c5592 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -365,6 +365,67 @@ private: SkAutoTUnref<SkPathHeap> fPathHeap; // reference counted + // ContentInfo is not serialized! It is intended solely for use + // with suitableForGpuRasterization. + class ContentInfo { + public: + ContentInfo() { this->reset(); } + + ContentInfo(const ContentInfo& src) { this->set(src); } + + void set(const ContentInfo& src) { + fNumPaintWithPathEffectUses = src.fNumPaintWithPathEffectUses; + fNumAAConcavePaths = src.fNumAAConcavePaths; + fNumAAHairlineConcavePaths = src.fNumAAHairlineConcavePaths; + } + + void reset() { + fNumPaintWithPathEffectUses = 0; + fNumAAConcavePaths = 0; + fNumAAHairlineConcavePaths = 0; + } + + void swap(ContentInfo* other) { + SkTSwap(fNumPaintWithPathEffectUses, other->fNumPaintWithPathEffectUses); + SkTSwap(fNumAAConcavePaths, other->fNumAAConcavePaths); + SkTSwap(fNumAAHairlineConcavePaths, other->fNumAAHairlineConcavePaths); + } + + // This field is incremented every time a paint with a path effect is + // used (i.e., it is not a de-duplicated count) + int fNumPaintWithPathEffectUses; + // This field is incremented every time an anti-aliased drawPath call is + // issued with a concave path + int fNumAAConcavePaths; + // This field is incremented every time a drawPath call is + // issued for a hairline stroked concave path. + int fNumAAHairlineConcavePaths; + }; + + ContentInfo fContentInfo; + + void incPaintWithPathEffectUses() { + ++fContentInfo.fNumPaintWithPathEffectUses; + } + int numPaintWithPathEffectUses() const { + return fContentInfo.fNumPaintWithPathEffectUses; + } + + void incAAConcavePaths() { + ++fContentInfo.fNumAAConcavePaths; + } + int numAAConcavePaths() const { + return fContentInfo.fNumAAConcavePaths; + } + + void incAAHairlineConcavePaths() { + ++fContentInfo.fNumAAHairlineConcavePaths; + SkASSERT(fContentInfo.fNumAAHairlineConcavePaths <= fContentInfo.fNumAAConcavePaths); + } + int numAAHairlineConcavePaths() const { + return fContentInfo.fNumAAHairlineConcavePaths; + } + const SkPath& getPath(int index) const; int addPathToHeap(const SkPath& path); diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 10cc14b85d..65f723e53b 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -122,17 +122,18 @@ static void validateMatrix(const SkMatrix* matrix) { /////////////////////////////////////////////////////////////////////////////// -SkPicture::SkPicture() { +SkPicture::SkPicture() + : fAccelData(NULL) { this->needsNewGenID(); fRecord = NULL; fPlayback = NULL; fWidth = fHeight = 0; - fAccelData = NULL; } SkPicture::SkPicture(const SkPicture& src) : INHERITED() - , fAccelData(NULL) { + , fAccelData(NULL) + , fContentInfo(src.fContentInfo) { this->needsNewGenID(); fWidth = src.fWidth; fHeight = src.fHeight; @@ -207,6 +208,7 @@ void SkPicture::swap(SkPicture& other) { SkTSwap(fWidth, other.fWidth); SkTSwap(fHeight, other.fHeight); fPathHeap.swap(&other.fPathHeap); + fContentInfo.swap(&other.fContentInfo); } SkPicture* SkPicture::clone() const { @@ -228,6 +230,7 @@ void SkPicture::clone(SkPicture* pictures, int count) const { clone->fHeight = fHeight; SkSafeSetNull(clone->fRecord); SkDELETE(clone->fPlayback); + clone->fContentInfo.set(fContentInfo); /* We want to copy the src's playback. However, if that hasn't been built yet, we need to fake a call to endRecording() without actually calling @@ -271,6 +274,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height, } SkSafeUnref(fAccelData); SkSafeSetNull(fRecord); + fContentInfo.reset(); this->needsNewGenID(); @@ -305,6 +309,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height, SkSafeUnref(fAccelData); SkSafeSetNull(fRecord); SkASSERT(NULL == fPathHeap); + fContentInfo.reset(); this->needsNewGenID(); @@ -602,8 +607,14 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const { #if SK_SUPPORT_GPU bool SkPicture::suitableForGpuRasterization(GrContext* context) const { - // Stub for now; never veto GPu rasterization. - return true; + // TODO: the heuristic used here needs to be refined + static const int kNumPaintWithPathEffectUsesTol = 1; + static const int kNumAAConcavePaths = 5; + + SkASSERT(this->numAAHairlineConcavePaths() <= this->numAAConcavePaths()); + + return this->numPaintWithPathEffectUses() < kNumPaintWithPathEffectUsesTol && + (this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) < kNumAAConcavePaths; } #endif diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index f4fc7365b1..f3d108c47b 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -1065,6 +1065,15 @@ void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { + if (paint.isAntiAlias() && !path.isConvex()) { + fPicture->incAAConcavePaths(); + + if (SkPaint::kStroke_Style == paint.getStyle() && + 0 == paint.getStrokeWidth()) { + fPicture->incAAHairlineConcavePaths(); + } + } + #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); #endif @@ -1578,6 +1587,10 @@ const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { } const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { + if (NULL != paint && NULL != paint->getPathEffect()) { + fPicture->incPaintWithPathEffectUses(); + } + const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; this->addFlatPaint(data); return data; diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index 0a1c3c66fc..5e152341cc 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -8,6 +8,7 @@ #include "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkColorPriv.h" +#include "SkDashPathEffect.h" #include "SkData.h" #include "SkDecodingImageGenerator.h" #include "SkError.h" @@ -694,6 +695,76 @@ static void rand_op(SkCanvas* canvas, SkRandom& rand) { } } +static void test_gpu_veto(skiatest::Reporter* reporter) { + + SkPictureRecorder recorder; + + SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0); + { + SkPath path; + path.moveTo(0, 0); + path.lineTo(50, 50); + + SkScalar intervals[] = { 1.0f, 1.0f }; + SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0)); + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setPathEffect(dash); + + canvas->drawPath(path, paint); + } + SkAutoTUnref<SkPicture> picture(recorder.endRecording()); + // path effects currently render an SkPicture undesireable for GPU rendering + REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL)); + + canvas = recorder.beginRecording(100, 100, NULL, 0); + { + SkPath path; + + path.moveTo(0, 0); + path.lineTo(0, 50); + path.lineTo(25, 25); + path.lineTo(50, 50); + path.lineTo(50, 0); + path.close(); + REPORTER_ASSERT(reporter, !path.isConvex()); + + SkPaint paint; + paint.setAntiAlias(true); + for (int i = 0; i < 50; ++i) { + canvas->drawPath(path, paint); + } + } + picture.reset(recorder.endRecording()); + // A lot of AA concave paths currently render an SkPicture undesireable for GPU rendering + REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL)); + + canvas = recorder.beginRecording(100, 100, NULL, 0); + { + SkPath path; + + path.moveTo(0, 0); + path.lineTo(0, 50); + path.lineTo(25, 25); + path.lineTo(50, 50); + path.lineTo(50, 0); + path.close(); + REPORTER_ASSERT(reporter, !path.isConvex()); + + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(0); + for (int i = 0; i < 50; ++i) { + canvas->drawPath(path, paint); + } + } + picture.reset(recorder.endRecording()); + // hairline stroked AA concave paths are fine for GPU rendering + REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL)); +} + static void set_canvas_to_save_count_4(SkCanvas* canvas) { canvas->restoreToCount(1); canvas->save(); @@ -1197,6 +1268,7 @@ DEF_TEST(Picture, reporter) { #endif test_unbalanced_save_restores(reporter); test_peephole(); + test_gpu_veto(reporter); test_gatherpixelrefs(reporter); test_gatherpixelrefsandrects(reporter); test_bitmap_with_encoded_data(reporter); diff --git a/tools/skpinfo.cpp b/tools/skpinfo.cpp index 087d7a3565..6b5eded2b3 100644 --- a/tools/skpinfo.cpp +++ b/tools/skpinfo.cpp @@ -14,6 +14,7 @@ DEFINE_string2(input, i, "", "skp on which to report"); DEFINE_bool2(version, v, true, "version"); DEFINE_bool2(width, w, true, "width"); DEFINE_bool2(height, h, true, "height"); +DEFINE_bool2(flags, f, true, "flags"); DEFINE_bool2(tags, t, true, "tags"); DEFINE_bool2(quiet, q, false, "quiet"); @@ -64,6 +65,9 @@ int tool_main(int argc, char** argv) { if (FLAGS_height && !FLAGS_quiet) { SkDebugf("Height: %d\n", info.fHeight); } + if (FLAGS_flags && !FLAGS_quiet) { + SkDebugf("Flags: 0x%x\n", info.fFlags); + } if (!stream.readBool()) { // If we read true there's a picture playback object flattened |