|
1 |
|
2 /* |
|
3 * Copyright 2011 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 #include "SkColorPriv.h" |
|
9 #include "SkReadBuffer.h" |
|
10 #include "SkWriteBuffer.h" |
|
11 #include "SkPixelRef.h" |
|
12 #include "SkErrorInternals.h" |
|
13 #include "SkBitmapProcShader.h" |
|
14 |
|
15 #if SK_SUPPORT_GPU |
|
16 #include "effects/GrSimpleTextureEffect.h" |
|
17 #include "effects/GrBicubicEffect.h" |
|
18 #endif |
|
19 |
|
20 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { |
|
21 switch (bm.colorType()) { |
|
22 case kAlpha_8_SkColorType: |
|
23 case kRGB_565_SkColorType: |
|
24 case kIndex_8_SkColorType: |
|
25 case kPMColor_SkColorType: |
|
26 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) |
|
27 return true; |
|
28 default: |
|
29 break; |
|
30 } |
|
31 return false; |
|
32 } |
|
33 |
|
34 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, |
|
35 TileMode tmx, TileMode tmy) { |
|
36 fRawBitmap = src; |
|
37 fState.fTileModeX = (uint8_t)tmx; |
|
38 fState.fTileModeY = (uint8_t)tmy; |
|
39 fFlags = 0; // computed in setContext |
|
40 } |
|
41 |
|
42 SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer) |
|
43 : INHERITED(buffer) { |
|
44 buffer.readBitmap(&fRawBitmap); |
|
45 fRawBitmap.setImmutable(); |
|
46 fState.fTileModeX = buffer.readUInt(); |
|
47 fState.fTileModeY = buffer.readUInt(); |
|
48 fFlags = 0; // computed in setContext |
|
49 } |
|
50 |
|
51 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, |
|
52 SkMatrix* texM, |
|
53 TileMode xy[]) const { |
|
54 if (texture) { |
|
55 *texture = fRawBitmap; |
|
56 } |
|
57 if (texM) { |
|
58 texM->reset(); |
|
59 } |
|
60 if (xy) { |
|
61 xy[0] = (TileMode)fState.fTileModeX; |
|
62 xy[1] = (TileMode)fState.fTileModeY; |
|
63 } |
|
64 return kDefault_BitmapType; |
|
65 } |
|
66 |
|
67 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { |
|
68 this->INHERITED::flatten(buffer); |
|
69 |
|
70 buffer.writeBitmap(fRawBitmap); |
|
71 buffer.writeUInt(fState.fTileModeX); |
|
72 buffer.writeUInt(fState.fTileModeY); |
|
73 } |
|
74 |
|
75 static bool only_scale_and_translate(const SkMatrix& matrix) { |
|
76 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; |
|
77 return (matrix.getType() & ~mask) == 0; |
|
78 } |
|
79 |
|
80 bool SkBitmapProcShader::isOpaque() const { |
|
81 return fRawBitmap.isOpaque(); |
|
82 } |
|
83 |
|
84 static bool valid_for_drawing(const SkBitmap& bm) { |
|
85 if (0 == bm.width() || 0 == bm.height()) { |
|
86 return false; // nothing to draw |
|
87 } |
|
88 if (NULL == bm.pixelRef()) { |
|
89 return false; // no pixels to read |
|
90 } |
|
91 if (kIndex_8_SkColorType == bm.colorType()) { |
|
92 // ugh, I have to lock-pixels to inspect the colortable |
|
93 SkAutoLockPixels alp(bm); |
|
94 if (!bm.getColorTable()) { |
|
95 return false; |
|
96 } |
|
97 } |
|
98 return true; |
|
99 } |
|
100 |
|
101 bool SkBitmapProcShader::setContext(const SkBitmap& device, |
|
102 const SkPaint& paint, |
|
103 const SkMatrix& matrix) { |
|
104 if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) { |
|
105 return false; |
|
106 } |
|
107 |
|
108 // do this first, so we have a correct inverse matrix |
|
109 if (!this->INHERITED::setContext(device, paint, matrix)) { |
|
110 return false; |
|
111 } |
|
112 |
|
113 fState.fOrigBitmap = fRawBitmap; |
|
114 if (!fState.chooseProcs(this->getTotalInverse(), paint)) { |
|
115 this->INHERITED::endContext(); |
|
116 return false; |
|
117 } |
|
118 |
|
119 const SkBitmap& bitmap = *fState.fBitmap; |
|
120 bool bitmapIsOpaque = bitmap.isOpaque(); |
|
121 |
|
122 // update fFlags |
|
123 uint32_t flags = 0; |
|
124 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { |
|
125 flags |= kOpaqueAlpha_Flag; |
|
126 } |
|
127 |
|
128 switch (bitmap.colorType()) { |
|
129 case kRGB_565_SkColorType: |
|
130 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); |
|
131 break; |
|
132 case kIndex_8_SkColorType: |
|
133 case kPMColor_SkColorType: |
|
134 if (bitmapIsOpaque) { |
|
135 flags |= kHasSpan16_Flag; |
|
136 } |
|
137 break; |
|
138 case kAlpha_8_SkColorType: |
|
139 break; // never set kHasSpan16_Flag |
|
140 default: |
|
141 break; |
|
142 } |
|
143 |
|
144 if (paint.isDither() && bitmap.colorType() != kRGB_565_SkColorType) { |
|
145 // gradients can auto-dither in their 16bit sampler, but we don't so |
|
146 // we clear the flag here. |
|
147 flags &= ~kHasSpan16_Flag; |
|
148 } |
|
149 |
|
150 // if we're only 1-pixel high, and we don't rotate, then we can claim this |
|
151 if (1 == bitmap.height() && |
|
152 only_scale_and_translate(this->getTotalInverse())) { |
|
153 flags |= kConstInY32_Flag; |
|
154 if (flags & kHasSpan16_Flag) { |
|
155 flags |= kConstInY16_Flag; |
|
156 } |
|
157 } |
|
158 |
|
159 fFlags = flags; |
|
160 return true; |
|
161 } |
|
162 |
|
163 void SkBitmapProcShader::endContext() { |
|
164 fState.endContext(); |
|
165 this->INHERITED::endContext(); |
|
166 } |
|
167 |
|
168 #define BUF_MAX 128 |
|
169 |
|
170 #define TEST_BUFFER_OVERRITEx |
|
171 |
|
172 #ifdef TEST_BUFFER_OVERRITE |
|
173 #define TEST_BUFFER_EXTRA 32 |
|
174 #define TEST_PATTERN 0x88888888 |
|
175 #else |
|
176 #define TEST_BUFFER_EXTRA 0 |
|
177 #endif |
|
178 |
|
179 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { |
|
180 const SkBitmapProcState& state = fState; |
|
181 if (state.getShaderProc32()) { |
|
182 state.getShaderProc32()(state, x, y, dstC, count); |
|
183 return; |
|
184 } |
|
185 |
|
186 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; |
|
187 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); |
|
188 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); |
|
189 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); |
|
190 |
|
191 SkASSERT(state.fBitmap->getPixels()); |
|
192 SkASSERT(state.fBitmap->pixelRef() == NULL || |
|
193 state.fBitmap->pixelRef()->isLocked()); |
|
194 |
|
195 for (;;) { |
|
196 int n = count; |
|
197 if (n > max) { |
|
198 n = max; |
|
199 } |
|
200 SkASSERT(n > 0 && n < BUF_MAX*2); |
|
201 #ifdef TEST_BUFFER_OVERRITE |
|
202 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { |
|
203 buffer[BUF_MAX + i] = TEST_PATTERN; |
|
204 } |
|
205 #endif |
|
206 mproc(state, buffer, n, x, y); |
|
207 #ifdef TEST_BUFFER_OVERRITE |
|
208 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { |
|
209 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); |
|
210 } |
|
211 #endif |
|
212 sproc(state, buffer, n, dstC); |
|
213 |
|
214 if ((count -= n) == 0) { |
|
215 break; |
|
216 } |
|
217 SkASSERT(count > 0); |
|
218 x += n; |
|
219 dstC += n; |
|
220 } |
|
221 } |
|
222 |
|
223 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { |
|
224 if (fState.getShaderProc32()) { |
|
225 *ctx = &fState; |
|
226 return (ShadeProc)fState.getShaderProc32(); |
|
227 } |
|
228 return NULL; |
|
229 } |
|
230 |
|
231 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { |
|
232 const SkBitmapProcState& state = fState; |
|
233 if (state.getShaderProc16()) { |
|
234 state.getShaderProc16()(state, x, y, dstC, count); |
|
235 return; |
|
236 } |
|
237 |
|
238 uint32_t buffer[BUF_MAX]; |
|
239 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); |
|
240 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); |
|
241 int max = fState.maxCountForBufferSize(sizeof(buffer)); |
|
242 |
|
243 SkASSERT(state.fBitmap->getPixels()); |
|
244 SkASSERT(state.fBitmap->pixelRef() == NULL || |
|
245 state.fBitmap->pixelRef()->isLocked()); |
|
246 |
|
247 for (;;) { |
|
248 int n = count; |
|
249 if (n > max) { |
|
250 n = max; |
|
251 } |
|
252 mproc(state, buffer, n, x, y); |
|
253 sproc(state, buffer, n, dstC); |
|
254 |
|
255 if ((count -= n) == 0) { |
|
256 break; |
|
257 } |
|
258 x += n; |
|
259 dstC += n; |
|
260 } |
|
261 } |
|
262 |
|
263 /////////////////////////////////////////////////////////////////////////////// |
|
264 |
|
265 #include "SkUnPreMultiply.h" |
|
266 #include "SkColorShader.h" |
|
267 #include "SkEmptyShader.h" |
|
268 |
|
269 // returns true and set color if the bitmap can be drawn as a single color |
|
270 // (for efficiency) |
|
271 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { |
|
272 if (1 != bm.width() || 1 != bm.height()) { |
|
273 return false; |
|
274 } |
|
275 |
|
276 SkAutoLockPixels alp(bm); |
|
277 if (!bm.readyToDraw()) { |
|
278 return false; |
|
279 } |
|
280 |
|
281 switch (bm.colorType()) { |
|
282 case kPMColor_SkColorType: |
|
283 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); |
|
284 return true; |
|
285 case kRGB_565_SkColorType: |
|
286 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); |
|
287 return true; |
|
288 case kIndex_8_SkColorType: |
|
289 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); |
|
290 return true; |
|
291 default: // just skip the other configs for now |
|
292 break; |
|
293 } |
|
294 return false; |
|
295 } |
|
296 |
|
297 static bool bitmapIsTooBig(const SkBitmap& bm) { |
|
298 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it |
|
299 // communicates between its matrix-proc and its sampler-proc. Until we can |
|
300 // widen that, we have to reject bitmaps that are larger. |
|
301 // |
|
302 const int maxSize = 65535; |
|
303 |
|
304 return bm.width() > maxSize || bm.height() > maxSize; |
|
305 } |
|
306 |
|
307 SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, |
|
308 SkShader::TileMode tmy, SkTBlitterAllocator* allocator) { |
|
309 SkShader* shader; |
|
310 SkColor color; |
|
311 if (src.isNull() || bitmapIsTooBig(src)) { |
|
312 if (NULL == allocator) { |
|
313 shader = SkNEW(SkEmptyShader); |
|
314 } else { |
|
315 shader = allocator->createT<SkEmptyShader>(); |
|
316 } |
|
317 } |
|
318 else if (canUseColorShader(src, &color)) { |
|
319 if (NULL == allocator) { |
|
320 shader = SkNEW_ARGS(SkColorShader, (color)); |
|
321 } else { |
|
322 shader = allocator->createT<SkColorShader>(color); |
|
323 } |
|
324 } else { |
|
325 if (NULL == allocator) { |
|
326 shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy)); |
|
327 } else { |
|
328 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy); |
|
329 } |
|
330 } |
|
331 return shader; |
|
332 } |
|
333 |
|
334 /////////////////////////////////////////////////////////////////////////////// |
|
335 |
|
336 #ifndef SK_IGNORE_TO_STRING |
|
337 void SkBitmapProcShader::toString(SkString* str) const { |
|
338 static const char* gTileModeName[SkShader::kTileModeCount] = { |
|
339 "clamp", "repeat", "mirror" |
|
340 }; |
|
341 |
|
342 str->append("BitmapShader: ("); |
|
343 |
|
344 str->appendf("(%s, %s)", |
|
345 gTileModeName[fState.fTileModeX], |
|
346 gTileModeName[fState.fTileModeY]); |
|
347 |
|
348 str->append(" "); |
|
349 fRawBitmap.toString(str); |
|
350 |
|
351 this->INHERITED::toString(str); |
|
352 |
|
353 str->append(")"); |
|
354 } |
|
355 #endif |
|
356 |
|
357 /////////////////////////////////////////////////////////////////////////////// |
|
358 |
|
359 #if SK_SUPPORT_GPU |
|
360 |
|
361 #include "GrTextureAccess.h" |
|
362 #include "effects/GrSimpleTextureEffect.h" |
|
363 #include "SkGr.h" |
|
364 |
|
365 // Note that this will return -1 if either matrix is perspective. |
|
366 static SkScalar get_combined_min_stretch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) { |
|
367 if (localMatrix.isIdentity()) { |
|
368 return viewMatrix.getMinStretch(); |
|
369 } else { |
|
370 SkMatrix combined; |
|
371 combined.setConcat(viewMatrix, localMatrix); |
|
372 return combined.getMinStretch(); |
|
373 } |
|
374 } |
|
375 |
|
376 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const { |
|
377 SkMatrix matrix; |
|
378 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); |
|
379 |
|
380 SkMatrix lmInverse; |
|
381 if (!this->getLocalMatrix().invert(&lmInverse)) { |
|
382 return NULL; |
|
383 } |
|
384 matrix.preConcat(lmInverse); |
|
385 |
|
386 SkShader::TileMode tm[] = { |
|
387 (TileMode)fState.fTileModeX, |
|
388 (TileMode)fState.fTileModeY, |
|
389 }; |
|
390 |
|
391 // Must set wrap and filter on the sampler before requesting a texture. In two places below |
|
392 // we check the matrix scale factors to determine how to interpret the filter quality setting. |
|
393 // This completely ignores the complexity of the drawVertices case where explicit local coords |
|
394 // are provided by the caller. |
|
395 SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel(); |
|
396 GrTextureParams::FilterMode textureFilterMode; |
|
397 switch(paintFilterLevel) { |
|
398 case SkPaint::kNone_FilterLevel: |
|
399 textureFilterMode = GrTextureParams::kNone_FilterMode; |
|
400 break; |
|
401 case SkPaint::kLow_FilterLevel: |
|
402 textureFilterMode = GrTextureParams::kBilerp_FilterMode; |
|
403 break; |
|
404 case SkPaint::kMedium_FilterLevel: |
|
405 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) < |
|
406 SK_Scalar1) { |
|
407 textureFilterMode = GrTextureParams::kMipMap_FilterMode; |
|
408 } else { |
|
409 // Don't trigger MIP level generation unnecessarily. |
|
410 textureFilterMode = GrTextureParams::kBilerp_FilterMode; |
|
411 } |
|
412 break; |
|
413 case SkPaint::kHigh_FilterLevel: |
|
414 // Minification can look bad with bicubic filtering. |
|
415 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) >= |
|
416 SK_Scalar1) { |
|
417 // fall back to no filtering here; we will install another shader that will do the |
|
418 // HQ filtering. |
|
419 textureFilterMode = GrTextureParams::kNone_FilterMode; |
|
420 } else { |
|
421 // Fall back to MIP-mapping. |
|
422 paintFilterLevel = SkPaint::kMedium_FilterLevel; |
|
423 textureFilterMode = GrTextureParams::kMipMap_FilterMode; |
|
424 } |
|
425 break; |
|
426 default: |
|
427 SkErrorInternals::SetError( kInvalidPaint_SkError, |
|
428 "Sorry, I don't understand the filtering " |
|
429 "mode you asked for. Falling back to " |
|
430 "MIPMaps."); |
|
431 textureFilterMode = GrTextureParams::kMipMap_FilterMode; |
|
432 break; |
|
433 |
|
434 } |
|
435 GrTextureParams params(tm, textureFilterMode); |
|
436 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms); |
|
437 |
|
438 if (NULL == texture) { |
|
439 SkErrorInternals::SetError( kInternalError_SkError, |
|
440 "Couldn't convert bitmap to texture."); |
|
441 return NULL; |
|
442 } |
|
443 |
|
444 GrEffectRef* effect = NULL; |
|
445 if (paintFilterLevel == SkPaint::kHigh_FilterLevel) { |
|
446 effect = GrBicubicEffect::Create(texture, matrix, tm); |
|
447 } else { |
|
448 effect = GrSimpleTextureEffect::Create(texture, matrix, params); |
|
449 } |
|
450 GrUnlockAndUnrefCachedBitmapTexture(texture); |
|
451 return effect; |
|
452 } |
|
453 #endif |