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 "SkReadBuffer.h" 10 #include "SkWriteBuffer.h" 11 #include "SkPixelRef.h" 12 #include "SkErrorInternals.h" 13 #include "SkBitmapProcShader.h" 14 15 #if SK_SUPPORT_GPU 16 #include "effects/GrSimpleTextureEffect.h" 17 #include "effects/GrBicubicEffect.h" 18 #endif 19 20 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { 21 switch (bm.colorType()) { 22 case kAlpha_8_SkColorType: 23 case kRGB_565_SkColorType: 24 case kIndex_8_SkColorType: 25 case kN32_SkColorType: 26 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) 27 return true; 28 default: 29 break; 30 } 31 return false; 32 } 33 34 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 35 const SkMatrix* localMatrix) 36 : INHERITED(localMatrix) { 37 fRawBitmap = src; 38 fTileModeX = (uint8_t)tmx; 39 fTileModeY = (uint8_t)tmy; 40 } 41 42 SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer) 43 : INHERITED(buffer) { 44 buffer.readBitmap(&fRawBitmap); 45 fRawBitmap.setImmutable(); 46 fTileModeX = buffer.readUInt(); 47 fTileModeY = buffer.readUInt(); 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)fTileModeX; 61 xy[1] = (TileMode)fTileModeY; 62 } 63 return kDefault_BitmapType; 64 } 65 66 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { 67 this->INHERITED::flatten(buffer); 68 69 buffer.writeBitmap(fRawBitmap); 70 buffer.writeUInt(fTileModeX); 71 buffer.writeUInt(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 (kIndex_8_SkColorType == bm.colorType()) { 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 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const { 101 if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) { 102 return NULL; 103 } 104 105 SkMatrix totalInverse; 106 // Do this first, so we know the matrix can be inverted. 107 if (!this->computeTotalInverse(rec, &totalInverse)) { 108 return NULL; 109 } 110 111 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); 112 SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState); 113 114 SkASSERT(state); 115 state->fTileModeX = fTileModeX; 116 state->fTileModeY = fTileModeY; 117 state->fOrigBitmap = fRawBitmap; 118 if (!state->chooseProcs(totalInverse, *rec.fPaint)) { 119 state->~SkBitmapProcState(); 120 return NULL; 121 } 122 123 return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, (*this, rec, state)); 124 } 125 126 size_t SkBitmapProcShader::contextSize() const { 127 // The SkBitmapProcState is stored outside of the context object, with the context holding 128 // a pointer to it. 129 return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); 130 } 131 132 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext( 133 const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state) 134 : INHERITED(shader, rec) 135 , fState(state) 136 { 137 const SkBitmap& bitmap = *fState->fBitmap; 138 bool bitmapIsOpaque = bitmap.isOpaque(); 139 140 // update fFlags 141 uint32_t flags = 0; 142 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 143 flags |= kOpaqueAlpha_Flag; 144 } 145 146 switch (bitmap.colorType()) { 147 case kRGB_565_SkColorType: 148 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 149 break; 150 case kIndex_8_SkColorType: 151 case kN32_SkColorType: 152 if (bitmapIsOpaque) { 153 flags |= kHasSpan16_Flag; 154 } 155 break; 156 case kAlpha_8_SkColorType: 157 break; // never set kHasSpan16_Flag 158 default: 159 break; 160 } 161 162 if (rec.fPaint->isDither() && bitmap.colorType() != kRGB_565_SkColorType) { 163 // gradients can auto-dither in their 16bit sampler, but we don't so 164 // we clear the flag here. 165 flags &= ~kHasSpan16_Flag; 166 } 167 168 // if we're only 1-pixel high, and we don't rotate, then we can claim this 169 if (1 == bitmap.height() && 170 only_scale_and_translate(this->getTotalInverse())) { 171 flags |= kConstInY32_Flag; 172 if (flags & kHasSpan16_Flag) { 173 flags |= kConstInY16_Flag; 174 } 175 } 176 177 fFlags = flags; 178 } 179 180 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() { 181 // The bitmap proc state has been created outside of the context on memory that will be freed 182 // elsewhere. Only call the destructor but leave the freeing of the memory to the caller. 183 fState->~SkBitmapProcState(); 184 } 185 186 #define BUF_MAX 128 187 188 #define TEST_BUFFER_OVERRITEx 189 190 #ifdef TEST_BUFFER_OVERRITE 191 #define TEST_BUFFER_EXTRA 32 192 #define TEST_PATTERN 0x88888888 193 #else 194 #define TEST_BUFFER_EXTRA 0 195 #endif 196 197 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], 198 int count) { 199 const SkBitmapProcState& state = *fState; 200 if (state.getShaderProc32()) { 201 state.getShaderProc32()(state, x, y, dstC, count); 202 return; 203 } 204 205 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 206 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 207 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 208 int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 209 210 SkASSERT(state.fBitmap->getPixels()); 211 SkASSERT(state.fBitmap->pixelRef() == NULL || 212 state.fBitmap->pixelRef()->isLocked()); 213 214 for (;;) { 215 int n = count; 216 if (n > max) { 217 n = max; 218 } 219 SkASSERT(n > 0 && n < BUF_MAX*2); 220 #ifdef TEST_BUFFER_OVERRITE 221 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 222 buffer[BUF_MAX + i] = TEST_PATTERN; 223 } 224 #endif 225 mproc(state, buffer, n, x, y); 226 #ifdef TEST_BUFFER_OVERRITE 227 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 228 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 229 } 230 #endif 231 sproc(state, buffer, n, dstC); 232 233 if ((count -= n) == 0) { 234 break; 235 } 236 SkASSERT(count > 0); 237 x += n; 238 dstC += n; 239 } 240 } 241 242 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) { 243 if (fState->getShaderProc32()) { 244 *ctx = fState; 245 return (ShadeProc)fState->getShaderProc32(); 246 } 247 return NULL; 248 } 249 250 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], 251 int count) { 252 const SkBitmapProcState& state = *fState; 253 if (state.getShaderProc16()) { 254 state.getShaderProc16()(state, x, y, dstC, count); 255 return; 256 } 257 258 uint32_t buffer[BUF_MAX]; 259 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 260 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); 261 int max = state.maxCountForBufferSize(sizeof(buffer)); 262 263 SkASSERT(state.fBitmap->getPixels()); 264 SkASSERT(state.fBitmap->pixelRef() == NULL || 265 state.fBitmap->pixelRef()->isLocked()); 266 267 for (;;) { 268 int n = count; 269 if (n > max) { 270 n = max; 271 } 272 mproc(state, buffer, n, x, y); 273 sproc(state, buffer, n, dstC); 274 275 if ((count -= n) == 0) { 276 break; 277 } 278 x += n; 279 dstC += n; 280 } 281 } 282 283 /////////////////////////////////////////////////////////////////////////////// 284 285 #include "SkUnPreMultiply.h" 286 #include "SkColorShader.h" 287 #include "SkEmptyShader.h" 288 289 // returns true and set color if the bitmap can be drawn as a single color 290 // (for efficiency) 291 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 292 if (1 != bm.width() || 1 != bm.height()) { 293 return false; 294 } 295 296 SkAutoLockPixels alp(bm); 297 if (!bm.readyToDraw()) { 298 return false; 299 } 300 301 switch (bm.colorType()) { 302 case kN32_SkColorType: 303 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 304 return true; 305 case kRGB_565_SkColorType: 306 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 307 return true; 308 case kIndex_8_SkColorType: 309 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 310 return true; 311 default: // just skip the other configs for now 312 break; 313 } 314 return false; 315 } 316 317 static bool bitmapIsTooBig(const SkBitmap& bm) { 318 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 319 // communicates between its matrix-proc and its sampler-proc. Until we can 320 // widen that, we have to reject bitmaps that are larger. 321 // 322 const int maxSize = 65535; 323 324 return bm.width() > maxSize || bm.height() > maxSize; 325 } 326 327 SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, 328 SkShader::TileMode tmy, const SkMatrix* localMatrix, SkTBlitterAllocator* allocator) { 329 SkShader* shader; 330 SkColor color; 331 if (src.isNull() || bitmapIsTooBig(src)) { 332 if (NULL == allocator) { 333 shader = SkNEW(SkEmptyShader); 334 } else { 335 shader = allocator->createT<SkEmptyShader>(); 336 } 337 } 338 else if (canUseColorShader(src, &color)) { 339 if (NULL == allocator) { 340 shader = SkNEW_ARGS(SkColorShader, (color)); 341 } else { 342 shader = allocator->createT<SkColorShader>(color); 343 } 344 } else { 345 if (NULL == allocator) { 346 shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix)); 347 } else { 348 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix); 349 } 350 } 351 return shader; 352 } 353 354 /////////////////////////////////////////////////////////////////////////////// 355 356 #ifndef SK_IGNORE_TO_STRING 357 void SkBitmapProcShader::toString(SkString* str) const { 358 static const char* gTileModeName[SkShader::kTileModeCount] = { 359 "clamp", "repeat", "mirror" 360 }; 361 362 str->append("BitmapShader: ("); 363 364 str->appendf("(%s, %s)", 365 gTileModeName[fTileModeX], 366 gTileModeName[fTileModeY]); 367 368 str->append(" "); 369 fRawBitmap.toString(str); 370 371 this->INHERITED::toString(str); 372 373 str->append(")"); 374 } 375 #endif 376 377 /////////////////////////////////////////////////////////////////////////////// 378 379 #if SK_SUPPORT_GPU 380 381 #include "GrTextureAccess.h" 382 #include "effects/GrSimpleTextureEffect.h" 383 #include "SkGr.h" 384 385 bool SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint, 386 const SkMatrix* localMatrix, GrColor* grColor, 387 GrEffectRef** grEffect) const { 388 SkMatrix matrix; 389 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); 390 391 SkMatrix lmInverse; 392 if (!this->getLocalMatrix().invert(&lmInverse)) { 393 return false; 394 } 395 if (localMatrix) { 396 SkMatrix inv; 397 if (!localMatrix->invert(&inv)) { 398 return false; 399 } 400 lmInverse.postConcat(inv); 401 } 402 matrix.preConcat(lmInverse); 403 404 SkShader::TileMode tm[] = { 405 (TileMode)fTileModeX, 406 (TileMode)fTileModeY, 407 }; 408 409 // Must set wrap and filter on the sampler before requesting a texture. In two places below 410 // we check the matrix scale factors to determine how to interpret the filter quality setting. 411 // This completely ignores the complexity of the drawVertices case where explicit local coords 412 // are provided by the caller. 413 bool useBicubic = false; 414 GrTextureParams::FilterMode textureFilterMode; 415 switch(paint.getFilterLevel()) { 416 case SkPaint::kNone_FilterLevel: 417 textureFilterMode = GrTextureParams::kNone_FilterMode; 418 break; 419 case SkPaint::kLow_FilterLevel: 420 textureFilterMode = GrTextureParams::kBilerp_FilterMode; 421 break; 422 case SkPaint::kMedium_FilterLevel: { 423 SkMatrix matrix; 424 matrix.setConcat(context->getMatrix(), this->getLocalMatrix()); 425 if (matrix.getMinScale() < SK_Scalar1) { 426 textureFilterMode = GrTextureParams::kMipMap_FilterMode; 427 } else { 428 // Don't trigger MIP level generation unnecessarily. 429 textureFilterMode = GrTextureParams::kBilerp_FilterMode; 430 } 431 break; 432 } 433 case SkPaint::kHigh_FilterLevel: { 434 SkMatrix matrix; 435 matrix.setConcat(context->getMatrix(), this->getLocalMatrix()); 436 useBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode); 437 break; 438 } 439 default: 440 SkErrorInternals::SetError( kInvalidPaint_SkError, 441 "Sorry, I don't understand the filtering " 442 "mode you asked for. Falling back to " 443 "MIPMaps."); 444 textureFilterMode = GrTextureParams::kMipMap_FilterMode; 445 break; 446 447 } 448 GrTextureParams params(tm, textureFilterMode); 449 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms); 450 451 if (NULL == texture) { 452 SkErrorInternals::SetError( kInternalError_SkError, 453 "Couldn't convert bitmap to texture."); 454 return false; 455 } 456 457 *grColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ? SkColor2GrColor(paint.getColor()) 458 : SkColor2GrColorJustAlpha(paint.getColor()); 459 460 if (useBicubic) { 461 *grEffect = GrBicubicEffect::Create(texture, matrix, tm); 462 } else { 463 *grEffect = GrSimpleTextureEffect::Create(texture, matrix, params); 464 } 465 GrUnlockAndUnrefCachedBitmapTexture(texture); 466 467 return true; 468 } 469 470 #else 471 472 bool SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint, 473 const SkMatrix* localMatrix, GrColor* grColor, 474 GrEffectRef** grEffect) const { 475 SkDEBUGFAIL("Should not call in GPU-less build"); 476 return false; 477 } 478 479 #endif 480