1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmapProcShader.h"
9 #include "SkBitmapProcState.h"
10 #include "SkBitmapProvider.h"
11 #include "SkColorPriv.h"
12 #include "SkErrorInternals.h"
13 #include "SkPixelRef.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16
17 #if SK_SUPPORT_GPU
18 #include "SkGrPriv.h"
19 #include "effects/GrBicubicEffect.h"
20 #include "effects/GrSimpleTextureEffect.h"
21 #endif
22
ContextSize()23 size_t SkBitmapProcShader::ContextSize() {
24 // The SkBitmapProcState is stored outside of the context object, with the context holding
25 // a pointer to it.
26 return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
27 }
28
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy,const SkMatrix * localMatrix)29 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
30 const SkMatrix* localMatrix)
31 : INHERITED(localMatrix) {
32 fRawBitmap = src;
33 fTileModeX = (uint8_t)tmx;
34 fTileModeY = (uint8_t)tmy;
35 }
36
onIsABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const37 bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
38 if (texture) {
39 *texture = fRawBitmap;
40 }
41 if (texM) {
42 texM->reset();
43 }
44 if (xy) {
45 xy[0] = (TileMode)fTileModeX;
46 xy[1] = (TileMode)fTileModeY;
47 }
48 return true;
49 }
50
CreateProc(SkReadBuffer & buffer)51 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
52 SkMatrix lm;
53 buffer.readMatrix(&lm);
54 SkBitmap bm;
55 if (!buffer.readBitmap(&bm)) {
56 return nullptr;
57 }
58 bm.setImmutable();
59 TileMode mx = (TileMode)buffer.readUInt();
60 TileMode my = (TileMode)buffer.readUInt();
61 return SkShader::CreateBitmapShader(bm, mx, my, &lm);
62 }
63
flatten(SkWriteBuffer & buffer) const64 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
65 buffer.writeMatrix(this->getLocalMatrix());
66 buffer.writeBitmap(fRawBitmap);
67 buffer.writeUInt(fTileModeX);
68 buffer.writeUInt(fTileModeY);
69 }
70
isOpaque() const71 bool SkBitmapProcShader::isOpaque() const {
72 return fRawBitmap.isOpaque();
73 }
74
MakeContext(const SkShader & shader,TileMode tmx,TileMode tmy,const SkBitmapProvider & provider,const ContextRec & rec,void * storage)75 SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
76 TileMode tmx, TileMode tmy,
77 const SkBitmapProvider& provider,
78 const ContextRec& rec, void* storage) {
79 SkMatrix totalInverse;
80 // Do this first, so we know the matrix can be inverted.
81 if (!shader.computeTotalInverse(rec, &totalInverse)) {
82 return nullptr;
83 }
84
85 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
86 SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
87
88 SkASSERT(state);
89 if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
90 state->~SkBitmapProcState();
91 return nullptr;
92 }
93
94 return new (storage) BitmapProcShaderContext(shader, rec, state);
95 }
96
onCreateContext(const ContextRec & rec,void * storage) const97 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
98 return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
99 SkBitmapProvider(fRawBitmap), rec, storage);
100 }
101
only_scale_and_translate(const SkMatrix & matrix)102 static bool only_scale_and_translate(const SkMatrix& matrix) {
103 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
104 return (matrix.getType() & ~mask) == 0;
105 }
106
BitmapProcShaderContext(const SkShader & shader,const ContextRec & rec,SkBitmapProcState * state)107 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader,
108 const ContextRec& rec,
109 SkBitmapProcState* state)
110 : INHERITED(shader, rec)
111 , fState(state)
112 {
113 fFlags = 0;
114 if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
115 fFlags |= kOpaqueAlpha_Flag;
116 }
117
118 if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
119 fFlags |= kConstInY32_Flag;
120 }
121 }
122
~BitmapProcShaderContext()123 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
124 // The bitmap proc state has been created outside of the context on memory that will be freed
125 // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
126 fState->~SkBitmapProcState();
127 }
128
129 #define BUF_MAX 128
130
131 #define TEST_BUFFER_OVERRITEx
132
133 #ifdef TEST_BUFFER_OVERRITE
134 #define TEST_BUFFER_EXTRA 32
135 #define TEST_PATTERN 0x88888888
136 #else
137 #define TEST_BUFFER_EXTRA 0
138 #endif
139
shadeSpan(int x,int y,SkPMColor dstC[],int count)140 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
141 int count) {
142 const SkBitmapProcState& state = *fState;
143 if (state.getShaderProc32()) {
144 state.getShaderProc32()(&state, x, y, dstC, count);
145 return;
146 }
147
148 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
149 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
150 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
151 int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
152
153 SkASSERT(state.fPixmap.addr());
154
155 for (;;) {
156 int n = count;
157 if (n > max) {
158 n = max;
159 }
160 SkASSERT(n > 0 && n < BUF_MAX*2);
161 #ifdef TEST_BUFFER_OVERRITE
162 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
163 buffer[BUF_MAX + i] = TEST_PATTERN;
164 }
165 #endif
166 mproc(state, buffer, n, x, y);
167 #ifdef TEST_BUFFER_OVERRITE
168 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
169 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
170 }
171 #endif
172 sproc(state, buffer, n, dstC);
173
174 if ((count -= n) == 0) {
175 break;
176 }
177 SkASSERT(count > 0);
178 x += n;
179 dstC += n;
180 }
181 }
182
asAShadeProc(void ** ctx)183 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
184 if (fState->getShaderProc32()) {
185 *ctx = fState;
186 return (ShadeProc)fState->getShaderProc32();
187 }
188 return nullptr;
189 }
190
191 ///////////////////////////////////////////////////////////////////////////////
192
193 #include "SkUnPreMultiply.h"
194 #include "SkColorShader.h"
195 #include "SkEmptyShader.h"
196
197 // returns true and set color if the bitmap can be drawn as a single color
198 // (for efficiency)
can_use_color_shader(const SkBitmap & bm,SkColor * color)199 static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
200 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
201 // HWUI does not support color shaders (see b/22390304)
202 return false;
203 #endif
204
205 if (1 != bm.width() || 1 != bm.height()) {
206 return false;
207 }
208
209 SkAutoLockPixels alp(bm);
210 if (!bm.readyToDraw()) {
211 return false;
212 }
213
214 switch (bm.colorType()) {
215 case kN32_SkColorType:
216 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
217 return true;
218 case kRGB_565_SkColorType:
219 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
220 return true;
221 case kIndex_8_SkColorType:
222 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
223 return true;
224 default: // just skip the other configs for now
225 break;
226 }
227 return false;
228 }
229
bitmap_is_too_big(const SkBitmap & bm)230 static bool bitmap_is_too_big(const SkBitmap& bm) {
231 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
232 // communicates between its matrix-proc and its sampler-proc. Until we can
233 // widen that, we have to reject bitmaps that are larger.
234 //
235 static const int kMaxSize = 65535;
236
237 return bm.width() > kMaxSize || bm.height() > kMaxSize;
238 }
239
SkCreateBitmapShader(const SkBitmap & src,SkShader::TileMode tmx,SkShader::TileMode tmy,const SkMatrix * localMatrix,SkTBlitterAllocator * allocator)240 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
241 SkShader::TileMode tmy, const SkMatrix* localMatrix,
242 SkTBlitterAllocator* allocator) {
243 SkShader* shader;
244 SkColor color;
245 if (src.isNull() || bitmap_is_too_big(src)) {
246 if (nullptr == allocator) {
247 shader = new SkEmptyShader;
248 } else {
249 shader = allocator->createT<SkEmptyShader>();
250 }
251 } else if (can_use_color_shader(src, &color)) {
252 if (nullptr == allocator) {
253 shader = new SkColorShader(color);
254 } else {
255 shader = allocator->createT<SkColorShader>(color);
256 }
257 } else {
258 if (nullptr == allocator) {
259 shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
260 } else {
261 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
262 }
263 }
264 return shader;
265 }
266
267 ///////////////////////////////////////////////////////////////////////////////
268
269 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const270 void SkBitmapProcShader::toString(SkString* str) const {
271 static const char* gTileModeName[SkShader::kTileModeCount] = {
272 "clamp", "repeat", "mirror"
273 };
274
275 str->append("BitmapShader: (");
276
277 str->appendf("(%s, %s)",
278 gTileModeName[fTileModeX],
279 gTileModeName[fTileModeY]);
280
281 str->append(" ");
282 fRawBitmap.toString(str);
283
284 this->INHERITED::toString(str);
285
286 str->append(")");
287 }
288 #endif
289
290 ///////////////////////////////////////////////////////////////////////////////
291
292 #if SK_SUPPORT_GPU
293
294 #include "GrTextureAccess.h"
295 #include "SkGr.h"
296 #include "effects/GrSimpleTextureEffect.h"
297
asFragmentProcessor(GrContext * context,const SkMatrix & viewM,const SkMatrix * localMatrix,SkFilterQuality filterQuality) const298 const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
299 const SkMatrix& viewM, const SkMatrix* localMatrix,
300 SkFilterQuality filterQuality) const {
301 SkMatrix matrix;
302 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
303
304 SkMatrix lmInverse;
305 if (!this->getLocalMatrix().invert(&lmInverse)) {
306 return nullptr;
307 }
308 if (localMatrix) {
309 SkMatrix inv;
310 if (!localMatrix->invert(&inv)) {
311 return nullptr;
312 }
313 lmInverse.postConcat(inv);
314 }
315 matrix.preConcat(lmInverse);
316
317 SkShader::TileMode tm[] = {
318 (TileMode)fTileModeX,
319 (TileMode)fTileModeY,
320 };
321
322 // Must set wrap and filter on the sampler before requesting a texture. In two places below
323 // we check the matrix scale factors to determine how to interpret the filter quality setting.
324 // This completely ignores the complexity of the drawVertices case where explicit local coords
325 // are provided by the caller.
326 bool doBicubic;
327 GrTextureParams::FilterMode textureFilterMode =
328 GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
329 &doBicubic);
330 GrTextureParams params(tm, textureFilterMode);
331 SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));
332
333 if (!texture) {
334 SkErrorInternals::SetError( kInternalError_SkError,
335 "Couldn't convert bitmap to texture.");
336 return nullptr;
337 }
338
339 SkAutoTUnref<const GrFragmentProcessor> inner;
340 if (doBicubic) {
341 inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
342 } else {
343 inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
344 }
345
346 if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
347 return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
348 }
349 return GrFragmentProcessor::MulOutputByInputAlpha(inner);
350 }
351
352 #endif
353