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