• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkFlattenableBuffers.h"
10 #include "SkPixelRef.h"
11 #include "SkErrorInternals.h"
12 #include "SkBitmapProcShader.h"
13 
14 #if SK_SUPPORT_GPU
15 #include "effects/GrSimpleTextureEffect.h"
16 #include "effects/GrBicubicEffect.h"
17 #endif
18 
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)19 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
20     switch (bm.config()) {
21         case SkBitmap::kA8_Config:
22         case SkBitmap::kRGB_565_Config:
23         case SkBitmap::kIndex8_Config:
24         case SkBitmap::kARGB_8888_Config:
25     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
26                 return true;
27         default:
28             break;
29     }
30     return false;
31 }
32 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy)33 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
34                                        TileMode tmx, TileMode tmy) {
35     fRawBitmap = src;
36     fState.fTileModeX = (uint8_t)tmx;
37     fState.fTileModeY = (uint8_t)tmy;
38     fFlags = 0; // computed in setContext
39 }
40 
SkBitmapProcShader(SkFlattenableReadBuffer & buffer)41 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
42         : INHERITED(buffer) {
43     buffer.readBitmap(&fRawBitmap);
44     fRawBitmap.setImmutable();
45     fState.fTileModeX = buffer.readUInt();
46     fState.fTileModeY = buffer.readUInt();
47     fFlags = 0; // computed in setContext
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)fState.fTileModeX;
61         xy[1] = (TileMode)fState.fTileModeY;
62     }
63     return kDefault_BitmapType;
64 }
65 
flatten(SkFlattenableWriteBuffer & buffer) const66 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
67     this->INHERITED::flatten(buffer);
68 
69     buffer.writeBitmap(fRawBitmap);
70     buffer.writeUInt(fState.fTileModeX);
71     buffer.writeUInt(fState.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 (SkBitmap::kIndex8_Config == bm.config()) {
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 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)100 bool SkBitmapProcShader::setContext(const SkBitmap& device,
101                                     const SkPaint& paint,
102                                     const SkMatrix& matrix) {
103     if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
104         return false;
105     }
106 
107     // do this first, so we have a correct inverse matrix
108     if (!this->INHERITED::setContext(device, paint, matrix)) {
109         return false;
110     }
111 
112     fState.fOrigBitmap = fRawBitmap;
113     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
114         this->INHERITED::endContext();
115         return false;
116     }
117 
118     const SkBitmap& bitmap = *fState.fBitmap;
119     bool bitmapIsOpaque = bitmap.isOpaque();
120 
121     // update fFlags
122     uint32_t flags = 0;
123     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
124         flags |= kOpaqueAlpha_Flag;
125     }
126 
127     switch (bitmap.config()) {
128         case SkBitmap::kRGB_565_Config:
129             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
130             break;
131         case SkBitmap::kIndex8_Config:
132         case SkBitmap::kARGB_8888_Config:
133             if (bitmapIsOpaque) {
134                 flags |= kHasSpan16_Flag;
135             }
136             break;
137         case SkBitmap::kA8_Config:
138             break;  // never set kHasSpan16_Flag
139         default:
140             break;
141     }
142 
143     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
144         // gradients can auto-dither in their 16bit sampler, but we don't so
145         // we clear the flag here.
146         flags &= ~kHasSpan16_Flag;
147     }
148 
149     // if we're only 1-pixel high, and we don't rotate, then we can claim this
150     if (1 == bitmap.height() &&
151             only_scale_and_translate(this->getTotalInverse())) {
152         flags |= kConstInY32_Flag;
153         if (flags & kHasSpan16_Flag) {
154             flags |= kConstInY16_Flag;
155         }
156     }
157 
158     fFlags = flags;
159     return true;
160 }
161 
endContext()162 void SkBitmapProcShader::endContext() {
163     fState.endContext();
164     this->INHERITED::endContext();
165 }
166 
167 #define BUF_MAX     128
168 
169 #define TEST_BUFFER_OVERRITEx
170 
171 #ifdef TEST_BUFFER_OVERRITE
172     #define TEST_BUFFER_EXTRA   32
173     #define TEST_PATTERN    0x88888888
174 #else
175     #define TEST_BUFFER_EXTRA   0
176 #endif
177 
shadeSpan(int x,int y,SkPMColor dstC[],int count)178 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
179     const SkBitmapProcState& state = fState;
180     if (state.getShaderProc32()) {
181         state.getShaderProc32()(state, x, y, dstC, count);
182         return;
183     }
184 
185     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
186     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
187     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
188     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
189 
190     SkASSERT(state.fBitmap->getPixels());
191     SkASSERT(state.fBitmap->pixelRef() == NULL ||
192              state.fBitmap->pixelRef()->isLocked());
193 
194     for (;;) {
195         int n = count;
196         if (n > max) {
197             n = max;
198         }
199         SkASSERT(n > 0 && n < BUF_MAX*2);
200 #ifdef TEST_BUFFER_OVERRITE
201         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
202             buffer[BUF_MAX + i] = TEST_PATTERN;
203         }
204 #endif
205         mproc(state, buffer, n, x, y);
206 #ifdef TEST_BUFFER_OVERRITE
207         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
208             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
209         }
210 #endif
211         sproc(state, buffer, n, dstC);
212 
213         if ((count -= n) == 0) {
214             break;
215         }
216         SkASSERT(count > 0);
217         x += n;
218         dstC += n;
219     }
220 }
221 
asAShadeProc(void ** ctx)222 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
223     if (fState.getShaderProc32()) {
224         *ctx = &fState;
225         return (ShadeProc)fState.getShaderProc32();
226     }
227     return NULL;
228 }
229 
shadeSpan16(int x,int y,uint16_t dstC[],int count)230 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
231     const SkBitmapProcState& state = fState;
232     if (state.getShaderProc16()) {
233         state.getShaderProc16()(state, x, y, dstC, count);
234         return;
235     }
236 
237     uint32_t buffer[BUF_MAX];
238     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
239     SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
240     int max = fState.maxCountForBufferSize(sizeof(buffer));
241 
242     SkASSERT(state.fBitmap->getPixels());
243     SkASSERT(state.fBitmap->pixelRef() == NULL ||
244              state.fBitmap->pixelRef()->isLocked());
245 
246     for (;;) {
247         int n = count;
248         if (n > max) {
249             n = max;
250         }
251         mproc(state, buffer, n, x, y);
252         sproc(state, buffer, n, dstC);
253 
254         if ((count -= n) == 0) {
255             break;
256         }
257         x += n;
258         dstC += n;
259     }
260 }
261 
262 ///////////////////////////////////////////////////////////////////////////////
263 
264 #include "SkUnPreMultiply.h"
265 #include "SkColorShader.h"
266 #include "SkEmptyShader.h"
267 
268 // returns true and set color if the bitmap can be drawn as a single color
269 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)270 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
271     if (1 != bm.width() || 1 != bm.height()) {
272         return false;
273     }
274 
275     SkAutoLockPixels alp(bm);
276     if (!bm.readyToDraw()) {
277         return false;
278     }
279 
280     switch (bm.config()) {
281         case SkBitmap::kARGB_8888_Config:
282             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
283             return true;
284         case SkBitmap::kRGB_565_Config:
285             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
286             return true;
287         case SkBitmap::kIndex8_Config:
288             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
289             return true;
290         default: // just skip the other configs for now
291             break;
292     }
293     return false;
294 }
295 
296 #include "SkTemplatesPriv.h"
297 
bitmapIsTooBig(const SkBitmap & bm)298 static bool bitmapIsTooBig(const SkBitmap& bm) {
299     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
300     // communicates between its matrix-proc and its sampler-proc. Until we can
301     // widen that, we have to reject bitmaps that are larger.
302     //
303     const int maxSize = 65535;
304 
305     return bm.width() > maxSize || bm.height() > maxSize;
306 }
307 
CreateBitmapShader(const SkBitmap & src,TileMode tmx,TileMode tmy,void * storage,size_t storageSize)308 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
309                                        TileMode tmx, TileMode tmy,
310                                        void* storage, size_t storageSize) {
311     SkShader* shader;
312     SkColor color;
313     if (src.isNull() || bitmapIsTooBig(src)) {
314         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
315     }
316     else if (canUseColorShader(src, &color)) {
317         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
318                               (color));
319     } else {
320         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
321                               storageSize, (src, tmx, tmy));
322     }
323     return shader;
324 }
325 
326 ///////////////////////////////////////////////////////////////////////////////
327 
328 #ifdef SK_DEVELOPER
toString(SkString * str) const329 void SkBitmapProcShader::toString(SkString* str) const {
330     static const char* gTileModeName[SkShader::kTileModeCount] = {
331         "clamp", "repeat", "mirror"
332     };
333 
334     str->append("BitmapShader: (");
335 
336     str->appendf("(%s, %s)",
337                  gTileModeName[fState.fTileModeX],
338                  gTileModeName[fState.fTileModeY]);
339 
340     str->append(" ");
341     fRawBitmap.toString(str);
342 
343     this->INHERITED::toString(str);
344 
345     str->append(")");
346 }
347 #endif
348 
349 ///////////////////////////////////////////////////////////////////////////////
350 
351 #if SK_SUPPORT_GPU
352 
353 #include "GrTextureAccess.h"
354 #include "effects/GrSimpleTextureEffect.h"
355 #include "SkGr.h"
356 
asNewEffect(GrContext * context,const SkPaint & paint) const357 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
358     SkMatrix matrix;
359     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
360 
361     SkMatrix inverse;
362     if (!this->getLocalMatrix().invert(&inverse)) {
363         return NULL;
364     }
365     matrix.preConcat(inverse);
366 
367     SkShader::TileMode tm[] = {
368         (TileMode)fState.fTileModeX,
369         (TileMode)fState.fTileModeY,
370     };
371 
372     // Must set wrap and filter on the sampler before requesting a texture.
373     SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
374     GrTextureParams::FilterMode textureFilterMode;
375     switch(paintFilterLevel) {
376         case SkPaint::kNone_FilterLevel:
377             textureFilterMode = GrTextureParams::kNone_FilterMode;
378             break;
379         case SkPaint::kLow_FilterLevel:
380             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
381             break;
382         case SkPaint::kMedium_FilterLevel:
383             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
384             break;
385         case SkPaint::kHigh_FilterLevel:
386             // Minification can look bad with the bicubic effect. This is an overly aggressive
387             // check for MIP fallbacks. It doesn't consider the fact that minification in the local
388             // matrix could be offset by the view matrix and vice versa. We also don't know whether
389             // the draw has explicit local coords (e.g. drawVertices) where the scale factor is
390             // unknown and varies.
391             if (context->getMatrix().getMinStretch() >= SK_Scalar1 &&
392                 this->getLocalMatrix().getMaxStretch() <= SK_Scalar1) {
393                 // fall back to no filtering here; we will install another
394                 // shader that will do the HQ filtering.
395                 textureFilterMode = GrTextureParams::kNone_FilterMode;
396             } else {
397                 // Fall back to mip-mapping.
398                 paintFilterLevel = SkPaint::kMedium_FilterLevel;
399                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
400             }
401             break;
402         default:
403             SkErrorInternals::SetError( kInvalidPaint_SkError,
404                                         "Sorry, I don't understand the filtering "
405                                         "mode you asked for.  Falling back to "
406                                         "MIPMaps.");
407             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
408             break;
409 
410     }
411     GrTextureParams params(tm, textureFilterMode);
412     GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
413 
414     if (NULL == texture) {
415         SkErrorInternals::SetError( kInternalError_SkError,
416                                     "Couldn't convert bitmap to texture.");
417         return NULL;
418     }
419 
420     GrEffectRef* effect = NULL;
421     if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
422         effect = GrBicubicEffect::Create(texture, matrix, tm);
423     } else {
424         effect = GrSimpleTextureEffect::Create(texture, matrix, params);
425     }
426     GrUnlockAndUnrefCachedBitmapTexture(texture);
427     return effect;
428 }
429 #endif
430