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 "SkBitmapProcShader.h"
9 #include "SkColorPriv.h"
10 #include "SkFlattenableBuffers.h"
11 #include "SkPixelRef.h"
12
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)13 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
14 switch (bm.config()) {
15 case SkBitmap::kA8_Config:
16 case SkBitmap::kRGB_565_Config:
17 case SkBitmap::kIndex8_Config:
18 case SkBitmap::kARGB_8888_Config:
19 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
20 return true;
21 default:
22 break;
23 }
24 return false;
25 }
26
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy)27 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
28 TileMode tmx, TileMode tmy) {
29 fRawBitmap = src;
30 fState.fTileModeX = (uint8_t)tmx;
31 fState.fTileModeY = (uint8_t)tmy;
32 fFlags = 0; // computed in setContext
33 }
34
SkBitmapProcShader(SkFlattenableReadBuffer & buffer)35 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
36 : INHERITED(buffer) {
37 buffer.readBitmap(&fRawBitmap);
38 fRawBitmap.setImmutable();
39 fState.fTileModeX = buffer.readUInt();
40 fState.fTileModeY = buffer.readUInt();
41 fFlags = 0; // computed in setContext
42 }
43
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const44 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
45 SkMatrix* texM,
46 TileMode xy[]) const {
47 if (texture) {
48 *texture = fRawBitmap;
49 }
50 if (texM) {
51 texM->reset();
52 }
53 if (xy) {
54 xy[0] = (TileMode)fState.fTileModeX;
55 xy[1] = (TileMode)fState.fTileModeY;
56 }
57 return kDefault_BitmapType;
58 }
59
flatten(SkFlattenableWriteBuffer & buffer) const60 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
61 this->INHERITED::flatten(buffer);
62
63 buffer.writeBitmap(fRawBitmap);
64 buffer.writeUInt(fState.fTileModeX);
65 buffer.writeUInt(fState.fTileModeY);
66 }
67
only_scale_and_translate(const SkMatrix & matrix)68 static bool only_scale_and_translate(const SkMatrix& matrix) {
69 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
70 return (matrix.getType() & ~mask) == 0;
71 }
72
isOpaque() const73 bool SkBitmapProcShader::isOpaque() const {
74 return fRawBitmap.isOpaque();
75 }
76
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)77 bool SkBitmapProcShader::setContext(const SkBitmap& device,
78 const SkPaint& paint,
79 const SkMatrix& matrix) {
80 // do this first, so we have a correct inverse matrix
81 if (!this->INHERITED::setContext(device, paint, matrix)) {
82 return false;
83 }
84
85 fState.fOrigBitmap = fRawBitmap;
86 fState.fOrigBitmap.lockPixels();
87 if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
88 fState.fOrigBitmap.unlockPixels();
89 this->INHERITED::endContext();
90 return false;
91 }
92
93 if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
94 fState.fOrigBitmap.unlockPixels();
95 this->INHERITED::endContext();
96 return false;
97 }
98
99 const SkBitmap& bitmap = *fState.fBitmap;
100 bool bitmapIsOpaque = bitmap.isOpaque();
101
102 // update fFlags
103 uint32_t flags = 0;
104 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
105 flags |= kOpaqueAlpha_Flag;
106 }
107
108 switch (bitmap.config()) {
109 case SkBitmap::kRGB_565_Config:
110 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
111 break;
112 case SkBitmap::kIndex8_Config:
113 case SkBitmap::kARGB_8888_Config:
114 if (bitmapIsOpaque) {
115 flags |= kHasSpan16_Flag;
116 }
117 break;
118 case SkBitmap::kA8_Config:
119 break; // never set kHasSpan16_Flag
120 default:
121 break;
122 }
123
124 if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
125 // gradients can auto-dither in their 16bit sampler, but we don't so
126 // we clear the flag here.
127 flags &= ~kHasSpan16_Flag;
128 }
129
130 // if we're only 1-pixel high, and we don't rotate, then we can claim this
131 if (1 == bitmap.height() &&
132 only_scale_and_translate(this->getTotalInverse())) {
133 flags |= kConstInY32_Flag;
134 if (flags & kHasSpan16_Flag) {
135 flags |= kConstInY16_Flag;
136 }
137 }
138
139 fFlags = flags;
140 return true;
141 }
142
endContext()143 void SkBitmapProcShader::endContext() {
144 fState.fOrigBitmap.unlockPixels();
145 this->INHERITED::endContext();
146 }
147
148 #define BUF_MAX 128
149
150 #define TEST_BUFFER_OVERRITEx
151
152 #ifdef TEST_BUFFER_OVERRITE
153 #define TEST_BUFFER_EXTRA 32
154 #define TEST_PATTERN 0x88888888
155 #else
156 #define TEST_BUFFER_EXTRA 0
157 #endif
158
shadeSpan(int x,int y,SkPMColor dstC[],int count)159 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
160 const SkBitmapProcState& state = fState;
161 if (state.getShaderProc32()) {
162 state.getShaderProc32()(state, x, y, dstC, count);
163 return;
164 }
165
166 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
167 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
168 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
169 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
170
171 SkASSERT(state.fBitmap->getPixels());
172 SkASSERT(state.fBitmap->pixelRef() == NULL ||
173 state.fBitmap->pixelRef()->isLocked());
174
175 for (;;) {
176 int n = count;
177 if (n > max) {
178 n = max;
179 }
180 SkASSERT(n > 0 && n < BUF_MAX*2);
181 #ifdef TEST_BUFFER_OVERRITE
182 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
183 buffer[BUF_MAX + i] = TEST_PATTERN;
184 }
185 #endif
186 mproc(state, buffer, n, x, y);
187 #ifdef TEST_BUFFER_OVERRITE
188 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
189 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
190 }
191 #endif
192 sproc(state, buffer, n, dstC);
193
194 if ((count -= n) == 0) {
195 break;
196 }
197 SkASSERT(count > 0);
198 x += n;
199 dstC += n;
200 }
201 }
202
asAShadeProc(void ** ctx)203 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
204 if (fState.getShaderProc32()) {
205 *ctx = &fState;
206 return (ShadeProc)fState.getShaderProc32();
207 }
208 return NULL;
209 }
210
shadeSpan16(int x,int y,uint16_t dstC[],int count)211 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
212 const SkBitmapProcState& state = fState;
213 if (state.getShaderProc16()) {
214 state.getShaderProc16()(state, x, y, dstC, count);
215 return;
216 }
217
218 uint32_t buffer[BUF_MAX];
219 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
220 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
221 int max = fState.maxCountForBufferSize(sizeof(buffer));
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 mproc(state, buffer, n, x, y);
233 sproc(state, buffer, n, dstC);
234
235 if ((count -= n) == 0) {
236 break;
237 }
238 x += n;
239 dstC += n;
240 }
241 }
242
243 ///////////////////////////////////////////////////////////////////////////////
244
245 #include "SkUnPreMultiply.h"
246 #include "SkColorShader.h"
247 #include "SkEmptyShader.h"
248
249 // returns true and set color if the bitmap can be drawn as a single color
250 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)251 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
252 if (1 != bm.width() || 1 != bm.height()) {
253 return false;
254 }
255
256 SkAutoLockPixels alp(bm);
257 if (!bm.readyToDraw()) {
258 return false;
259 }
260
261 switch (bm.config()) {
262 case SkBitmap::kARGB_8888_Config:
263 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
264 return true;
265 case SkBitmap::kRGB_565_Config:
266 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
267 return true;
268 case SkBitmap::kIndex8_Config:
269 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
270 return true;
271 default: // just skip the other configs for now
272 break;
273 }
274 return false;
275 }
276
277 #include "SkTemplatesPriv.h"
278
bitmapIsTooBig(const SkBitmap & bm)279 static bool bitmapIsTooBig(const SkBitmap& bm) {
280 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
281 // communicates between its matrix-proc and its sampler-proc. Until we can
282 // widen that, we have to reject bitmaps that are larger.
283 //
284 const int maxSize = 65535;
285
286 return bm.width() > maxSize || bm.height() > maxSize;
287 }
288
CreateBitmapShader(const SkBitmap & src,TileMode tmx,TileMode tmy,void * storage,size_t storageSize)289 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
290 TileMode tmx, TileMode tmy,
291 void* storage, size_t storageSize) {
292 SkShader* shader;
293 SkColor color;
294 if (src.isNull() || bitmapIsTooBig(src)) {
295 SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
296 }
297 else if (canUseColorShader(src, &color)) {
298 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
299 (color));
300 } else {
301 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
302 storageSize, (src, tmx, tmy));
303 }
304 return shader;
305 }
306
307 ///////////////////////////////////////////////////////////////////////////////
308
309 #ifdef SK_DEVELOPER
toString(SkString * str) const310 void SkBitmapProcShader::toString(SkString* str) const {
311 static const char* gTileModeName[SkShader::kTileModeCount] = {
312 "clamp", "repeat", "mirror"
313 };
314
315 str->append("BitmapShader: (");
316
317 str->appendf("(%s, %s)",
318 gTileModeName[fState.fTileModeX],
319 gTileModeName[fState.fTileModeY]);
320
321 str->append(" ");
322 fRawBitmap.toString(str);
323
324 this->INHERITED::toString(str);
325
326 str->append(")");
327 }
328 #endif
329
330 ///////////////////////////////////////////////////////////////////////////////
331
332 #if SK_SUPPORT_GPU
333
334 #include "GrTextureAccess.h"
335 #include "effects/GrSimpleTextureEffect.h"
336 #include "SkGr.h"
337
asNewEffect(GrContext * context,const SkPaint & paint) const338 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
339 SkMatrix matrix;
340 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
341
342 if (this->hasLocalMatrix()) {
343 SkMatrix inverse;
344 if (!this->getLocalMatrix().invert(&inverse)) {
345 return NULL;
346 }
347 matrix.preConcat(inverse);
348 }
349 SkShader::TileMode tm[] = {
350 (TileMode)fState.fTileModeX,
351 (TileMode)fState.fTileModeY,
352 };
353
354 // Must set wrap and filter on the sampler before requesting a texture.
355 GrTextureParams params(tm, paint.isFilterBitmap());
356 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms);
357
358 if (NULL == texture) {
359 SkDebugf("Couldn't convert bitmap to texture.\n");
360 return NULL;
361 }
362
363 GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
364 GrUnlockAndUnrefCachedBitmapTexture(texture);
365 return effect;
366 }
367 #endif
368