1 /* 2 * Copyright 2006 The Android Open Source Project 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 "SkArenaAlloc.h" 9 #include "SkAtomics.h" 10 #include "SkBitmapProcShader.h" 11 #include "SkColorShader.h" 12 #include "SkEmptyShader.h" 13 #include "SkMallocPixelRef.h" 14 #include "SkPaint.h" 15 #include "SkPicture.h" 16 #include "SkPictureShader.h" 17 #include "SkPM4fPriv.h" 18 #include "SkRasterPipeline.h" 19 #include "SkReadBuffer.h" 20 #include "SkScalar.h" 21 #include "SkShader.h" 22 #include "SkTLazy.h" 23 #include "SkWriteBuffer.h" 24 25 #if SK_SUPPORT_GPU 26 #include "GrFragmentProcessor.h" 27 #endif 28 29 //#define SK_TRACK_SHADER_LIFETIME 30 31 #ifdef SK_TRACK_SHADER_LIFETIME 32 static int32_t gShaderCounter; 33 #endif 34 35 static inline void inc_shader_counter() { 36 #ifdef SK_TRACK_SHADER_LIFETIME 37 int32_t prev = sk_atomic_inc(&gShaderCounter); 38 SkDebugf("+++ shader counter %d\n", prev + 1); 39 #endif 40 } 41 static inline void dec_shader_counter() { 42 #ifdef SK_TRACK_SHADER_LIFETIME 43 int32_t prev = sk_atomic_dec(&gShaderCounter); 44 SkDebugf("--- shader counter %d\n", prev - 1); 45 #endif 46 } 47 48 SkShader::SkShader(const SkMatrix* localMatrix) { 49 inc_shader_counter(); 50 if (localMatrix) { 51 fLocalMatrix = *localMatrix; 52 } else { 53 fLocalMatrix.reset(); 54 } 55 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe. 56 (void)fLocalMatrix.getType(); 57 } 58 59 SkShader::~SkShader() { 60 dec_shader_counter(); 61 } 62 63 void SkShader::flatten(SkWriteBuffer& buffer) const { 64 this->INHERITED::flatten(buffer); 65 bool hasLocalM = !fLocalMatrix.isIdentity(); 66 buffer.writeBool(hasLocalM); 67 if (hasLocalM) { 68 buffer.writeMatrix(fLocalMatrix); 69 } 70 } 71 72 bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const { 73 SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fLocalMatrix); 74 if (rec.fLocalMatrix) { 75 total.preConcat(*rec.fLocalMatrix); 76 } 77 78 return total.invert(totalInverse); 79 } 80 81 bool SkShader::asLuminanceColor(SkColor* colorPtr) const { 82 SkColor storage; 83 if (nullptr == colorPtr) { 84 colorPtr = &storage; 85 } 86 if (this->onAsLuminanceColor(colorPtr)) { 87 *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque 88 return true; 89 } 90 return false; 91 } 92 93 SkShader::Context* SkShader::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { 94 if (!this->computeTotalInverse(rec, nullptr)) { 95 return nullptr; 96 } 97 return this->onMakeContext(rec, alloc); 98 } 99 100 SkShader::Context::Context(const SkShader& shader, const ContextRec& rec) 101 : fShader(shader), fCTM(*rec.fMatrix) 102 { 103 // Because the context parameters must be valid at this point, we know that the matrix is 104 // invertible. 105 SkAssertResult(fShader.computeTotalInverse(rec, &fTotalInverse)); 106 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); 107 108 fPaintAlpha = rec.fPaint->getAlpha(); 109 } 110 111 SkShader::Context::~Context() {} 112 113 SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { 114 return nullptr; 115 } 116 117 void SkShader::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { 118 const int N = 128; 119 SkPMColor tmp[N]; 120 while (count > 0) { 121 int n = SkTMin(count, N); 122 this->shadeSpan(x, y, tmp, n); 123 for (int i = 0; i < n; ++i) { 124 dst[i] = SkPM4f::FromPMColor(tmp[i]); 125 } 126 dst += n; 127 x += n; 128 count -= n; 129 } 130 } 131 132 #include "SkColorPriv.h" 133 134 #define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space 135 #define kTempColorCount (kTempColorQuadCount << 2) 136 137 #ifdef SK_CPU_BENDIAN 138 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) 139 #else 140 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) 141 #endif 142 143 void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 144 SkASSERT(count > 0); 145 146 SkPMColor colors[kTempColorCount]; 147 148 while ((count -= kTempColorCount) >= 0) { 149 this->shadeSpan(x, y, colors, kTempColorCount); 150 x += kTempColorCount; 151 152 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 153 int quads = kTempColorQuadCount; 154 do { 155 U8CPU a0 = srcA[0]; 156 U8CPU a1 = srcA[4]; 157 U8CPU a2 = srcA[8]; 158 U8CPU a3 = srcA[12]; 159 srcA += 4*4; 160 *alpha++ = SkToU8(a0); 161 *alpha++ = SkToU8(a1); 162 *alpha++ = SkToU8(a2); 163 *alpha++ = SkToU8(a3); 164 } while (--quads != 0); 165 } 166 SkASSERT(count < 0); 167 SkASSERT(count + kTempColorCount >= 0); 168 if (count += kTempColorCount) { 169 this->shadeSpan(x, y, colors, count); 170 171 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 172 do { 173 *alpha++ = *srcA; 174 srcA += 4; 175 } while (--count != 0); 176 } 177 #if 0 178 do { 179 int n = count; 180 if (n > kTempColorCount) 181 n = kTempColorCount; 182 SkASSERT(n > 0); 183 184 this->shadeSpan(x, y, colors, n); 185 x += n; 186 count -= n; 187 188 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 189 do { 190 *alpha++ = *srcA; 191 srcA += 4; 192 } while (--n != 0); 193 } while (count > 0); 194 #endif 195 } 196 197 SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) { 198 MatrixClass mc = kLinear_MatrixClass; 199 200 if (mat.hasPerspective()) { 201 if (mat.isFixedStepInX()) { 202 mc = kFixedStepInX_MatrixClass; 203 } else { 204 mc = kPerspective_MatrixClass; 205 } 206 } 207 return mc; 208 } 209 210 ////////////////////////////////////////////////////////////////////////////// 211 212 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 213 return kNone_GradientType; 214 } 215 216 #if SK_SUPPORT_GPU 217 sk_sp<GrFragmentProcessor> SkShader::asFragmentProcessor(const AsFPArgs&) const { 218 return nullptr; 219 } 220 #endif 221 222 sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const { 223 return nullptr; 224 } 225 226 sk_sp<SkShader> SkShader::MakeEmptyShader() { return sk_make_sp<SkEmptyShader>(); } 227 228 sk_sp<SkShader> SkShader::MakeColorShader(SkColor color) { return sk_make_sp<SkColorShader>(color); } 229 230 sk_sp<SkShader> SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 231 const SkMatrix* localMatrix) { 232 if (localMatrix && !localMatrix->invert(nullptr)) { 233 return nullptr; 234 } 235 return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode); 236 } 237 238 sk_sp<SkShader> SkShader::MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy, 239 const SkMatrix* localMatrix, const SkRect* tile) { 240 if (localMatrix && !localMatrix->invert(nullptr)) { 241 return nullptr; 242 } 243 return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile); 244 } 245 246 #ifndef SK_IGNORE_TO_STRING 247 void SkShader::toString(SkString* str) const { 248 if (!fLocalMatrix.isIdentity()) { 249 str->append(" "); 250 fLocalMatrix.toString(str); 251 } 252 } 253 #endif 254 255 bool SkShader::appendStages(SkRasterPipeline* pipeline, 256 SkColorSpace* dst, 257 SkArenaAlloc* scratch, 258 const SkMatrix& ctm, 259 const SkPaint& paint) const { 260 return this->onAppendStages(pipeline, dst, scratch, ctm, paint, nullptr); 261 } 262 263 bool SkShader::onAppendStages(SkRasterPipeline* p, 264 SkColorSpace* cs, 265 SkArenaAlloc* alloc, 266 const SkMatrix& ctm, 267 const SkPaint& paint, 268 const SkMatrix* localM) const { 269 // Legacy shaders handle the paint opacity internally, 270 // but RP applies it as a separate stage. 271 SkTCopyOnFirstWrite<SkPaint> opaquePaint(paint); 272 if (paint.getAlpha() != SK_AlphaOPAQUE) { 273 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE); 274 } 275 276 ContextRec rec(*opaquePaint, ctm, localM, ContextRec::kPM4f_DstType, cs); 277 if (auto* ctx = this->makeContext(rec, alloc)) { 278 p->append(SkRasterPipeline::shader_adapter, ctx); 279 280 // Legacy shaders aren't aware of color spaces. We can pretty 281 // safely assume they're in sRGB gamut. 282 return append_gamut_transform(p, alloc, 283 SkColorSpace::MakeSRGB().get(), cs); 284 } 285 return false; 286 } 287 288 /////////////////////////////////////////////////////////////////////////////////////////////////// 289 290 sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) { 291 return SkShader::MakeEmptyShader(); 292 } 293 294 #ifndef SK_IGNORE_TO_STRING 295 #include "SkEmptyShader.h" 296 297 void SkEmptyShader::toString(SkString* str) const { 298 str->append("SkEmptyShader: ("); 299 300 this->INHERITED::toString(str); 301 302 str->append(")"); 303 } 304 #endif 305