aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkPicture.h61
-rw-r--r--src/core/SkPicture.cpp21
-rw-r--r--src/core/SkPictureRecord.cpp13
-rw-r--r--tests/PictureTest.cpp72
-rw-r--r--tools/skpinfo.cpp4
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