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

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

Issue 23591030: start to remove lockPixels from bitmapshader (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: address review suggestions Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 #include "SkBitmapProcState.h" 8 #include "SkBitmapProcState.h"
9 #include "SkColorPriv.h" 9 #include "SkColorPriv.h"
10 #include "SkFilterProc.h" 10 #include "SkFilterProc.h"
11 #include "SkPaint.h" 11 #include "SkPaint.h"
12 #include "SkShader.h" // for tilemodes 12 #include "SkShader.h" // for tilemodes
13 #include "SkUtilsArm.h" 13 #include "SkUtilsArm.h"
14 #include "SkBitmapScaler.h" 14 #include "SkBitmapScaler.h"
15 #include "SkMipMap.h" 15 #include "SkMipMap.h"
16 #include "SkPixelRef.h"
16 #include "SkScaledImageCache.h" 17 #include "SkScaledImageCache.h"
17 18
18 #if !SK_ARM_NEON_IS_NONE 19 #if !SK_ARM_NEON_IS_NONE
19 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp 20 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
20 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; 21 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
21 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 22 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
22 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, i nt, uint16_t*); 23 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, i nt, uint16_t*);
23 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, i nt, int, uint16_t*, int); 24 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, i nt, int, uint16_t*, int);
24 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 25 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
25 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint3 2_t*, int, SkPMColor*); 26 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint3 2_t*, int, SkPMColor*);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 v2.fX = mat.getSkewX(); 103 v2.fX = mat.getSkewX();
103 v2.fY = mat.getScaleY(); 104 v2.fY = mat.getScaleY();
104 105
105 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); 106 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
106 } 107 }
107 108
108 // TODO -- we may want to pass the clip into this function so we only scale 109 // TODO -- we may want to pass the clip into this function so we only scale
109 // the portion of the image that we're going to need. This will complicate 110 // the portion of the image that we're going to need. This will complicate
110 // the interface to the cache, but might be well worth it. 111 // the interface to the cache, but might be well worth it.
111 112
112 void SkBitmapProcState::possiblyScaleImage() { 113 bool SkBitmapProcState::possiblyScaleImage() {
114 SkASSERT(NULL == fBitmap);
115 SkASSERT(NULL == fScaledCacheID);
113 116
114 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { 117 if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
115 // none or low (bilerp) does not need to look any further 118 return false;
116 return;
117 } 119 }
118 120
119 // STEP 1: Highest quality direct scale?
120
121 // Check to see if the transformation matrix is simple, and if we're 121 // Check to see if the transformation matrix is simple, and if we're
122 // doing high quality scaling. If so, do the bitmap scale here and 122 // doing high quality scaling. If so, do the bitmap scale here and
123 // remove the scaling component from the matrix. 123 // remove the scaling component from the matrix.
124 124
125 if (SkPaint::kHigh_FilterLevel == fFilterLevel && 125 if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
126 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) && 126 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) &&
127 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) { 127 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
128 128
129 SkScalar invScaleX = fInvMatrix.getScaleX(); 129 SkScalar invScaleX = fInvMatrix.getScaleX();
130 SkScalar invScaleY = fInvMatrix.getScaleY(); 130 SkScalar invScaleY = fInvMatrix.getScaleY();
131 131
132 SkASSERT(NULL == fScaledCacheID);
133 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, 132 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
134 invScaleX, invScaleY, 133 invScaleX, invScaleY,
135 &fScaledBitmap); 134 &fScaledBitmap);
136 if (NULL == fScaledCacheID) { 135 if (NULL == fScaledCacheID) {
137 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ; 136 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ;
138 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY ); 137 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY );
139 138
140 // All the criteria are met; let's make a new bitmap. 139 // All the criteria are met; let's make a new bitmap.
141 140
142 SkConvolutionProcs simd; 141 SkConvolutionProcs simd;
143 sk_bzero(&simd, sizeof(simd)); 142 sk_bzero(&simd, sizeof(simd));
144 this->platformConvolutionProcs(&simd); 143 this->platformConvolutionProcs(&simd);
145 144
146 if (!SkBitmapScaler::Resize(&fScaledBitmap, 145 if (!SkBitmapScaler::Resize(&fScaledBitmap,
147 fOrigBitmap, 146 fOrigBitmap,
148 SkBitmapScaler::RESIZE_BEST, 147 SkBitmapScaler::RESIZE_BEST,
149 dest_width, 148 dest_width,
150 dest_height, 149 dest_height,
151 simd)) { 150 simd)) {
152 // we failed to create fScaledBitmap, so just return and let 151 // we failed to create fScaledBitmap, so just return and let
153 // the scanline proc handle it. 152 // the scanline proc handle it.
154 return; 153 return true;
155 154
156 } 155 }
157 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, 156 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
158 invScaleX, 157 invScaleX,
159 invScaleY, 158 invScaleY,
160 fScaledBitmap); 159 fScaledBitmap);
161 } 160 }
162 fScaledBitmap.lockPixels(); 161 fScaledBitmap.lockPixels(); // wonder if Resize() should have locked thi s
163
164 fBitmap = &fScaledBitmap; 162 fBitmap = &fScaledBitmap;
165 163
166 // set the inv matrix type to translate-only; 164 // set the inv matrix type to translate-only;
167
168 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(), 165 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(),
169 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y()); 166 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y());
170 167
171 // no need for any further filtering; we just did it! 168 // no need for any further filtering; we just did it!
172
173 fFilterLevel = SkPaint::kNone_FilterLevel; 169 fFilterLevel = SkPaint::kNone_FilterLevel;
174 170 return true;
175 return;
176 } 171 }
177 172
178 /* 173 /*
179 * If we get here, the caller has requested either Med or High filter-level
180 *
181 * If High, then our special-case for scale-only did not take, and so we 174 * If High, then our special-case for scale-only did not take, and so we
182 * have to make a choice: 175 * have to make a choice:
183 * 1. fall back on mipmaps + bilerp 176 * 1. fall back on mipmaps + bilerp
184 * 2. fall back on scanline bicubic filter 177 * 2. fall back on scanline bicubic filter
185 * For now, we compute the "scale" value from the matrix, and have a 178 * For now, we compute the "scale" value from the matrix, and have a
186 * threshold to decide when bicubic is better, and when mips are better. 179 * threshold to decide when bicubic is better, and when mips are better.
187 * No doubt a fancier decision tree could be used uere. 180 * No doubt a fancier decision tree could be used uere.
188 * 181 *
189 * If Medium, then we just try to build a mipmap and select a level, 182 * If Medium, then we just try to build a mipmap and select a level,
190 * setting the filter-level to kLow to signal that we just need bilerp 183 * setting the filter-level to kLow to signal that we just need bilerp
191 * to process the selected level. 184 * to process the selected level.
192 */ 185 */
193 186
194 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix); 187 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
195 188
196 if (SkPaint::kHigh_FilterLevel == fFilterLevel) { 189 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
197 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller 190 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
198 // than this, then the mipmaps quality may be greater (certainly faster) 191 // than this, then the mipmaps quality may be greater (certainly faster)
199 // so we only keep High quality if the scale is greater than this. 192 // so we only keep High quality if the scale is greater than this.
200 // 193 //
201 // Since we're dealing with the inverse, we compare against its inverse. 194 // Since we're dealing with the inverse, we compare against its inverse.
202 const SkScalar bicubicLimit = SkFloatToScalar(4.0f); 195 const SkScalar bicubicLimit = SkFloatToScalar(4.0f);
203 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit; 196 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
204 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline 197 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline
205 return; 198 return false;
206 } 199 }
207 200
208 // else set the filter-level to Medium, since we're scaling down and 201 // else set the filter-level to Medium, since we're scaling down and
209 // want to reqeust mipmaps 202 // want to reqeust mipmaps
210 fFilterLevel = SkPaint::kMedium_FilterLevel; 203 fFilterLevel = SkPaint::kMedium_FilterLevel;
211 } 204 }
212 205
213 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); 206 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
214 207
215 /** 208 /**
(...skipping 24 matching lines...) Expand all
240 SkMipMap::Level level; 233 SkMipMap::Level level;
241 if (mip->extractLevel(levelScale, &level)) { 234 if (mip->extractLevel(levelScale, &level)) {
242 SkScalar invScaleFixup = level.fScale; 235 SkScalar invScaleFixup = level.fScale;
243 fInvMatrix.postScale(invScaleFixup, invScaleFixup); 236 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
244 237
245 fScaledBitmap.setConfig(fOrigBitmap.config(), 238 fScaledBitmap.setConfig(fOrigBitmap.config(),
246 level.fWidth, level.fHeight, 239 level.fWidth, level.fHeight,
247 level.fRowBytes); 240 level.fRowBytes);
248 fScaledBitmap.setPixels(level.fPixels); 241 fScaledBitmap.setPixels(level.fPixels);
249 fBitmap = &fScaledBitmap; 242 fBitmap = &fScaledBitmap;
243 fFilterLevel = SkPaint::kLow_FilterLevel;
244 return true;
250 } 245 }
251 } 246 }
252 } 247 }
253 248
249 return false;
250 }
251
252 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
253 SkPixelRef* pr = src.pixelRef();
254 if (pr && pr->decodeInto(pow2, dst)) {
255 return true;
256 }
257
254 /* 258 /*
255 * At this point, we may or may not have built a mipmap. Regardless, we 259 * If decodeInto() fails, the possibly we just have an old subclass that
scroggo 2013/09/10 21:51:41 If decodeInto() fails, it is possible* we just hav
reed1 2013/09/11 14:16:36 Done.
256 * now fall back on Low so will bilerp whatever fBitmap now points at. 260 * does not, or cannot, implement that. In that case we fall back to the
261 * older protocol of having the pixelRef handle the caching for us.
257 */ 262 */
258 fFilterLevel = SkPaint::kLow_FilterLevel; 263 *dst = src;
264 dst->lockPixels();
265 return SkToBool(dst->getPixels());
266 }
267
268 bool SkBitmapProcState::lockBaseBitmap() {
269 /*
270 * TODO
271 *
272 * If a pixelRef does not need to support decodeInto(), because it
273 * naturally always has the pixels around (e.g. SkMallocPixelRef) we should
274 * have a way to detect that, so we can skip all of this caching and just
275 * jump to its lockPixels() method (which should be free).
276 */
277
278 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
279 SK_Scalar1, SK_Scalar1,
280 &fScaledBitmap);
281 if (NULL == fScaledCacheID) {
282 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
283 return false;
284 }
285
286 // TODO: if fScaled comes back at a different width/height than fOrig,
287 // we need to update the matrix we are using to sample from this guy.
288
289 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
290 SK_Scalar1, SK_Scalar1,
291 fScaledBitmap);
292 if (!fScaledCacheID) {
293 fScaledBitmap.reset();
294 return false;
295 }
296 }
297
298 fScaledBitmap.lockPixels(); // just 'cause the cache made a copy :(
299 fBitmap = &fScaledBitmap;
300 return true;
259 } 301 }
260 302
261 void SkBitmapProcState::endContext() { 303 void SkBitmapProcState::endContext() {
262 SkDELETE(fBitmapFilter); 304 SkDELETE(fBitmapFilter);
263 fBitmapFilter = NULL; 305 fBitmapFilter = NULL;
264 fScaledBitmap.reset(); 306 fScaledBitmap.reset();
265 307
266 if (fScaledCacheID) { 308 if (fScaledCacheID) {
267 SkScaledImageCache::Unlock(fScaledCacheID); 309 SkScaledImageCache::Unlock(fScaledCacheID);
268 fScaledCacheID = NULL; 310 fScaledCacheID = NULL;
269 } 311 }
270 } 312 }
271 313
272 SkBitmapProcState::~SkBitmapProcState() { 314 SkBitmapProcState::~SkBitmapProcState() {
273 if (fScaledCacheID) { 315 if (fScaledCacheID) {
274 SkScaledImageCache::Unlock(fScaledCacheID); 316 SkScaledImageCache::Unlock(fScaledCacheID);
275 } 317 }
276 SkDELETE(fBitmapFilter); 318 SkDELETE(fBitmapFilter);
277 } 319 }
278 320
279 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 321 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
280 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 322 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
281 return false;
282 }
283 323
284 fBitmap = &fOrigBitmap; 324 fBitmap = NULL;
285 fInvMatrix = inv; 325 fInvMatrix = inv;
286
287 // initialize our filter quality to the one requested by the caller.
288 // We may downgrade it later if we determine that we either don't need
289 // or can't provide as high a quality filtering as the user requested.
290
291 fFilterLevel = paint.getFilterLevel(); 326 fFilterLevel = paint.getFilterLevel();
292 327
293 // possiblyScaleImage will look to see if it can rescale the image as a 328 // possiblyScaleImage will look to see if it can rescale the image as a
294 // preprocess; either by scaling up to the target size, or by selecting 329 // preprocess; either by scaling up to the target size, or by selecting
295 // a nearby mipmap level. If it does, it will adjust the working 330 // a nearby mipmap level. If it does, it will adjust the working
296 // matrix as well as the working bitmap. It may also adjust the filter 331 // matrix as well as the working bitmap. It may also adjust the filter
297 // quality to avoid re-filtering an already perfectly scaled image. 332 // quality to avoid re-filtering an already perfectly scaled image.
298 333 if (!this->possiblyScaleImage()) {
299 this->possiblyScaleImage(); 334 if (!this->lockBaseBitmap()) {
335 return false;
336 }
337 }
338
339 SkASSERT(fBitmap);
300 340
301 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; 341 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
302 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && 342 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
303 SkShader::kClamp_TileMode == fTileModeY; 343 SkShader::kClamp_TileMode == fTileModeY;
304 344
305 if (!(clampClamp || trivialMatrix)) { 345 if (!(clampClamp || trivialMatrix)) {
306 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 346 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
307 } 347 }
308 348
309 // Now that all possible changes to the matrix have taken place, check 349 // Now that all possible changes to the matrix have taken place, check
310 // to see if we're really close to a no-scale matrix. If so, explicitly 350 // to see if we're really close to a no-scale matrix. If so, explicitly
311 // set it to be so. Subsequent code may inspect this matrix to choose 351 // set it to be so. Subsequent code may inspect this matrix to choose
312 // a faster path in this case. 352 // a faster path in this case.
313 353
314 // This code will only execute if the matrix has some scale component; 354 // This code will only execute if the matrix has some scale component;
315 // if it's already pure translate then we won't do this inversion. 355 // if it's already pure translate then we won't do this inversion.
316 356
317 if (matrix_only_scale_translate(fInvMatrix)) { 357 if (matrix_only_scale_translate(fInvMatrix)) {
318 SkMatrix forward; 358 SkMatrix forward;
319 if (fInvMatrix.invert(&forward)) { 359 if (fInvMatrix.invert(&forward)) {
320 if (clampClamp ? just_trans_clamp(forward, *fBitmap) 360 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
321 : just_trans_general(forward)) { 361 : just_trans_general(forward)) {
322 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); 362 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
323 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); 363 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
324 fInvMatrix.setTranslate(tx, ty); 364 fInvMatrix.setTranslate(tx, ty);
325
326 } 365 }
327 } 366 }
328 } 367 }
329 368
330 fInvProc = fInvMatrix.getMapXYProc(); 369 fInvProc = fInvMatrix.getMapXYProc();
331 fInvType = fInvMatrix.getType(); 370 fInvType = fInvMatrix.getType();
332 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); 371 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
333 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); 372 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
334 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); 373 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
335 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); 374 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
932 } else { 971 } else {
933 size >>= 2; 972 size >>= 2;
934 } 973 }
935 974
936 if (fFilterLevel != SkPaint::kNone_FilterLevel) { 975 if (fFilterLevel != SkPaint::kNone_FilterLevel) {
937 size >>= 1; 976 size >>= 1;
938 } 977 }
939 978
940 return size; 979 return size;
941 } 980 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698