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