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