1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkBitmapProcShader.h" 9 #include "SkBitmapProcState.h" 10 #include "SkBitmapProvider.h" 11 #include "SkColorPriv.h" 12 #include "SkErrorInternals.h" 13 #include "SkPixelRef.h" 14 #include "SkReadBuffer.h" 15 #include "SkWriteBuffer.h" 16 17 #if SK_SUPPORT_GPU 18 #include "SkGrPriv.h" 19 #include "effects/GrBicubicEffect.h" 20 #include "effects/GrSimpleTextureEffect.h" 21 #endif 22 23 size_t SkBitmapProcShader::ContextSize() { 24 // The SkBitmapProcState is stored outside of the context object, with the context holding 25 // a pointer to it. 26 return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); 27 } 28 29 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 30 const SkMatrix* localMatrix) 31 : INHERITED(localMatrix) { 32 fRawBitmap = src; 33 fTileModeX = (uint8_t)tmx; 34 fTileModeY = (uint8_t)tmy; 35 } 36 37 bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const { 38 if (texture) { 39 *texture = fRawBitmap; 40 } 41 if (texM) { 42 texM->reset(); 43 } 44 if (xy) { 45 xy[0] = (TileMode)fTileModeX; 46 xy[1] = (TileMode)fTileModeY; 47 } 48 return true; 49 } 50 51 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) { 52 SkMatrix lm; 53 buffer.readMatrix(&lm); 54 SkBitmap bm; 55 if (!buffer.readBitmap(&bm)) { 56 return nullptr; 57 } 58 bm.setImmutable(); 59 TileMode mx = (TileMode)buffer.readUInt(); 60 TileMode my = (TileMode)buffer.readUInt(); 61 return SkShader::CreateBitmapShader(bm, mx, my, &lm); 62 } 63 64 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { 65 buffer.writeMatrix(this->getLocalMatrix()); 66 buffer.writeBitmap(fRawBitmap); 67 buffer.writeUInt(fTileModeX); 68 buffer.writeUInt(fTileModeY); 69 } 70 71 bool SkBitmapProcShader::isOpaque() const { 72 return fRawBitmap.isOpaque(); 73 } 74 75 SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, 76 TileMode tmx, TileMode tmy, 77 const SkBitmapProvider& provider, 78 const ContextRec& rec, void* storage) { 79 SkMatrix totalInverse; 80 // Do this first, so we know the matrix can be inverted. 81 if (!shader.computeTotalInverse(rec, &totalInverse)) { 82 return nullptr; 83 } 84 85 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); 86 SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy); 87 88 SkASSERT(state); 89 if (!state->chooseProcs(totalInverse, *rec.fPaint)) { 90 state->~SkBitmapProcState(); 91 return nullptr; 92 } 93 94 return new (storage) BitmapProcShaderContext(shader, rec, state); 95 } 96 97 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const { 98 return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY, 99 SkBitmapProvider(fRawBitmap), rec, storage); 100 } 101 102 static bool only_scale_and_translate(const SkMatrix& matrix) { 103 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 104 return (matrix.getType() & ~mask) == 0; 105 } 106 107 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader, 108 const ContextRec& rec, 109 SkBitmapProcState* state) 110 : INHERITED(shader, rec) 111 , fState(state) 112 { 113 fFlags = 0; 114 if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) { 115 fFlags |= kOpaqueAlpha_Flag; 116 } 117 118 if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) { 119 fFlags |= kConstInY32_Flag; 120 } 121 } 122 123 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() { 124 // The bitmap proc state has been created outside of the context on memory that will be freed 125 // elsewhere. Only call the destructor but leave the freeing of the memory to the caller. 126 fState->~SkBitmapProcState(); 127 } 128 129 #define BUF_MAX 128 130 131 #define TEST_BUFFER_OVERRITEx 132 133 #ifdef TEST_BUFFER_OVERRITE 134 #define TEST_BUFFER_EXTRA 32 135 #define TEST_PATTERN 0x88888888 136 #else 137 #define TEST_BUFFER_EXTRA 0 138 #endif 139 140 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], 141 int count) { 142 const SkBitmapProcState& state = *fState; 143 if (state.getShaderProc32()) { 144 state.getShaderProc32()(&state, x, y, dstC, count); 145 return; 146 } 147 148 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 149 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 150 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 151 int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 152 153 SkASSERT(state.fPixmap.addr()); 154 155 for (;;) { 156 int n = count; 157 if (n > max) { 158 n = max; 159 } 160 SkASSERT(n > 0 && n < BUF_MAX*2); 161 #ifdef TEST_BUFFER_OVERRITE 162 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 163 buffer[BUF_MAX + i] = TEST_PATTERN; 164 } 165 #endif 166 mproc(state, buffer, n, x, y); 167 #ifdef TEST_BUFFER_OVERRITE 168 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 169 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 170 } 171 #endif 172 sproc(state, buffer, n, dstC); 173 174 if ((count -= n) == 0) { 175 break; 176 } 177 SkASSERT(count > 0); 178 x += n; 179 dstC += n; 180 } 181 } 182 183 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) { 184 if (fState->getShaderProc32()) { 185 *ctx = fState; 186 return (ShadeProc)fState->getShaderProc32(); 187 } 188 return nullptr; 189 } 190 191 /////////////////////////////////////////////////////////////////////////////// 192 193 #include "SkUnPreMultiply.h" 194 #include "SkColorShader.h" 195 #include "SkEmptyShader.h" 196 197 // returns true and set color if the bitmap can be drawn as a single color 198 // (for efficiency) 199 static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) { 200 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 201 // HWUI does not support color shaders (see b/22390304) 202 return false; 203 #endif 204 205 if (1 != bm.width() || 1 != bm.height()) { 206 return false; 207 } 208 209 SkAutoLockPixels alp(bm); 210 if (!bm.readyToDraw()) { 211 return false; 212 } 213 214 switch (bm.colorType()) { 215 case kN32_SkColorType: 216 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 217 return true; 218 case kRGB_565_SkColorType: 219 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 220 return true; 221 case kIndex_8_SkColorType: 222 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 223 return true; 224 default: // just skip the other configs for now 225 break; 226 } 227 return false; 228 } 229 230 static bool bitmap_is_too_big(const SkBitmap& bm) { 231 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 232 // communicates between its matrix-proc and its sampler-proc. Until we can 233 // widen that, we have to reject bitmaps that are larger. 234 // 235 static const int kMaxSize = 65535; 236 237 return bm.width() > kMaxSize || bm.height() > kMaxSize; 238 } 239 240 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, 241 SkShader::TileMode tmy, const SkMatrix* localMatrix, 242 SkTBlitterAllocator* allocator) { 243 SkShader* shader; 244 SkColor color; 245 if (src.isNull() || bitmap_is_too_big(src)) { 246 if (nullptr == allocator) { 247 shader = new SkEmptyShader; 248 } else { 249 shader = allocator->createT<SkEmptyShader>(); 250 } 251 } else if (can_use_color_shader(src, &color)) { 252 if (nullptr == allocator) { 253 shader = new SkColorShader(color); 254 } else { 255 shader = allocator->createT<SkColorShader>(color); 256 } 257 } else { 258 if (nullptr == allocator) { 259 shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix); 260 } else { 261 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix); 262 } 263 } 264 return shader; 265 } 266 267 /////////////////////////////////////////////////////////////////////////////// 268 269 #ifndef SK_IGNORE_TO_STRING 270 void SkBitmapProcShader::toString(SkString* str) const { 271 static const char* gTileModeName[SkShader::kTileModeCount] = { 272 "clamp", "repeat", "mirror" 273 }; 274 275 str->append("BitmapShader: ("); 276 277 str->appendf("(%s, %s)", 278 gTileModeName[fTileModeX], 279 gTileModeName[fTileModeY]); 280 281 str->append(" "); 282 fRawBitmap.toString(str); 283 284 this->INHERITED::toString(str); 285 286 str->append(")"); 287 } 288 #endif 289 290 /////////////////////////////////////////////////////////////////////////////// 291 292 #if SK_SUPPORT_GPU 293 294 #include "GrTextureAccess.h" 295 #include "SkGr.h" 296 #include "effects/GrSimpleTextureEffect.h" 297 298 const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context, 299 const SkMatrix& viewM, const SkMatrix* localMatrix, 300 SkFilterQuality filterQuality) const { 301 SkMatrix matrix; 302 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); 303 304 SkMatrix lmInverse; 305 if (!this->getLocalMatrix().invert(&lmInverse)) { 306 return nullptr; 307 } 308 if (localMatrix) { 309 SkMatrix inv; 310 if (!localMatrix->invert(&inv)) { 311 return nullptr; 312 } 313 lmInverse.postConcat(inv); 314 } 315 matrix.preConcat(lmInverse); 316 317 SkShader::TileMode tm[] = { 318 (TileMode)fTileModeX, 319 (TileMode)fTileModeY, 320 }; 321 322 // Must set wrap and filter on the sampler before requesting a texture. In two places below 323 // we check the matrix scale factors to determine how to interpret the filter quality setting. 324 // This completely ignores the complexity of the drawVertices case where explicit local coords 325 // are provided by the caller. 326 bool doBicubic; 327 GrTextureParams::FilterMode textureFilterMode = 328 GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), 329 &doBicubic); 330 GrTextureParams params(tm, textureFilterMode); 331 SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params)); 332 333 if (!texture) { 334 SkErrorInternals::SetError( kInternalError_SkError, 335 "Couldn't convert bitmap to texture."); 336 return nullptr; 337 } 338 339 SkAutoTUnref<const GrFragmentProcessor> inner; 340 if (doBicubic) { 341 inner.reset(GrBicubicEffect::Create(texture, matrix, tm)); 342 } else { 343 inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params)); 344 } 345 346 if (kAlpha_8_SkColorType == fRawBitmap.colorType()) { 347 return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner); 348 } 349 return GrFragmentProcessor::MulOutputByInputAlpha(inner); 350 } 351 352 #endif 353