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 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 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 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 50 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 66 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 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 79 bool SkBitmapProcShader::isOpaque() const { 80 return fRawBitmap.isOpaque(); 81 } 82 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 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 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 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 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 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) 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 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 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 329 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 357 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, ¶ms); 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