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
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)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 kN32_SkColorType:
26 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
27 return true;
28 default:
29 break;
30 }
31 return false;
32 }
33
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy,const SkMatrix * localMatrix)34 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
35 const SkMatrix* localMatrix)
36 : INHERITED(localMatrix) {
37 fRawBitmap = src;
38 fTileModeX = (uint8_t)tmx;
39 fTileModeY = (uint8_t)tmy;
40 }
41
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const42 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
43 SkMatrix* texM,
44 TileMode xy[]) const {
45 if (texture) {
46 *texture = fRawBitmap;
47 }
48 if (texM) {
49 texM->reset();
50 }
51 if (xy) {
52 xy[0] = (TileMode)fTileModeX;
53 xy[1] = (TileMode)fTileModeY;
54 }
55 return kDefault_BitmapType;
56 }
57
CreateProc(SkReadBuffer & buffer)58 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
59 SkMatrix lm;
60 buffer.readMatrix(&lm);
61 SkBitmap bm;
62 if (!buffer.readBitmap(&bm)) {
63 return NULL;
64 }
65 bm.setImmutable();
66 TileMode mx = (TileMode)buffer.readUInt();
67 TileMode my = (TileMode)buffer.readUInt();
68 return SkShader::CreateBitmapShader(bm, mx, my, &lm);
69 }
70
flatten(SkWriteBuffer & buffer) const71 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
72 buffer.writeMatrix(this->getLocalMatrix());
73 buffer.writeBitmap(fRawBitmap);
74 buffer.writeUInt(fTileModeX);
75 buffer.writeUInt(fTileModeY);
76 }
77
only_scale_and_translate(const SkMatrix & matrix)78 static bool only_scale_and_translate(const SkMatrix& matrix) {
79 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
80 return (matrix.getType() & ~mask) == 0;
81 }
82
isOpaque() const83 bool SkBitmapProcShader::isOpaque() const {
84 return fRawBitmap.isOpaque();
85 }
86
onCreateContext(const ContextRec & rec,void * storage) const87 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
88 SkMatrix totalInverse;
89 // Do this first, so we know the matrix can be inverted.
90 if (!this->computeTotalInverse(rec, &totalInverse)) {
91 return NULL;
92 }
93
94 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
95 SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
96
97 SkASSERT(state);
98 state->fTileModeX = fTileModeX;
99 state->fTileModeY = fTileModeY;
100 state->fOrigBitmap = fRawBitmap;
101 if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
102 state->~SkBitmapProcState();
103 return NULL;
104 }
105
106 return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, (*this, rec, state));
107 }
108
contextSize() const109 size_t SkBitmapProcShader::contextSize() const {
110 // The SkBitmapProcState is stored outside of the context object, with the context holding
111 // a pointer to it.
112 return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
113 }
114
BitmapProcShaderContext(const SkBitmapProcShader & shader,const ContextRec & rec,SkBitmapProcState * state)115 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
116 const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state)
117 : INHERITED(shader, rec)
118 , fState(state)
119 {
120 const SkBitmap& bitmap = *fState->fBitmap;
121 bool bitmapIsOpaque = bitmap.isOpaque();
122
123 // update fFlags
124 uint32_t flags = 0;
125 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
126 flags |= kOpaqueAlpha_Flag;
127 }
128
129 switch (bitmap.colorType()) {
130 case kRGB_565_SkColorType:
131 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
132 break;
133 case kIndex_8_SkColorType:
134 case kN32_SkColorType:
135 if (bitmapIsOpaque) {
136 flags |= kHasSpan16_Flag;
137 }
138 break;
139 case kAlpha_8_SkColorType:
140 break; // never set kHasSpan16_Flag
141 default:
142 break;
143 }
144
145 if (rec.fPaint->isDither() && bitmap.colorType() != kRGB_565_SkColorType) {
146 // gradients can auto-dither in their 16bit sampler, but we don't so
147 // we clear the flag here.
148 flags &= ~kHasSpan16_Flag;
149 }
150
151 // if we're only 1-pixel high, and we don't rotate, then we can claim this
152 if (1 == bitmap.height() &&
153 only_scale_and_translate(this->getTotalInverse())) {
154 flags |= kConstInY32_Flag;
155 if (flags & kHasSpan16_Flag) {
156 flags |= kConstInY16_Flag;
157 }
158 }
159
160 fFlags = flags;
161 }
162
~BitmapProcShaderContext()163 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
164 // The bitmap proc state has been created outside of the context on memory that will be freed
165 // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
166 fState->~SkBitmapProcState();
167 }
168
169 #define BUF_MAX 128
170
171 #define TEST_BUFFER_OVERRITEx
172
173 #ifdef TEST_BUFFER_OVERRITE
174 #define TEST_BUFFER_EXTRA 32
175 #define TEST_PATTERN 0x88888888
176 #else
177 #define TEST_BUFFER_EXTRA 0
178 #endif
179
shadeSpan(int x,int y,SkPMColor dstC[],int count)180 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
181 int count) {
182 const SkBitmapProcState& state = *fState;
183 if (state.getShaderProc32()) {
184 state.getShaderProc32()(state, x, y, dstC, count);
185 return;
186 }
187
188 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
189 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
190 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
191 int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
192
193 SkASSERT(state.fBitmap->getPixels());
194 SkASSERT(state.fBitmap->pixelRef() == NULL ||
195 state.fBitmap->pixelRef()->isLocked());
196
197 for (;;) {
198 int n = count;
199 if (n > max) {
200 n = max;
201 }
202 SkASSERT(n > 0 && n < BUF_MAX*2);
203 #ifdef TEST_BUFFER_OVERRITE
204 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
205 buffer[BUF_MAX + i] = TEST_PATTERN;
206 }
207 #endif
208 mproc(state, buffer, n, x, y);
209 #ifdef TEST_BUFFER_OVERRITE
210 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
211 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
212 }
213 #endif
214 sproc(state, buffer, n, dstC);
215
216 if ((count -= n) == 0) {
217 break;
218 }
219 SkASSERT(count > 0);
220 x += n;
221 dstC += n;
222 }
223 }
224
asAShadeProc(void ** ctx)225 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
226 if (fState->getShaderProc32()) {
227 *ctx = fState;
228 return (ShadeProc)fState->getShaderProc32();
229 }
230 return NULL;
231 }
232
shadeSpan16(int x,int y,uint16_t dstC[],int count)233 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
234 int count) {
235 const SkBitmapProcState& state = *fState;
236 if (state.getShaderProc16()) {
237 state.getShaderProc16()(state, x, y, dstC, count);
238 return;
239 }
240
241 uint32_t buffer[BUF_MAX];
242 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
243 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
244 int max = state.maxCountForBufferSize(sizeof(buffer));
245
246 SkASSERT(state.fBitmap->getPixels());
247 SkASSERT(state.fBitmap->pixelRef() == NULL ||
248 state.fBitmap->pixelRef()->isLocked());
249
250 for (;;) {
251 int n = count;
252 if (n > max) {
253 n = max;
254 }
255 mproc(state, buffer, n, x, y);
256 sproc(state, buffer, n, dstC);
257
258 if ((count -= n) == 0) {
259 break;
260 }
261 x += n;
262 dstC += n;
263 }
264 }
265
266 ///////////////////////////////////////////////////////////////////////////////
267
268 #include "SkUnPreMultiply.h"
269 #include "SkColorShader.h"
270 #include "SkEmptyShader.h"
271
272 // returns true and set color if the bitmap can be drawn as a single color
273 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)274 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
275 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
276 // Android expects SkShaders constructed from a Bitmap to always be queryable with
277 // SkShader::asABitmap()
278 return false;
279 #endif
280
281 if (1 != bm.width() || 1 != bm.height()) {
282 return false;
283 }
284
285 SkAutoLockPixels alp(bm);
286 if (!bm.readyToDraw()) {
287 return false;
288 }
289
290 switch (bm.colorType()) {
291 case kN32_SkColorType:
292 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
293 return true;
294 case kRGB_565_SkColorType:
295 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
296 return true;
297 case kIndex_8_SkColorType:
298 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
299 return true;
300 default: // just skip the other configs for now
301 break;
302 }
303 return false;
304 }
305
bitmapIsTooBig(const SkBitmap & bm)306 static bool bitmapIsTooBig(const SkBitmap& bm) {
307 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
308 // communicates between its matrix-proc and its sampler-proc. Until we can
309 // widen that, we have to reject bitmaps that are larger.
310 //
311 const int maxSize = 65535;
312
313 return bm.width() > maxSize || bm.height() > maxSize;
314 }
315
SkCreateBitmapShader(const SkBitmap & src,SkShader::TileMode tmx,SkShader::TileMode tmy,const SkMatrix * localMatrix,SkTBlitterAllocator * allocator)316 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
317 SkShader::TileMode tmy, const SkMatrix* localMatrix,
318 SkTBlitterAllocator* allocator) {
319 SkShader* shader;
320 SkColor color;
321 if (src.isNull() || bitmapIsTooBig(src)) {
322 if (NULL == allocator) {
323 shader = SkNEW(SkEmptyShader);
324 } else {
325 shader = allocator->createT<SkEmptyShader>();
326 }
327 }
328 else if (canUseColorShader(src, &color)) {
329 if (NULL == allocator) {
330 shader = SkNEW_ARGS(SkColorShader, (color));
331 } else {
332 shader = allocator->createT<SkColorShader>(color);
333 }
334 } else {
335 if (NULL == allocator) {
336 shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix));
337 } else {
338 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
339 }
340 }
341 return shader;
342 }
343
344 ///////////////////////////////////////////////////////////////////////////////
345
346 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const347 void SkBitmapProcShader::toString(SkString* str) const {
348 static const char* gTileModeName[SkShader::kTileModeCount] = {
349 "clamp", "repeat", "mirror"
350 };
351
352 str->append("BitmapShader: (");
353
354 str->appendf("(%s, %s)",
355 gTileModeName[fTileModeX],
356 gTileModeName[fTileModeY]);
357
358 str->append(" ");
359 fRawBitmap.toString(str);
360
361 this->INHERITED::toString(str);
362
363 str->append(")");
364 }
365 #endif
366
367 ///////////////////////////////////////////////////////////////////////////////
368
369 #if SK_SUPPORT_GPU
370
371 #include "GrTextureAccess.h"
372 #include "effects/GrSimpleTextureEffect.h"
373 #include "SkGr.h"
374
asFragmentProcessor(GrContext * context,const SkPaint & paint,const SkMatrix & viewM,const SkMatrix * localMatrix,GrColor * paintColor,GrFragmentProcessor ** fp) const375 bool SkBitmapProcShader::asFragmentProcessor(GrContext* context, const SkPaint& paint,
376 const SkMatrix& viewM,
377 const SkMatrix* localMatrix, GrColor* paintColor,
378 GrFragmentProcessor** fp) const {
379 SkMatrix matrix;
380 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
381
382 SkMatrix lmInverse;
383 if (!this->getLocalMatrix().invert(&lmInverse)) {
384 return false;
385 }
386 if (localMatrix) {
387 SkMatrix inv;
388 if (!localMatrix->invert(&inv)) {
389 return false;
390 }
391 lmInverse.postConcat(inv);
392 }
393 matrix.preConcat(lmInverse);
394
395 SkShader::TileMode tm[] = {
396 (TileMode)fTileModeX,
397 (TileMode)fTileModeY,
398 };
399
400 // Must set wrap and filter on the sampler before requesting a texture. In two places below
401 // we check the matrix scale factors to determine how to interpret the filter quality setting.
402 // This completely ignores the complexity of the drawVertices case where explicit local coords
403 // are provided by the caller.
404 bool useBicubic = false;
405 GrTextureParams::FilterMode textureFilterMode;
406 switch(paint.getFilterQuality()) {
407 case kNone_SkFilterQuality:
408 textureFilterMode = GrTextureParams::kNone_FilterMode;
409 break;
410 case kLow_SkFilterQuality:
411 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
412 break;
413 case kMedium_SkFilterQuality: {
414 SkMatrix matrix;
415 matrix.setConcat(viewM, this->getLocalMatrix());
416 if (matrix.getMinScale() < SK_Scalar1) {
417 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
418 } else {
419 // Don't trigger MIP level generation unnecessarily.
420 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
421 }
422 break;
423 }
424 case kHigh_SkFilterQuality: {
425 SkMatrix matrix;
426 matrix.setConcat(viewM, this->getLocalMatrix());
427 useBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
428 break;
429 }
430 default:
431 SkErrorInternals::SetError( kInvalidPaint_SkError,
432 "Sorry, I don't understand the filtering "
433 "mode you asked for. Falling back to "
434 "MIPMaps.");
435 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
436 break;
437
438 }
439 GrTextureParams params(tm, textureFilterMode);
440 SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, ¶ms));
441
442 if (!texture) {
443 SkErrorInternals::SetError( kInternalError_SkError,
444 "Couldn't convert bitmap to texture.");
445 return false;
446 }
447
448 *paintColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ?
449 SkColor2GrColor(paint.getColor()) :
450 SkColor2GrColorJustAlpha(paint.getColor());
451
452 if (useBicubic) {
453 *fp = GrBicubicEffect::Create(texture, matrix, tm);
454 } else {
455 *fp = GrSimpleTextureEffect::Create(texture, matrix, params);
456 }
457
458 return true;
459 }
460
461 #else
462
asFragmentProcessor(GrContext *,const SkPaint &,const SkMatrix &,const SkMatrix *,GrColor *,GrFragmentProcessor **) const463 bool SkBitmapProcShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix&,
464 const SkMatrix*, GrColor*,
465 GrFragmentProcessor**) const {
466 SkDEBUGFAIL("Should not call in GPU-less build");
467 return false;
468 }
469
470 #endif
471