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

Side by Side Diff: src/core/SkBitmapController.cpp

Issue 1153123003: refactor bitmapshader to use a controller (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 6 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 unified diff | Download patch
OLDNEW
(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 "SkBitmap.h"
9 #include "SkBitmapController.h"
10 #include "SkMatrix.h"
11
12 static bool valid_for_drawing(const SkBitmap& bm) {
13 if (0 == bm.width() || 0 == bm.height()) {
14 return false; // nothing to draw
15 }
16 if (NULL == bm.pixelRef()) {
17 return false; // no pixels to read
18 }
19 if (bm.getTexture()) {
20 // we can handle texture (ugh) since lockPixels will perform a read-back
21 return true;
22 }
23 if (kIndex_8_SkColorType == bm.colorType()) {
24 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe.
25 if (!bm.getColorTable()) {
26 return false;
27 }
28 }
29 return true;
30 }
31
32 bool SkBitmapController::requestBitmap(const SkBitmap& inBM, const SkMatrix& inv ,
33 SkFilterQuality inQuality, SkBitmap* outB M, SkMatrix* outInv,
34 SkFilterQuality* outQuality) {
35 if (!valid_for_drawing(inBM)) {
36 return false;
37 }
38 return this->onRequestBitmap(inBM, inv, inQuality, outBM, outInv, outQuality );
39 }
40
41 //////////////////////////////////////////////////////////////////////////////// ///////////////////
42
43 #include "SkBitmapCache.h"
44 #include "SkBitmapScaler.h"
45 #include "SkMipMap.h"
46 #include "SkResourceCache.h"
47
48 class SkDefaultBitmapControllerState {
49 public:
50 SkDefaultBitmapControllerState(const SkBitmap& src, const SkMatrix& inv, SkF ilterQuality qual)
51 : fOrigBitmap(src), fInvMatrix(inv), fFilterLevel(qual)
52 {}
53
54 const SkBitmap& fOrigBitmap;
55 SkMatrix fInvMatrix;
56 SkFilterQuality fFilterLevel;
57
58 SkBitmap fScaledBitmap;
59 SkAutoTUnref<const SkMipMap> fCurrMip;
60
61 bool processHQRequest();
62 bool processMediumRequest();
63 };
64
65 // Check to see that the size of the bitmap that would be produced by
66 // scaling by the given inverted matrix is less than the maximum allowed.
67 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
68 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByte Limit();
69 if (0 == maximumAllocation) {
70 return true;
71 }
72 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
73 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
74 // Skip the division step:
75 const size_t size = bm.info().getSafeSize(bm.info().minRowBytes());
76 return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
77 }
78
79 /*
80 * High quality is implemented by performing up-right scale-only filtering and then
81 * using bilerp for any remaining transformations.
82 */
83 bool SkDefaultBitmapControllerState::processHQRequest() {
84 SkASSERT(kHigh_SkFilterQuality == fFilterLevel);
85
86 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
87 // to a valid bitmap. If we succeed, we will set this to Low instead.
88 fFilterLevel = kMedium_SkFilterQuality;
89
90 if (kN32_SkColorType != fOrigBitmap.colorType() || !cache_size_okay(fOrigBit map, fInvMatrix) ||
91 fInvMatrix.hasPerspective())
92 {
93 return false; // can't handle the reqeust
94 }
95
96 SkScalar invScaleX = fInvMatrix.getScaleX();
97 SkScalar invScaleY = fInvMatrix.getScaleY();
98 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
99 SkSize scale;
100 if (!fInvMatrix.decomposeScale(&scale)) {
101 return false;
102 }
103 invScaleX = scale.width();
104 invScaleY = scale.height();
105 }
106 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
107 return false; // no need for HQ
108 }
109
110 SkScalar trueDestWidth = fOrigBitmap.width() / invScaleX;
111 SkScalar trueDestHeight = fOrigBitmap.height() / invScaleY;
112 SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
113 SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
114
115 if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, & fScaledBitmap)) {
116 if (!SkBitmapScaler::Resize(&fScaledBitmap,
117 fOrigBitmap,
118 SkBitmapScaler::RESIZE_BEST,
119 roundedDestWidth,
120 roundedDestHeight,
121 SkResourceCache::GetAllocator())) {
122 return false; // we failed to create fScaledBitmap
123 }
124
125 SkASSERT(fScaledBitmap.getPixels());
126 fScaledBitmap.setImmutable();
127 SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fSc aledBitmap);
128 }
129
130 SkASSERT(fScaledBitmap.getPixels());
131
132 fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(),
133 roundedDestHeight / fOrigBitmap.height());
134 fFilterLevel = kLow_SkFilterQuality;
135 return true;
136 }
137
138 /*
139 * Modulo internal errors, this should always succeed *if* the matrix is downsc aling
140 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscalin g)
141 */
142 bool SkDefaultBitmapControllerState::processMediumRequest() {
143 SkASSERT(kMedium_SkFilterQuality == fFilterLevel);
144
145 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap
146 // to a valid bitmap.
147 fFilterLevel = kLow_SkFilterQuality;
148
149 SkSize invScaleSize;
150 if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) {
151 return false;
152 }
153 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height( ));
154
155 if (invScale > SK_Scalar1) {
156 fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
157 if (NULL == fCurrMip.get()) {
158 fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap));
159 if (NULL == fCurrMip.get()) {
160 return false;
161 }
162 }
163 // diagnostic for a crasher...
164 if (NULL == fCurrMip->data()) {
165 sk_throw();
166 }
167
168 SkScalar levelScale = SkScalarInvert(invScale);
169 SkMipMap::Level level;
170 if (fCurrMip->extractLevel(levelScale, &level)) {
171 SkScalar invScaleFixup = level.fScale;
172 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
173
174 const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, lev el.fHeight);
175 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
176 // that here, and not need to explicitly track it ourselves.
177 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
scroggo 2015/06/02 13:24:53 Should we check the return value? (Even just to as
reed1 2015/06/02 14:07:46 Done.
178 return true;
179 } else {
180 // failed to extract, so release the mipmap
181 fCurrMip.reset(NULL);
182 }
183 }
184 return false;
185 }
186
187 bool SkDefaultBitmapController::onRequestBitmap(const SkBitmap& inBM, const SkMa trix& inInverse,
188 SkFilterQuality inQuality, SkBit map* outBM,
189 SkMatrix* outInverse, SkFilterQu ality* outQuality) {
190 SkDefaultBitmapControllerState state(inBM, inInverse, inQuality);
191
192 if (!state.processHQRequest() && !state.processHQRequest()) {
scroggo 2015/06/02 13:24:54 Two questions: - if inQuality is not kHigh, won't
reed1 2015/06/02 14:07:46 Done.
193 state.fScaledBitmap = inBM;
194 }
195 SkASSERT(state.fFilterLevel <= kLow_SkFilterQuality);
196 *outBM = state.fScaledBitmap;
197 *outInverse = inInverse;
198 *outQuality = state.fFilterLevel;
199 return true;
200 }
201
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698