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