Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Unified Diff: src/core/SkPicture.cpp

Issue 364823009: Port suitableForGpuRasterization to SkRecord (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Reed review complete Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/core/SkPicture.cpp
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index fa4c103d5ce1ca5506a5fc7b7731b7bf9c24572a..18fc249a3c39a72ff1357a26ff7bac91b4ef62ae 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -19,11 +19,13 @@
#include "SkChunkAlloc.h"
#include "SkDrawPictureCallback.h"
#include "SkPaintPriv.h"
+#include "SkPathEffect.h"
#include "SkPicture.h"
-#include "SkRecordAnalysis.h"
#include "SkRegion.h"
+#include "SkShader.h"
#include "SkStream.h"
#include "SkTDArray.h"
+#include "SkTLogic.h"
#include "SkTSearch.h"
#include "SkTime.h"
@@ -46,12 +48,198 @@ template <typename T> int SafeCount(const T* obj) {
///////////////////////////////////////////////////////////////////////////////
+namespace {
+
+/** SkRecords visitor to determine whether an instance may require an
+ "external" bitmap to rasterize. May return false positives.
+ Does not return true for bitmap text.
+
+ Expected use is to determine whether images need to be decoded before
+ rasterizing a particular SkRecord.
+ */
+struct BitmapTester {
+ // Helpers. These create HasMember_bitmap and HasMember_paint.
+ SK_CREATE_MEMBER_DETECTOR(bitmap);
+ SK_CREATE_MEMBER_DETECTOR(paint);
+
+ // Some commands have a paint, some have an optional paint. Either way, get back a pointer.
+ static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
mtklein 2014/08/18 19:22:14 Might promote these guys out of the structs, now t
tomhudson 2014/08/18 21:37:00 Done.
+ static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
+
+
+ // Main entry for visitor:
+ // If the command has a bitmap directly, return true.
+ // If the command has a paint and the paint has a bitmap, return true.
+ // Otherwise, return false.
+ template <typename T>
+ bool operator()(const T& r) { return CheckBitmap(r); }
+
+
+ // If the command has a bitmap, of course we're going to play back bitmaps.
+ template <typename T>
+ static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
+
+ // If not, look for one in its paint (if it has a paint).
+ template <typename T>
+ static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
+
+ // If we have a paint, dig down into the effects looking for a bitmap.
+ template <typename T>
+ static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
+ const SkPaint* paint = AsPtr(r.paint);
+ if (paint) {
+ const SkShader* shader = paint->getShader();
+ if (shader &&
+ shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // If we don't have a paint, that non-paint has no bitmap.
+ template <typename T>
+ static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
+};
+
+bool WillPlaybackBitmaps(const SkRecord& record) {
+ BitmapTester tester;
+ for (unsigned i = 0; i < record.count(); i++) {
+ if (record.visit<bool>(i, tester)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** SkRecords visitor to determine heuristically whether or not a SkPicture
+ will be performant when rasterized on the GPU.
+ */
+struct PathCounter {
+ SK_CREATE_MEMBER_DETECTOR(paint);
+ SK_CREATE_TYPE_DETECTOR(DrawPoints);
+ SK_CREATE_TYPE_DETECTOR(DrawPath);
+
+ // Some commands have a paint, some have an optional paint. Either way, get back a pointer.
+ static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
+ static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
+
+ PathCounter()
+ : numPaintWithPathEffectUses (0)
+ , numFastPathDashEffects (0)
+ , numAAConcavePaths (0)
+ , numAAHairlineConcavePaths (0) {
+ }
+
+ // Must have a return type to make the SkRecord vistor templates happy.
+ template <typename T>
+ bool operator()(const T& r) {
mtklein 2014/08/18 19:22:14 void's okay too. Just use record.visit<void>(...)
mtklein 2014/08/18 19:22:14 I'd structure this a little differently: void che
tomhudson 2014/08/18 21:37:00 How about this, which gets rid of the indirection
tomhudson 2014/08/18 21:37:00 Done.
+ CheckPaint(r);
+ CheckDrawPoints(r);
+ CheckDrawPath(r);
+ return true;
+ }
+
+ template <typename T>
+ SK_WHEN(HasMember_paint<T>, void) CheckPaint(const T& r) {
+ const SkPaint* paint = AsPtr(r.paint);
+ if (paint && paint->getPathEffect()) {
+ numPaintWithPathEffectUses++;
+ }
+ }
+
+ template <typename T>
+ SK_WHEN(!HasMember_paint<T>, void) CheckPaint(const T& r) { /* do nothing */ }
+
+ template <typename T>
+ SK_WHEN(HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) {
+ const SkPathEffect* effect = r.paint.getPathEffect();
+ if (effect) {
+ SkPathEffect::DashInfo info;
+ SkPathEffect::DashType dashType = effect->asADash(&info);
+ if (2 == r.count && SkPaint::kRound_Cap != r.paint.getStrokeCap() &&
+ SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
+ numFastPathDashEffects++;
+ }
+ }
+ }
+
+ template <typename T>
+ SK_WHEN(!HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) { /* do nothing */ }
+
+ template <typename T>
+ SK_WHEN(HasType_DrawPath<T>, void) CheckDrawPath(const T& r) {
+ if (r.paint.isAntiAlias() && !r.path.isConvex()) {
+ numAAConcavePaths++;
+
+ if (SkPaint::kStroke_Style == r.paint.getStyle() &&
+ 0 == r.paint.getStrokeWidth()) {
+ numAAHairlineConcavePaths++;
+ }
+ }
+ }
+
+ template <typename T>
+ SK_WHEN(!HasType_DrawPath<T>, void) CheckDrawPath(const T& r) { /* do nothing */ }
+
+
+ int numPaintWithPathEffectUses;
+ int numFastPathDashEffects;
+ int numAAConcavePaths;
+ int numAAHairlineConcavePaths;
+};
+
+bool SuitableForGpuRasterization(const SkRecord& record,
+ const char** reason = NULL,
mtklein 2014/08/18 19:22:14 Funky indent?
tomhudson 2014/08/18 21:37:00 Done.
+ int sampleCount = 0) {
+ PathCounter counter;
+ for (unsigned i = 0; i < record.count(); i++) {
+ record.visit<bool>(i, counter);
+ }
+
+ // TODO: the heuristic used here needs to be refined
+ static const int kNumPaintWithPathEffectsUsesTol = 1;
+ static const int kNumAAConcavePathsTol = 5;
+
+ int numNonDashedPathEffects = counter.numPaintWithPathEffectUses -
+ counter.numFastPathDashEffects;
+ bool suitableForDash = (0 == counter.numPaintWithPathEffectUses) ||
+ (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol
+ && 0 == sampleCount);
+
+ bool ret = suitableForDash &&
+ (counter.numAAConcavePaths - counter.numAAHairlineConcavePaths)
+ < kNumAAConcavePathsTol;
+
+ if (!ret && NULL != reason) {
+ if (!suitableForDash) {
+ if (0 != sampleCount) {
+ *reason = "Can't use multisample on dash effect.";
+ } else {
+ *reason = "Too many non dashed path effects.";
+ }
+ } else if ((counter.numAAConcavePaths - counter.numAAHairlineConcavePaths)
+ >= kNumAAConcavePathsTol)
+ *reason = "Too many anti-aliased concave paths.";
+ else
+ *reason = "Unknown reason for GPU unsuitability.";
+ }
+ return ret;
+}
+
+} // namespace
+
+SkPicture::Analysis::Analysis(const SkRecord& record)
+ : fWillPlaybackBitmaps (WillPlaybackBitmaps(record))
+ , fSuitableForGpuRasterization (SuitableForGpuRasterization(record)) { }
+
+///////////////////////////////////////////////////////////////////////////////
+
#ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR
// fRecord OK
SkPicture::SkPicture()
: fWidth(0)
- , fHeight(0)
- , fRecordWillPlayBackBitmaps(false) {
+ , fHeight(0) {
this->needsNewGenID();
}
#endif
@@ -61,8 +249,7 @@ SkPicture::SkPicture(int width, int height,
const SkPictureRecord& record,
bool deepCopyOps)
: fWidth(width)
- , fHeight(height)
- , fRecordWillPlayBackBitmaps(false) {
+ , fHeight(height) {
this->needsNewGenID();
SkPictInfo info;
@@ -137,7 +324,6 @@ SkPicture* SkPicture::clone() const {
}
SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight));
- clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps;
clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
return clone;
@@ -264,8 +450,7 @@ bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo
SkPicture::SkPicture(SkPictureData* data, int width, int height)
: fData(data)
, fWidth(width)
- , fHeight(height)
- , fRecordWillPlayBackBitmaps(false) {
+ , fHeight(height) {
this->needsNewGenID();
}
@@ -380,8 +565,11 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
}
#if SK_SUPPORT_GPU
-// fRecord TODO
+// fRecord OK
bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
+ if (fRecord.get()) {
+ return fAnalysis.fSuitableForGpuRasterization;
+ }
if (NULL == fData.get()) {
if (NULL != reason) {
*reason = "Missing internal data.";
@@ -396,7 +584,7 @@ bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **rea
// fRecord OK
bool SkPicture::willPlayBackBitmaps() const {
if (fRecord.get()) {
- return fRecordWillPlayBackBitmaps;
+ return fAnalysis.fWillPlaybackBitmaps;
}
if (!fData.get()) {
return false;
@@ -430,7 +618,7 @@ SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* b
, fHeight(height)
, fRecord(record)
, fBBH(SkSafeRef(bbh))
- , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) {
+ , fAnalysis(*record) {
// TODO: delay as much of this work until just before first playback?
if (fBBH.get()) {
SkRecordFillBounds(*record, fBBH.get());

Powered by Google App Engine
This is Rietveld 408576698