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 13bool 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 27SkBitmapProcShader::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 35SkBitmapProcShader::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 44SkShader::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 60void 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 68static 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 73bool SkBitmapProcShader::isOpaque() const { 74 return fRawBitmap.isOpaque(); 75} 76 77bool 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 143void 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 159void 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 203SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { 204 if (fState.getShaderProc32()) { 205 *ctx = &fState; 206 return (ShadeProc)fState.getShaderProc32(); 207 } 208 return NULL; 209} 210 211void 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) 251static 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 279static 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 289SkShader* 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 310void 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 338GrEffectRef* 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