1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkBitmapProcShader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,453 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkColorPriv.h" 1.12 +#include "SkReadBuffer.h" 1.13 +#include "SkWriteBuffer.h" 1.14 +#include "SkPixelRef.h" 1.15 +#include "SkErrorInternals.h" 1.16 +#include "SkBitmapProcShader.h" 1.17 + 1.18 +#if SK_SUPPORT_GPU 1.19 +#include "effects/GrSimpleTextureEffect.h" 1.20 +#include "effects/GrBicubicEffect.h" 1.21 +#endif 1.22 + 1.23 +bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { 1.24 + switch (bm.colorType()) { 1.25 + case kAlpha_8_SkColorType: 1.26 + case kRGB_565_SkColorType: 1.27 + case kIndex_8_SkColorType: 1.28 + case kPMColor_SkColorType: 1.29 + // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) 1.30 + return true; 1.31 + default: 1.32 + break; 1.33 + } 1.34 + return false; 1.35 +} 1.36 + 1.37 +SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, 1.38 + TileMode tmx, TileMode tmy) { 1.39 + fRawBitmap = src; 1.40 + fState.fTileModeX = (uint8_t)tmx; 1.41 + fState.fTileModeY = (uint8_t)tmy; 1.42 + fFlags = 0; // computed in setContext 1.43 +} 1.44 + 1.45 +SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer) 1.46 + : INHERITED(buffer) { 1.47 + buffer.readBitmap(&fRawBitmap); 1.48 + fRawBitmap.setImmutable(); 1.49 + fState.fTileModeX = buffer.readUInt(); 1.50 + fState.fTileModeY = buffer.readUInt(); 1.51 + fFlags = 0; // computed in setContext 1.52 +} 1.53 + 1.54 +SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 1.55 + SkMatrix* texM, 1.56 + TileMode xy[]) const { 1.57 + if (texture) { 1.58 + *texture = fRawBitmap; 1.59 + } 1.60 + if (texM) { 1.61 + texM->reset(); 1.62 + } 1.63 + if (xy) { 1.64 + xy[0] = (TileMode)fState.fTileModeX; 1.65 + xy[1] = (TileMode)fState.fTileModeY; 1.66 + } 1.67 + return kDefault_BitmapType; 1.68 +} 1.69 + 1.70 +void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { 1.71 + this->INHERITED::flatten(buffer); 1.72 + 1.73 + buffer.writeBitmap(fRawBitmap); 1.74 + buffer.writeUInt(fState.fTileModeX); 1.75 + buffer.writeUInt(fState.fTileModeY); 1.76 +} 1.77 + 1.78 +static bool only_scale_and_translate(const SkMatrix& matrix) { 1.79 + unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 1.80 + return (matrix.getType() & ~mask) == 0; 1.81 +} 1.82 + 1.83 +bool SkBitmapProcShader::isOpaque() const { 1.84 + return fRawBitmap.isOpaque(); 1.85 +} 1.86 + 1.87 +static bool valid_for_drawing(const SkBitmap& bm) { 1.88 + if (0 == bm.width() || 0 == bm.height()) { 1.89 + return false; // nothing to draw 1.90 + } 1.91 + if (NULL == bm.pixelRef()) { 1.92 + return false; // no pixels to read 1.93 + } 1.94 + if (kIndex_8_SkColorType == bm.colorType()) { 1.95 + // ugh, I have to lock-pixels to inspect the colortable 1.96 + SkAutoLockPixels alp(bm); 1.97 + if (!bm.getColorTable()) { 1.98 + return false; 1.99 + } 1.100 + } 1.101 + return true; 1.102 +} 1.103 + 1.104 +bool SkBitmapProcShader::setContext(const SkBitmap& device, 1.105 + const SkPaint& paint, 1.106 + const SkMatrix& matrix) { 1.107 + if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) { 1.108 + return false; 1.109 + } 1.110 + 1.111 + // do this first, so we have a correct inverse matrix 1.112 + if (!this->INHERITED::setContext(device, paint, matrix)) { 1.113 + return false; 1.114 + } 1.115 + 1.116 + fState.fOrigBitmap = fRawBitmap; 1.117 + if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 1.118 + this->INHERITED::endContext(); 1.119 + return false; 1.120 + } 1.121 + 1.122 + const SkBitmap& bitmap = *fState.fBitmap; 1.123 + bool bitmapIsOpaque = bitmap.isOpaque(); 1.124 + 1.125 + // update fFlags 1.126 + uint32_t flags = 0; 1.127 + if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 1.128 + flags |= kOpaqueAlpha_Flag; 1.129 + } 1.130 + 1.131 + switch (bitmap.colorType()) { 1.132 + case kRGB_565_SkColorType: 1.133 + flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 1.134 + break; 1.135 + case kIndex_8_SkColorType: 1.136 + case kPMColor_SkColorType: 1.137 + if (bitmapIsOpaque) { 1.138 + flags |= kHasSpan16_Flag; 1.139 + } 1.140 + break; 1.141 + case kAlpha_8_SkColorType: 1.142 + break; // never set kHasSpan16_Flag 1.143 + default: 1.144 + break; 1.145 + } 1.146 + 1.147 + if (paint.isDither() && bitmap.colorType() != kRGB_565_SkColorType) { 1.148 + // gradients can auto-dither in their 16bit sampler, but we don't so 1.149 + // we clear the flag here. 1.150 + flags &= ~kHasSpan16_Flag; 1.151 + } 1.152 + 1.153 + // if we're only 1-pixel high, and we don't rotate, then we can claim this 1.154 + if (1 == bitmap.height() && 1.155 + only_scale_and_translate(this->getTotalInverse())) { 1.156 + flags |= kConstInY32_Flag; 1.157 + if (flags & kHasSpan16_Flag) { 1.158 + flags |= kConstInY16_Flag; 1.159 + } 1.160 + } 1.161 + 1.162 + fFlags = flags; 1.163 + return true; 1.164 +} 1.165 + 1.166 +void SkBitmapProcShader::endContext() { 1.167 + fState.endContext(); 1.168 + this->INHERITED::endContext(); 1.169 +} 1.170 + 1.171 +#define BUF_MAX 128 1.172 + 1.173 +#define TEST_BUFFER_OVERRITEx 1.174 + 1.175 +#ifdef TEST_BUFFER_OVERRITE 1.176 + #define TEST_BUFFER_EXTRA 32 1.177 + #define TEST_PATTERN 0x88888888 1.178 +#else 1.179 + #define TEST_BUFFER_EXTRA 0 1.180 +#endif 1.181 + 1.182 +void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 1.183 + const SkBitmapProcState& state = fState; 1.184 + if (state.getShaderProc32()) { 1.185 + state.getShaderProc32()(state, x, y, dstC, count); 1.186 + return; 1.187 + } 1.188 + 1.189 + uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 1.190 + SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 1.191 + SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 1.192 + int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 1.193 + 1.194 + SkASSERT(state.fBitmap->getPixels()); 1.195 + SkASSERT(state.fBitmap->pixelRef() == NULL || 1.196 + state.fBitmap->pixelRef()->isLocked()); 1.197 + 1.198 + for (;;) { 1.199 + int n = count; 1.200 + if (n > max) { 1.201 + n = max; 1.202 + } 1.203 + SkASSERT(n > 0 && n < BUF_MAX*2); 1.204 +#ifdef TEST_BUFFER_OVERRITE 1.205 + for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 1.206 + buffer[BUF_MAX + i] = TEST_PATTERN; 1.207 + } 1.208 +#endif 1.209 + mproc(state, buffer, n, x, y); 1.210 +#ifdef TEST_BUFFER_OVERRITE 1.211 + for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 1.212 + SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 1.213 + } 1.214 +#endif 1.215 + sproc(state, buffer, n, dstC); 1.216 + 1.217 + if ((count -= n) == 0) { 1.218 + break; 1.219 + } 1.220 + SkASSERT(count > 0); 1.221 + x += n; 1.222 + dstC += n; 1.223 + } 1.224 +} 1.225 + 1.226 +SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { 1.227 + if (fState.getShaderProc32()) { 1.228 + *ctx = &fState; 1.229 + return (ShadeProc)fState.getShaderProc32(); 1.230 + } 1.231 + return NULL; 1.232 +} 1.233 + 1.234 +void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 1.235 + const SkBitmapProcState& state = fState; 1.236 + if (state.getShaderProc16()) { 1.237 + state.getShaderProc16()(state, x, y, dstC, count); 1.238 + return; 1.239 + } 1.240 + 1.241 + uint32_t buffer[BUF_MAX]; 1.242 + SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 1.243 + SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); 1.244 + int max = fState.maxCountForBufferSize(sizeof(buffer)); 1.245 + 1.246 + SkASSERT(state.fBitmap->getPixels()); 1.247 + SkASSERT(state.fBitmap->pixelRef() == NULL || 1.248 + state.fBitmap->pixelRef()->isLocked()); 1.249 + 1.250 + for (;;) { 1.251 + int n = count; 1.252 + if (n > max) { 1.253 + n = max; 1.254 + } 1.255 + mproc(state, buffer, n, x, y); 1.256 + sproc(state, buffer, n, dstC); 1.257 + 1.258 + if ((count -= n) == 0) { 1.259 + break; 1.260 + } 1.261 + x += n; 1.262 + dstC += n; 1.263 + } 1.264 +} 1.265 + 1.266 +/////////////////////////////////////////////////////////////////////////////// 1.267 + 1.268 +#include "SkUnPreMultiply.h" 1.269 +#include "SkColorShader.h" 1.270 +#include "SkEmptyShader.h" 1.271 + 1.272 +// returns true and set color if the bitmap can be drawn as a single color 1.273 +// (for efficiency) 1.274 +static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 1.275 + if (1 != bm.width() || 1 != bm.height()) { 1.276 + return false; 1.277 + } 1.278 + 1.279 + SkAutoLockPixels alp(bm); 1.280 + if (!bm.readyToDraw()) { 1.281 + return false; 1.282 + } 1.283 + 1.284 + switch (bm.colorType()) { 1.285 + case kPMColor_SkColorType: 1.286 + *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 1.287 + return true; 1.288 + case kRGB_565_SkColorType: 1.289 + *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 1.290 + return true; 1.291 + case kIndex_8_SkColorType: 1.292 + *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 1.293 + return true; 1.294 + default: // just skip the other configs for now 1.295 + break; 1.296 + } 1.297 + return false; 1.298 +} 1.299 + 1.300 +static bool bitmapIsTooBig(const SkBitmap& bm) { 1.301 + // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 1.302 + // communicates between its matrix-proc and its sampler-proc. Until we can 1.303 + // widen that, we have to reject bitmaps that are larger. 1.304 + // 1.305 + const int maxSize = 65535; 1.306 + 1.307 + return bm.width() > maxSize || bm.height() > maxSize; 1.308 +} 1.309 + 1.310 +SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, 1.311 + SkShader::TileMode tmy, SkTBlitterAllocator* allocator) { 1.312 + SkShader* shader; 1.313 + SkColor color; 1.314 + if (src.isNull() || bitmapIsTooBig(src)) { 1.315 + if (NULL == allocator) { 1.316 + shader = SkNEW(SkEmptyShader); 1.317 + } else { 1.318 + shader = allocator->createT<SkEmptyShader>(); 1.319 + } 1.320 + } 1.321 + else if (canUseColorShader(src, &color)) { 1.322 + if (NULL == allocator) { 1.323 + shader = SkNEW_ARGS(SkColorShader, (color)); 1.324 + } else { 1.325 + shader = allocator->createT<SkColorShader>(color); 1.326 + } 1.327 + } else { 1.328 + if (NULL == allocator) { 1.329 + shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy)); 1.330 + } else { 1.331 + shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy); 1.332 + } 1.333 + } 1.334 + return shader; 1.335 +} 1.336 + 1.337 +/////////////////////////////////////////////////////////////////////////////// 1.338 + 1.339 +#ifndef SK_IGNORE_TO_STRING 1.340 +void SkBitmapProcShader::toString(SkString* str) const { 1.341 + static const char* gTileModeName[SkShader::kTileModeCount] = { 1.342 + "clamp", "repeat", "mirror" 1.343 + }; 1.344 + 1.345 + str->append("BitmapShader: ("); 1.346 + 1.347 + str->appendf("(%s, %s)", 1.348 + gTileModeName[fState.fTileModeX], 1.349 + gTileModeName[fState.fTileModeY]); 1.350 + 1.351 + str->append(" "); 1.352 + fRawBitmap.toString(str); 1.353 + 1.354 + this->INHERITED::toString(str); 1.355 + 1.356 + str->append(")"); 1.357 +} 1.358 +#endif 1.359 + 1.360 +/////////////////////////////////////////////////////////////////////////////// 1.361 + 1.362 +#if SK_SUPPORT_GPU 1.363 + 1.364 +#include "GrTextureAccess.h" 1.365 +#include "effects/GrSimpleTextureEffect.h" 1.366 +#include "SkGr.h" 1.367 + 1.368 +// Note that this will return -1 if either matrix is perspective. 1.369 +static SkScalar get_combined_min_stretch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) { 1.370 + if (localMatrix.isIdentity()) { 1.371 + return viewMatrix.getMinStretch(); 1.372 + } else { 1.373 + SkMatrix combined; 1.374 + combined.setConcat(viewMatrix, localMatrix); 1.375 + return combined.getMinStretch(); 1.376 + } 1.377 +} 1.378 + 1.379 +GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const { 1.380 + SkMatrix matrix; 1.381 + matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); 1.382 + 1.383 + SkMatrix lmInverse; 1.384 + if (!this->getLocalMatrix().invert(&lmInverse)) { 1.385 + return NULL; 1.386 + } 1.387 + matrix.preConcat(lmInverse); 1.388 + 1.389 + SkShader::TileMode tm[] = { 1.390 + (TileMode)fState.fTileModeX, 1.391 + (TileMode)fState.fTileModeY, 1.392 + }; 1.393 + 1.394 + // Must set wrap and filter on the sampler before requesting a texture. In two places below 1.395 + // we check the matrix scale factors to determine how to interpret the filter quality setting. 1.396 + // This completely ignores the complexity of the drawVertices case where explicit local coords 1.397 + // are provided by the caller. 1.398 + SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel(); 1.399 + GrTextureParams::FilterMode textureFilterMode; 1.400 + switch(paintFilterLevel) { 1.401 + case SkPaint::kNone_FilterLevel: 1.402 + textureFilterMode = GrTextureParams::kNone_FilterMode; 1.403 + break; 1.404 + case SkPaint::kLow_FilterLevel: 1.405 + textureFilterMode = GrTextureParams::kBilerp_FilterMode; 1.406 + break; 1.407 + case SkPaint::kMedium_FilterLevel: 1.408 + if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) < 1.409 + SK_Scalar1) { 1.410 + textureFilterMode = GrTextureParams::kMipMap_FilterMode; 1.411 + } else { 1.412 + // Don't trigger MIP level generation unnecessarily. 1.413 + textureFilterMode = GrTextureParams::kBilerp_FilterMode; 1.414 + } 1.415 + break; 1.416 + case SkPaint::kHigh_FilterLevel: 1.417 + // Minification can look bad with bicubic filtering. 1.418 + if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) >= 1.419 + SK_Scalar1) { 1.420 + // fall back to no filtering here; we will install another shader that will do the 1.421 + // HQ filtering. 1.422 + textureFilterMode = GrTextureParams::kNone_FilterMode; 1.423 + } else { 1.424 + // Fall back to MIP-mapping. 1.425 + paintFilterLevel = SkPaint::kMedium_FilterLevel; 1.426 + textureFilterMode = GrTextureParams::kMipMap_FilterMode; 1.427 + } 1.428 + break; 1.429 + default: 1.430 + SkErrorInternals::SetError( kInvalidPaint_SkError, 1.431 + "Sorry, I don't understand the filtering " 1.432 + "mode you asked for. Falling back to " 1.433 + "MIPMaps."); 1.434 + textureFilterMode = GrTextureParams::kMipMap_FilterMode; 1.435 + break; 1.436 + 1.437 + } 1.438 + GrTextureParams params(tm, textureFilterMode); 1.439 + GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms); 1.440 + 1.441 + if (NULL == texture) { 1.442 + SkErrorInternals::SetError( kInternalError_SkError, 1.443 + "Couldn't convert bitmap to texture."); 1.444 + return NULL; 1.445 + } 1.446 + 1.447 + GrEffectRef* effect = NULL; 1.448 + if (paintFilterLevel == SkPaint::kHigh_FilterLevel) { 1.449 + effect = GrBicubicEffect::Create(texture, matrix, tm); 1.450 + } else { 1.451 + effect = GrSimpleTextureEffect::Create(texture, matrix, params); 1.452 + } 1.453 + GrUnlockAndUnrefCachedBitmapTexture(texture); 1.454 + return effect; 1.455 +} 1.456 +#endif