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 "SkColorSpaceXformer.h" 13 #include "SkEmptyShader.h" 14 #include "SkMallocPixelRef.h" 15 #include "SkPaint.h" 16 #include "SkPicture.h" 17 #include "SkPictureShader.h" 18 #include "SkPM4fPriv.h" 19 #include "SkRasterPipeline.h" 20 #include "SkReadBuffer.h" 21 #include "SkScalar.h" 22 #include "SkShaderBase.h" 23 #include "SkTLazy.h" 24 #include "SkWriteBuffer.h" 25 #include "../jumper/SkJumper.h" 26 27 #if SK_SUPPORT_GPU 28 #include "GrFragmentProcessor.h" 29 #endif 30 31 //#define SK_TRACK_SHADER_LIFETIME 32 33 #ifdef SK_TRACK_SHADER_LIFETIME 34 static int32_t gShaderCounter; 35 #endif 36 37 static inline void inc_shader_counter() { 38 #ifdef SK_TRACK_SHADER_LIFETIME 39 int32_t prev = sk_atomic_inc(&gShaderCounter); 40 SkDebugf("+++ shader counter %d\n", prev + 1); 41 #endif 42 } 43 static inline void dec_shader_counter() { 44 #ifdef SK_TRACK_SHADER_LIFETIME 45 int32_t prev = sk_atomic_dec(&gShaderCounter); 46 SkDebugf("--- shader counter %d\n", prev - 1); 47 #endif 48 } 49 50 SkShaderBase::SkShaderBase(const SkMatrix* localMatrix) 51 : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) { 52 inc_shader_counter(); 53 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe. 54 (void)fLocalMatrix.getType(); 55 } 56 57 SkShaderBase::~SkShaderBase() { 58 dec_shader_counter(); 59 } 60 61 void SkShaderBase::flatten(SkWriteBuffer& buffer) const { 62 this->INHERITED::flatten(buffer); 63 bool hasLocalM = !fLocalMatrix.isIdentity(); 64 buffer.writeBool(hasLocalM); 65 if (hasLocalM) { 66 buffer.writeMatrix(fLocalMatrix); 67 } 68 } 69 70 bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm, 71 const SkMatrix* outerLocalMatrix, 72 SkMatrix* totalInverse) const { 73 SkMatrix total = SkMatrix::Concat(ctm, fLocalMatrix); 74 if (outerLocalMatrix) { 75 total.preConcat(*outerLocalMatrix); 76 } 77 78 return total.invert(totalInverse); 79 } 80 81 bool SkShaderBase::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 SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { 94 return this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr) 95 ? this->onMakeContext(rec, alloc) 96 : nullptr; 97 } 98 99 SkShaderBase::Context* SkShaderBase::makeBurstPipelineContext(const ContextRec& rec, 100 SkArenaAlloc* alloc) const { 101 102 SkASSERT(rec.fPreferredDstType == ContextRec::kPM4f_DstType); 103 104 // Always use vanilla stages for perspective. 105 if (rec.fMatrix->hasPerspective() || fLocalMatrix.hasPerspective()) { 106 return nullptr; 107 } 108 109 return this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr) 110 ? this->onMakeBurstPipelineContext(rec, alloc) 111 : nullptr; 112 } 113 114 SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec) 115 : fShader(shader), fCTM(*rec.fMatrix) 116 { 117 // We should never use a context for RP-only shaders. 118 SkASSERT(!shader.isRasterPipelineOnly(*rec.fMatrix)); 119 // ... or for perspective. 120 SkASSERT(!rec.fMatrix->hasPerspective()); 121 SkASSERT(!rec.fLocalMatrix || !rec.fLocalMatrix->hasPerspective()); 122 123 // Because the context parameters must be valid at this point, we know that the matrix is 124 // invertible. 125 SkAssertResult(fShader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &fTotalInverse)); 126 127 fPaintAlpha = rec.fPaint->getAlpha(); 128 } 129 130 SkShaderBase::Context::~Context() {} 131 132 void SkShaderBase::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { 133 const int N = 128; 134 SkPMColor tmp[N]; 135 while (count > 0) { 136 int n = SkTMin(count, N); 137 this->shadeSpan(x, y, tmp, n); 138 for (int i = 0; i < n; ++i) { 139 dst[i] = SkPM4f::FromPMColor(tmp[i]); 140 } 141 dst += n; 142 x += n; 143 count -= n; 144 } 145 } 146 147 const SkMatrix& SkShader::getLocalMatrix() const { 148 return as_SB(this)->getLocalMatrix(); 149 } 150 151 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP 152 bool SkShader::isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const { 153 return as_SB(this)->onIsABitmap(outTexture, outMatrix, xy); 154 } 155 #endif 156 157 SkImage* SkShader::isAImage(SkMatrix* localMatrix, TileMode xy[2]) const { 158 return as_SB(this)->onIsAImage(localMatrix, xy); 159 } 160 161 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 162 return kNone_GradientType; 163 } 164 165 #if SK_SUPPORT_GPU 166 std::unique_ptr<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const GrFPArgs&) const { 167 return nullptr; 168 } 169 #endif 170 171 sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const { 172 return nullptr; 173 } 174 175 sk_sp<SkShader> SkShader::MakeEmptyShader() { return sk_make_sp<SkEmptyShader>(); } 176 177 sk_sp<SkShader> SkShader::MakeColorShader(SkColor color) { return sk_make_sp<SkColorShader>(color); } 178 179 sk_sp<SkShader> SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 180 const SkMatrix* localMatrix) { 181 if (localMatrix && !localMatrix->invert(nullptr)) { 182 return nullptr; 183 } 184 return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode); 185 } 186 187 sk_sp<SkShader> SkShader::MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy, 188 const SkMatrix* localMatrix, const SkRect* tile) { 189 if (localMatrix && !localMatrix->invert(nullptr)) { 190 return nullptr; 191 } 192 return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile); 193 } 194 195 #ifndef SK_IGNORE_TO_STRING 196 void SkShaderBase::toString(SkString* str) const { 197 if (!fLocalMatrix.isIdentity()) { 198 str->append(" "); 199 fLocalMatrix.toString(str); 200 } 201 } 202 #endif 203 204 bool SkShaderBase::appendStages(const StageRec& rec) const { 205 return this->onAppendStages(rec); 206 } 207 208 bool SkShaderBase::onAppendStages(const StageRec& rec) const { 209 // SkShader::Context::shadeSpan4f() handles the paint opacity internally, 210 // but SkRasterPipelineBlitter applies it as a separate stage. 211 // We skip the internal shadeSpan4f() step by forcing the paint opaque. 212 SkTCopyOnFirstWrite<SkPaint> opaquePaint(rec.fPaint); 213 if (rec.fPaint.getAlpha() != SK_AlphaOPAQUE) { 214 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE); 215 } 216 217 ContextRec cr(*opaquePaint, rec.fCTM, rec.fLocalM, ContextRec::kPM4f_DstType, rec.fDstCS); 218 219 struct CallbackCtx : SkJumper_CallbackCtx { 220 sk_sp<SkShader> shader; 221 Context* ctx; 222 }; 223 auto cb = rec.fAlloc->make<CallbackCtx>(); 224 cb->shader = rec.fDstCS ? SkColorSpaceXformer::Make(sk_ref_sp(rec.fDstCS))->apply(this) 225 : sk_ref_sp((SkShader*)this); 226 cb->ctx = as_SB(cb->shader)->makeContext(cr, rec.fAlloc); 227 cb->fn = [](SkJumper_CallbackCtx* self, int active_pixels) { 228 auto c = (CallbackCtx*)self; 229 int x = (int)c->rgba[0], 230 y = (int)c->rgba[1]; 231 c->ctx->shadeSpan4f(x,y, (SkPM4f*)c->rgba, active_pixels); 232 }; 233 234 if (cb->ctx) { 235 rec.fPipeline->append_seed_shader(); 236 rec.fPipeline->append(SkRasterPipeline::callback, cb); 237 return true; 238 } 239 return false; 240 } 241 242 /////////////////////////////////////////////////////////////////////////////////////////////////// 243 244 sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) { 245 return SkShader::MakeEmptyShader(); 246 } 247 248 #ifndef SK_IGNORE_TO_STRING 249 #include "SkEmptyShader.h" 250 251 void SkEmptyShader::toString(SkString* str) const { 252 str->append("SkEmptyShader: ("); 253 254 this->INHERITED::toString(str); 255 256 str->append(")"); 257 } 258 #endif 259