OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include "SkBBoxHierarchy.h" |
| 9 #include "SkBigPicture.h" |
| 10 #include "SkPathEffect.h" |
| 11 #include "SkRecord.h" |
| 12 #include "SkRecordDraw.h" |
| 13 |
| 14 SkBigPicture::SkBigPicture(const SkRect& cull, |
| 15 SkRecord* record, |
| 16 SnapshotArray* drawablePicts, |
| 17 SkBBoxHierarchy* bbh, |
| 18 AccelData* accelData, |
| 19 size_t approxBytesUsedBySubPictures) |
| 20 : fCullRect(cull) |
| 21 , fAnalysis(*record) |
| 22 , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures) |
| 23 , fRecord(record) // Take ownership of caller's ref. |
| 24 , fDrawablePicts(drawablePicts) // Take ownership. |
| 25 , fBBH(bbh) // Take ownership of caller's ref. |
| 26 , fAccelData(accelData) // Take ownership of caller's ref. |
| 27 {} |
| 28 |
| 29 void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const { |
| 30 SkASSERT(canvas); |
| 31 |
| 32 // If the query contains the whole picture, don't bother with the BBH. |
| 33 SkRect clipBounds = { 0, 0, 0, 0 }; |
| 34 (void)canvas->getClipBounds(&clipBounds); |
| 35 const bool useBBH = !clipBounds.contains(this->cullRect()); |
| 36 |
| 37 SkRecordDraw(*fRecord, |
| 38 canvas, |
| 39 this->drawablePicts(), |
| 40 nullptr, |
| 41 this->drawableCount(), |
| 42 useBBH ? fBBH : nullptr, |
| 43 callback); |
| 44 } |
| 45 |
| 46 void SkBigPicture::partialPlayback(SkCanvas* canvas, |
| 47 unsigned start, |
| 48 unsigned stop, |
| 49 const SkMatrix& initialCTM) const { |
| 50 SkASSERT(canvas); |
| 51 SkRecordPartialDraw(*fRecord, |
| 52 canvas, |
| 53 this->drawablePicts(), |
| 54 this->drawableCount(), |
| 55 start, |
| 56 stop, |
| 57 initialCTM); |
| 58 } |
| 59 |
| 60 SkRect SkBigPicture::cullRect() const { return fCullRect; } |
| 61 bool SkBigPicture::hasText() const { return fAnalysis.fHasText; } |
| 62 bool SkBigPicture::willPlayBackBitmaps() const { return fAnalysis.fWillPlayba
ckBitmaps; } |
| 63 int SkBigPicture::numSlowPaths() const { return fAnalysis.fNumSlowPat
hsAndDashEffects; } |
| 64 int SkBigPicture::approximateOpCount() const { return fRecord->count(); } |
| 65 size_t SkBigPicture::approximateBytesUsed() const { |
| 66 size_t bytes = sizeof(*this) + fRecord->bytesUsed() + fApproxBytesUsedBySubP
ictures; |
| 67 if (fBBH) { bytes += fBBH->bytesUsed(); } |
| 68 return bytes; |
| 69 } |
| 70 bool SkBigPicture::suitableForGpuRasterization(GrContext*, const char** reason)
const { |
| 71 return fAnalysis.suitableForGpuRasterization(reason); |
| 72 } |
| 73 |
| 74 int SkBigPicture::drawableCount() const { |
| 75 return fDrawablePicts ? fDrawablePicts->count() : 0; |
| 76 } |
| 77 SkPicture const* const* SkBigPicture::drawablePicts() const { |
| 78 return fDrawablePicts ? fDrawablePicts->begin() : nullptr; |
| 79 } |
| 80 |
| 81 |
| 82 // Some ops have a paint, some have an optional paint. Either way, get back a p
ointer. |
| 83 static const SkPaint* as_ptr(const SkPaint& p) { return &p; } |
| 84 static const SkPaint* as_ptr(const SkRecords::Optional<SkPaint>& p) { return p;
} |
| 85 |
| 86 struct TextHunter { |
| 87 // Most ops never have text. Some always do. Subpictures know themeselves. |
| 88 template <typename T> bool operator()(const T&) { return false; } |
| 89 bool operator()(const SkRecords::DrawPosText&) { return true; } |
| 90 bool operator()(const SkRecords::DrawPosTextH&) { return true; } |
| 91 bool operator()(const SkRecords::DrawText&) { return true; } |
| 92 bool operator()(const SkRecords::DrawTextBlob&) { return true; } |
| 93 bool operator()(const SkRecords::DrawTextOnPath&) { return true; } |
| 94 bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasTe
xt(); } |
| 95 }; |
| 96 |
| 97 struct BitmapHunter { |
| 98 // Helpers. These create HasMember_bitmap and HasMember_paint. |
| 99 SK_CREATE_MEMBER_DETECTOR(bitmap); |
| 100 SK_CREATE_MEMBER_DETECTOR(paint); |
| 101 |
| 102 // Main entry for visitor: |
| 103 // If the op is a DrawPicture, recurse. |
| 104 // If the op has a bitmap directly, return true. |
| 105 // If the op has a paint and the paint has a bitmap, return true. |
| 106 // Otherwise, return false. |
| 107 bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willP
layBackBitmaps(); } |
| 108 |
| 109 template <typename T> |
| 110 bool operator()(const T& r) { return CheckBitmap(r); } |
| 111 |
| 112 // If the op has a bitmap, of course we're going to play back bitmaps. |
| 113 template <typename T> |
| 114 static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return tru
e; } |
| 115 |
| 116 // If not, look for one in its paint (if it has a paint). |
| 117 template <typename T> |
| 118 static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return
CheckPaint(r); } |
| 119 |
| 120 // If we have a paint, dig down into the effects looking for a bitmap. |
| 121 template <typename T> |
| 122 static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) { |
| 123 const SkPaint* paint = as_ptr(r.paint); |
| 124 if (paint) { |
| 125 const SkShader* shader = paint->getShader(); |
| 126 if (shader && |
| 127 shader->asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefau
lt_BitmapType) { |
| 128 return true; |
| 129 } |
| 130 } |
| 131 return false; |
| 132 } |
| 133 |
| 134 // If we don't have a paint, that non-paint has no bitmap. |
| 135 template <typename T> |
| 136 static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return fals
e; } |
| 137 }; |
| 138 |
| 139 struct SkBigPicture::PathCounter { |
| 140 SK_CREATE_MEMBER_DETECTOR(paint); |
| 141 |
| 142 PathCounter() : fNumSlowPathsAndDashEffects(0) {} |
| 143 |
| 144 // Recurse into nested pictures. |
| 145 void operator()(const SkRecords::DrawPicture& op) { |
| 146 fNumSlowPathsAndDashEffects += op.picture->numSlowPaths(); |
| 147 } |
| 148 |
| 149 void checkPaint(const SkPaint* paint) { |
| 150 if (paint && paint->getPathEffect()) { |
| 151 // Initially assume it's slow. |
| 152 fNumSlowPathsAndDashEffects++; |
| 153 } |
| 154 } |
| 155 |
| 156 void operator()(const SkRecords::DrawPoints& op) { |
| 157 this->checkPaint(&op.paint); |
| 158 const SkPathEffect* effect = op.paint.getPathEffect(); |
| 159 if (effect) { |
| 160 SkPathEffect::DashInfo info; |
| 161 SkPathEffect::DashType dashType = effect->asADash(&info); |
| 162 if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap()
&& |
| 163 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) { |
| 164 fNumSlowPathsAndDashEffects--; |
| 165 } |
| 166 } |
| 167 } |
| 168 |
| 169 void operator()(const SkRecords::DrawPath& op) { |
| 170 this->checkPaint(&op.paint); |
| 171 if (op.paint.isAntiAlias() && !op.path.isConvex()) { |
| 172 SkPaint::Style paintStyle = op.paint.getStyle(); |
| 173 const SkRect& pathBounds = op.path.getBounds(); |
| 174 if (SkPaint::kStroke_Style == paintStyle && |
| 175 0 == op.paint.getStrokeWidth()) { |
| 176 // AA hairline concave path is not slow. |
| 177 } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width()
< 64.f && |
| 178 pathBounds.height() < 64.f && !op.path.isVolatile()) { |
| 179 // AADF eligible concave path is not slow. |
| 180 } else { |
| 181 fNumSlowPathsAndDashEffects++; |
| 182 } |
| 183 } |
| 184 } |
| 185 |
| 186 template <typename T> |
| 187 SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) { |
| 188 this->checkPaint(as_ptr(op.paint)); |
| 189 } |
| 190 |
| 191 template <typename T> |
| 192 SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing *
/ } |
| 193 |
| 194 int fNumSlowPathsAndDashEffects; |
| 195 }; |
| 196 |
| 197 SkBigPicture::Analysis::Analysis(const SkRecord& record) { |
| 198 TextHunter text; |
| 199 BitmapHunter bitmap; |
| 200 PathCounter path; |
| 201 |
| 202 bool hasText = false, hasBitmap = false; |
| 203 for (unsigned i = 0; i < record.count(); i++) { |
| 204 hasText = hasText || record.visit<bool>(i, text); |
| 205 hasBitmap = hasBitmap || record.visit<bool>(i, bitmap); |
| 206 record.visit<void>(i, path); |
| 207 } |
| 208 |
| 209 fHasText = hasText; |
| 210 fWillPlaybackBitmaps = hasBitmap; |
| 211 fNumSlowPathsAndDashEffects = SkTMin<int>(path.fNumSlowPathsAndDashEffects,
255); |
| 212 } |
| 213 |
| 214 bool SkBigPicture::Analysis::suitableForGpuRasterization(const char** reason) co
nst { |
| 215 if (fNumSlowPathsAndDashEffects > 5) { |
| 216 if (reason) { *reason = "Too many slow paths (either concave or dashed).
"; } |
| 217 return false; |
| 218 } |
| 219 return true; |
| 220 } |
OLD | NEW |