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

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 "SkInPlace.h"
11 #include "SkMatrix.h"
12
13 static bool valid_for_drawing(const SkBitmap& bm) {
14 if (0 == bm.width() || 0 == bm.height()) {
15 return false; // nothing to draw
16 }
17 if (NULL == bm.pixelRef()) {
18 return false; // no pixels to read
19 }
20 if (bm.getTexture()) {
21 // we can handle texture (ugh) since lockPixels will perform a read-back
22 return true;
23 }
24 if (kIndex_8_SkColorType == bm.colorType()) {
25 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe.
26 if (!bm.getColorTable()) {
27 return false;
28 }
29 }
30 return true;
31 }
32
33 SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmap& bm,
34 const SkMatrix& inv ,
35 SkFilterQuality qua lity,
36 SkInPlace* allocato r) {
37
38 if (!valid_for_drawing(bm)) {
39 return NULL;
40 }
41
42 SkInPlace heapAllocator(NULL, 0);
43 if (NULL == allocator) {
44 allocator = &heapAllocator;
45 }
46
47 State* state = this->onRequestBitmap(bm, inv, quality, *allocator);
48 if (state) {
49 if (!state->fLockedBitmap.getPixels()) {
50 state->fLockedBitmap.lockPixels();
51 if (!state->fLockedBitmap.getPixels()) {
52 allocator->destroy(state);
53 state = NULL;
54 }
55 }
56 }
57 return state;
58 }
59
60 //////////////////////////////////////////////////////////////////////////////// ///////////////////
61
62 #include "SkBitmapCache.h"
63 #include "SkBitmapScaler.h"
64 #include "SkMipMap.h"
65 #include "SkResourceCache.h"
66
67 class SkDefaultBitmapControllerState : public SkBitmapController::State {
68 public:
69 SkDefaultBitmapControllerState(const SkBitmap& src, const SkMatrix& inv, SkF ilterQuality qual);
70
71 private:
72 SkAutoTUnref<const SkMipMap> fCurrMip;
73
74 bool processHQRequest(const SkBitmap& orig);
75 bool processMediumRequest(const SkBitmap& orig);
76 };
77
78 // Check to see that the size of the bitmap that would be produced by
79 // scaling by the given inverted matrix is less than the maximum allowed.
80 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
81 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByte Limit();
82 if (0 == maximumAllocation) {
83 return true;
84 }
85 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
86 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
87 // Skip the division step:
88 const size_t size = bm.info().getSafeSize(bm.info().minRowBytes());
89 return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
90 }
91
92 /*
93 * High quality is implemented by performing up-right scale-only filtering and then
94 * using bilerp for any remaining transformations.
95 */
96 bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap ) {
97 if (fQuality != kHigh_SkFilterQuality) {
98 return false;
99 }
100
101 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
102 // to a valid bitmap. If we succeed, we will set this to Low instead.
103 fQuality = kMedium_SkFilterQuality;
104
105 if (kN32_SkColorType != origBitmap.colorType() || !cache_size_okay(origBitma p, fInvMatrix) ||
106 fInvMatrix.hasPerspective())
107 {
108 return false; // can't handle the reqeust
109 }
110
111 SkScalar invScaleX = fInvMatrix.getScaleX();
112 SkScalar invScaleY = fInvMatrix.getScaleY();
113 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
114 SkSize scale;
115 if (!fInvMatrix.decomposeScale(&scale)) {
116 return false;
117 }
118 invScaleX = scale.width();
119 invScaleY = scale.height();
120 }
121 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
122 return false; // no need for HQ
123 }
124
125 SkScalar trueDestWidth = origBitmap.width() / invScaleX;
126 SkScalar trueDestHeight = origBitmap.height() / invScaleY;
127 SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
128 SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
129
130 if (!SkBitmapCache::Find(origBitmap, roundedDestWidth, roundedDestHeight, &f LockedBitmap)) {
131 if (!SkBitmapScaler::Resize(&fLockedBitmap,
132 origBitmap,
133 SkBitmapScaler::RESIZE_BEST,
134 roundedDestWidth,
135 roundedDestHeight,
136 SkResourceCache::GetAllocator())) {
137 return false; // we failed to create fScaledBitmap
138 }
139
140 SkASSERT(fLockedBitmap.getPixels());
141 fLockedBitmap.setImmutable();
142 SkBitmapCache::Add(origBitmap, roundedDestWidth, roundedDestHeight, fLoc kedBitmap);
143 }
144
145 SkASSERT(fLockedBitmap.getPixels());
146
147 fInvMatrix.postScale(roundedDestWidth / origBitmap.width(),
148 roundedDestHeight / origBitmap.height());
149 fQuality = kLow_SkFilterQuality;
150 return true;
151 }
152
153 /*
154 * Modulo internal errors, this should always succeed *if* the matrix is downsc aling
155 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscalin g)
156 */
157 bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi tmap) {
158 SkASSERT(fQuality <= kMedium_SkFilterQuality);
159 if (fQuality != kMedium_SkFilterQuality) {
160 return false;
161 }
162
163 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap
164 // to a valid bitmap.
165 fQuality = kLow_SkFilterQuality;
166
167 SkSize invScaleSize;
168 if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) {
169 return false;
170 }
171 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height( ));
172
173 if (invScale > SK_Scalar1) {
174 fCurrMip.reset(SkMipMapCache::FindAndRef(origBitmap));
175 if (NULL == fCurrMip.get()) {
176 fCurrMip.reset(SkMipMapCache::AddAndRef(origBitmap));
177 if (NULL == fCurrMip.get()) {
178 return false;
179 }
180 }
181 // diagnostic for a crasher...
182 if (NULL == fCurrMip->data()) {
183 sk_throw();
184 }
185
186 SkScalar levelScale = SkScalarInvert(invScale);
187 SkMipMap::Level level;
188 if (fCurrMip->extractLevel(levelScale, &level)) {
189 SkScalar invScaleFixup = level.fScale;
190 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
191
192 const SkImageInfo info = origBitmap.info().makeWH(level.fWidth, leve l.fHeight);
193 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
194 // that here, and not need to explicitly track it ourselves.
195 return fLockedBitmap.installPixels(info, level.fPixels, level.fRowBy tes);
196 } else {
197 // failed to extract, so release the mipmap
198 fCurrMip.reset(NULL);
199 }
200 }
201 return false;
202 }
203
204 SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmap& s rc,
205 const SkMatrix& i nv,
206 SkFilterQuality q ual) {
207 fInvMatrix = inv;
208 fQuality = qual;
209
210 if (kMedium_SkFilterQuality == qual) {
211 SkDebugf("");
scroggo 2015/06/02 21:17:33 Did you mean to leave this in?
reed1 2015/06/04 13:17:03 Done.
212 }
213 if (!this->processHQRequest(src) && !this->processMediumRequest(src)) {
214 fLockedBitmap = src;
215 }
216 SkASSERT(fQuality <= kLow_SkFilterQuality);
217 }
218
219 SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi tmap& bm,
220 const SkMa trix& inverse,
221 SkFilterQu ality quality,
222 SkInPlace& allocator) {
223 return allocator.create<SkDefaultBitmapControllerState>(bm, inverse, quality );
224 }
225
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698