SkBitmapProcShader.cpp revision 2ad83ea8309733730c5232bc47c76303bc7240ee
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 return false; 90 } 91 92 if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 93 fState.fOrigBitmap.unlockPixels(); 94 return false; 95 } 96 97 const SkBitmap& bitmap = *fState.fBitmap; 98 bool bitmapIsOpaque = bitmap.isOpaque(); 99 100 // update fFlags 101 uint32_t flags = 0; 102 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 103 flags |= kOpaqueAlpha_Flag; 104 } 105 106 switch (bitmap.config()) { 107 case SkBitmap::kRGB_565_Config: 108 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 109 break; 110 case SkBitmap::kIndex8_Config: 111 case SkBitmap::kARGB_8888_Config: 112 if (bitmapIsOpaque) { 113 flags |= kHasSpan16_Flag; 114 } 115 break; 116 case SkBitmap::kA8_Config: 117 break; // never set kHasSpan16_Flag 118 default: 119 break; 120 } 121 122 if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) { 123 // gradients can auto-dither in their 16bit sampler, but we don't so 124 // we clear the flag here. 125 flags &= ~kHasSpan16_Flag; 126 } 127 128 // if we're only 1-pixel heigh, and we don't rotate, then we can claim this 129 if (1 == bitmap.height() && 130 only_scale_and_translate(this->getTotalInverse())) { 131 flags |= kConstInY32_Flag; 132 if (flags & kHasSpan16_Flag) { 133 flags |= kConstInY16_Flag; 134 } 135 } 136 137 fFlags = flags; 138 return true; 139} 140 141void SkBitmapProcShader::endContext() { 142 fState.fOrigBitmap.unlockPixels(); 143 this->INHERITED::endContext(); 144} 145 146#define BUF_MAX 128 147 148#define TEST_BUFFER_OVERRITEx 149 150#ifdef TEST_BUFFER_OVERRITE 151 #define TEST_BUFFER_EXTRA 32 152 #define TEST_PATTERN 0x88888888 153#else 154 #define TEST_BUFFER_EXTRA 0 155#endif 156 157void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 158 const SkBitmapProcState& state = fState; 159 if (state.getShaderProc32()) { 160 state.getShaderProc32()(state, x, y, dstC, count); 161 return; 162 } 163 164 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 165 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 166 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 167 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 168 169 SkASSERT(state.fBitmap->getPixels()); 170 SkASSERT(state.fBitmap->pixelRef() == NULL || 171 state.fBitmap->pixelRef()->isLocked()); 172 173 for (;;) { 174 int n = count; 175 if (n > max) { 176 n = max; 177 } 178 SkASSERT(n > 0 && n < BUF_MAX*2); 179#ifdef TEST_BUFFER_OVERRITE 180 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 181 buffer[BUF_MAX + i] = TEST_PATTERN; 182 } 183#endif 184 mproc(state, buffer, n, x, y); 185#ifdef TEST_BUFFER_OVERRITE 186 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 187 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 188 } 189#endif 190 sproc(state, buffer, n, dstC); 191 192 if ((count -= n) == 0) { 193 break; 194 } 195 SkASSERT(count > 0); 196 x += n; 197 dstC += n; 198 } 199} 200 201SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { 202 if (fState.getShaderProc32()) { 203 *ctx = &fState; 204 return (ShadeProc)fState.getShaderProc32(); 205 } 206 return NULL; 207} 208 209void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 210 const SkBitmapProcState& state = fState; 211 if (state.getShaderProc16()) { 212 state.getShaderProc16()(state, x, y, dstC, count); 213 return; 214 } 215 216 uint32_t buffer[BUF_MAX]; 217 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 218 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); 219 int max = fState.maxCountForBufferSize(sizeof(buffer)); 220 221 SkASSERT(state.fBitmap->getPixels()); 222 SkASSERT(state.fBitmap->pixelRef() == NULL || 223 state.fBitmap->pixelRef()->isLocked()); 224 225 for (;;) { 226 int n = count; 227 if (n > max) { 228 n = max; 229 } 230 mproc(state, buffer, n, x, y); 231 sproc(state, buffer, n, dstC); 232 233 if ((count -= n) == 0) { 234 break; 235 } 236 x += n; 237 dstC += n; 238 } 239} 240 241/////////////////////////////////////////////////////////////////////////////// 242 243#include "SkUnPreMultiply.h" 244#include "SkColorShader.h" 245#include "SkEmptyShader.h" 246 247// returns true and set color if the bitmap can be drawn as a single color 248// (for efficiency) 249static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 250 if (1 != bm.width() || 1 != bm.height()) { 251 return false; 252 } 253 254 SkAutoLockPixels alp(bm); 255 if (!bm.readyToDraw()) { 256 return false; 257 } 258 259 switch (bm.config()) { 260 case SkBitmap::kARGB_8888_Config: 261 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 262 return true; 263 case SkBitmap::kRGB_565_Config: 264 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 265 return true; 266 case SkBitmap::kIndex8_Config: 267 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 268 return true; 269 default: // just skip the other configs for now 270 break; 271 } 272 return false; 273} 274 275#include "SkTemplatesPriv.h" 276 277static bool bitmapIsTooBig(const SkBitmap& bm) { 278 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 279 // communicates between its matrix-proc and its sampler-proc. Until we can 280 // widen that, we have to reject bitmaps that are larger. 281 // 282 const int maxSize = 65535; 283 284 return bm.width() > maxSize || bm.height() > maxSize; 285} 286 287SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 288 TileMode tmx, TileMode tmy, 289 void* storage, size_t storageSize) { 290 SkShader* shader; 291 SkColor color; 292 if (src.isNull() || bitmapIsTooBig(src)) { 293 SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize); 294 } 295 else if (canUseColorShader(src, &color)) { 296 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 297 (color)); 298 } else { 299 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 300 storageSize, (src, tmx, tmy)); 301 } 302 return shader; 303} 304 305/////////////////////////////////////////////////////////////////////////////// 306 307static const char* gTileModeName[] = { 308 "clamp", "repeat", "mirror" 309}; 310 311bool SkBitmapProcShader::toDumpString(SkString* str) const { 312 str->printf("BitmapShader: [%d %d %d", 313 fRawBitmap.width(), fRawBitmap.height(), 314 fRawBitmap.bytesPerPixel()); 315 316 // add the pixelref 317 SkPixelRef* pr = fRawBitmap.pixelRef(); 318 if (pr) { 319 const char* uri = pr->getURI(); 320 if (uri) { 321 str->appendf(" \"%s\"", uri); 322 } 323 } 324 325 // add the (optional) matrix 326 { 327 if (this->hasLocalMatrix()) { 328 SkString info; 329 this->getLocalMatrix().toDumpString(&info); 330 str->appendf(" %s", info.c_str()); 331 } 332 } 333 334 str->appendf(" [%s %s]]", 335 gTileModeName[fState.fTileModeX], 336 gTileModeName[fState.fTileModeY]); 337 return true; 338} 339/////////////////////////////////////////////////////////////////////////////// 340 341#if SK_SUPPORT_GPU 342 343#include "GrTextureAccess.h" 344#include "effects/GrSingleTextureEffect.h" 345#include "SkGr.h" 346 347GrEffect* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const { 348 SkMatrix matrix; 349 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); 350 351 if (this->hasLocalMatrix()) { 352 SkMatrix inverse; 353 if (!this->getLocalMatrix().invert(&inverse)) { 354 return NULL; 355 } 356 matrix.preConcat(inverse); 357 } 358 SkShader::TileMode tm[] = { 359 (TileMode)fState.fTileModeX, 360 (TileMode)fState.fTileModeY, 361 }; 362 363 // Must set wrap and filter on the sampler before requesting a texture. 364 GrTextureParams params(tm, paint.isFilterBitmap()); 365 GrTexture* texture = GrLockCachedBitmapTexture(context, fRawBitmap, ¶ms); 366 367 if (NULL == texture) { 368 SkDebugf("Couldn't convert bitmap to texture.\n"); 369 return NULL; 370 } 371 372 GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params)); 373 GrUnlockCachedBitmapTexture(texture); 374 return effect; 375} 376#endif 377