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

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: 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
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | src/core/SkPixelRef.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, it is possibe that we have an old subclass that
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 SkPixelRef* pr = fOrigBitmap.pixelRef();
270
271 if (pr->isLocked() || !pr->implementsDecodeInto()) {
272 // fast-case, no need to look in our cache
273 fScaledBitmap = fOrigBitmap;
274 } else {
275 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
276 SK_Scalar1, SK_Scalar1,
277 &fScaledBitmap);
278 if (NULL == fScaledCacheID) {
279 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
280 return false;
281 }
282
283 // TODO: if fScaled comes back at a different width/height than fOri g,
284 // we need to update the matrix we are using to sample from this guy .
285
286 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
287 SK_Scalar1, SK_Scala r1,
288 fScaledBitmap);
289 if (!fScaledCacheID) {
290 fScaledBitmap.reset();
291 return false;
292 }
293 }
294 }
295 fScaledBitmap.lockPixels(); // just 'cause the cache made a copy :(
296 fBitmap = &fScaledBitmap;
297 return true;
259 } 298 }
260 299
261 void SkBitmapProcState::endContext() { 300 void SkBitmapProcState::endContext() {
262 SkDELETE(fBitmapFilter); 301 SkDELETE(fBitmapFilter);
263 fBitmapFilter = NULL; 302 fBitmapFilter = NULL;
264 fScaledBitmap.reset(); 303 fScaledBitmap.reset();
265 304
266 if (fScaledCacheID) { 305 if (fScaledCacheID) {
267 SkScaledImageCache::Unlock(fScaledCacheID); 306 SkScaledImageCache::Unlock(fScaledCacheID);
268 fScaledCacheID = NULL; 307 fScaledCacheID = NULL;
269 } 308 }
270 } 309 }
271 310
272 SkBitmapProcState::~SkBitmapProcState() { 311 SkBitmapProcState::~SkBitmapProcState() {
273 if (fScaledCacheID) { 312 if (fScaledCacheID) {
274 SkScaledImageCache::Unlock(fScaledCacheID); 313 SkScaledImageCache::Unlock(fScaledCacheID);
275 } 314 }
276 SkDELETE(fBitmapFilter); 315 SkDELETE(fBitmapFilter);
277 } 316 }
278 317
279 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 318 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
280 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 319 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
281 return false;
282 }
283 320
284 fBitmap = &fOrigBitmap; 321 fBitmap = NULL;
285 fInvMatrix = inv; 322 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(); 323 fFilterLevel = paint.getFilterLevel();
292 324
293 // possiblyScaleImage will look to see if it can rescale the image as a 325 // 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 326 // 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 327 // 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 328 // matrix as well as the working bitmap. It may also adjust the filter
297 // quality to avoid re-filtering an already perfectly scaled image. 329 // quality to avoid re-filtering an already perfectly scaled image.
298 330 if (!this->possiblyScaleImage()) {
299 this->possiblyScaleImage(); 331 if (!this->lockBaseBitmap()) {
332 return false;
333 }
334 }
335
336 SkASSERT(fBitmap);
300 337
301 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; 338 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
302 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX && 339 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
303 SkShader::kClamp_TileMode == fTileModeY; 340 SkShader::kClamp_TileMode == fTileModeY;
304 341
305 if (!(clampClamp || trivialMatrix)) { 342 if (!(clampClamp || trivialMatrix)) {
306 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 343 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
307 } 344 }
308 345
309 // Now that all possible changes to the matrix have taken place, check 346 // 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 347 // 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 348 // set it to be so. Subsequent code may inspect this matrix to choose
312 // a faster path in this case. 349 // a faster path in this case.
313 350
314 // This code will only execute if the matrix has some scale component; 351 // 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. 352 // if it's already pure translate then we won't do this inversion.
316 353
317 if (matrix_only_scale_translate(fInvMatrix)) { 354 if (matrix_only_scale_translate(fInvMatrix)) {
318 SkMatrix forward; 355 SkMatrix forward;
319 if (fInvMatrix.invert(&forward)) { 356 if (fInvMatrix.invert(&forward)) {
320 if (clampClamp ? just_trans_clamp(forward, *fBitmap) 357 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
321 : just_trans_general(forward)) { 358 : just_trans_general(forward)) {
322 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX()); 359 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
323 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY()); 360 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
324 fInvMatrix.setTranslate(tx, ty); 361 fInvMatrix.setTranslate(tx, ty);
325
326 } 362 }
327 } 363 }
328 } 364 }
329 365
330 fInvProc = fInvMatrix.getMapXYProc(); 366 fInvProc = fInvMatrix.getMapXYProc();
331 fInvType = fInvMatrix.getType(); 367 fInvType = fInvMatrix.getType();
332 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX()); 368 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
333 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX()); 369 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
334 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY()); 370 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
335 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY()); 371 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
932 } else { 968 } else {
933 size >>= 2; 969 size >>= 2;
934 } 970 }
935 971
936 if (fFilterLevel != SkPaint::kNone_FilterLevel) { 972 if (fFilterLevel != SkPaint::kNone_FilterLevel) {
937 size >>= 1; 973 size >>= 1;
938 } 974 }
939 975
940 return size; 976 return size;
941 } 977 }
OLDNEW
« no previous file with comments | « src/core/SkBitmapProcState.h ('k') | src/core/SkPixelRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698