Home | History | Annotate | Download | only in shaders
      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());
    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 SkShaderBase::Context::ShadeProc SkShaderBase::Context::asAShadeProc(void** ctx) {
    133     return nullptr;
    134 }
    135 
    136 void SkShaderBase::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
    137     const int N = 128;
    138     SkPMColor tmp[N];
    139     while (count > 0) {
    140         int n = SkTMin(count, N);
    141         this->shadeSpan(x, y, tmp, n);
    142         for (int i = 0; i < n; ++i) {
    143             dst[i] = SkPM4f::FromPMColor(tmp[i]);
    144         }
    145         dst += n;
    146         x += n;
    147         count -= n;
    148     }
    149 }
    150 
    151 #include "SkColorPriv.h"
    152 
    153 #define kTempColorQuadCount 6   // balance between speed (larger) and saving stack-space
    154 #define kTempColorCount     (kTempColorQuadCount << 2)
    155 
    156 #ifdef SK_CPU_BENDIAN
    157     #define SkU32BitShiftToByteOffset(shift)    (3 - ((shift) >> 3))
    158 #else
    159     #define SkU32BitShiftToByteOffset(shift)    ((shift) >> 3)
    160 #endif
    161 
    162 void SkShaderBase::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
    163     SkASSERT(count > 0);
    164 
    165     SkPMColor   colors[kTempColorCount];
    166 
    167     while ((count -= kTempColorCount) >= 0) {
    168         this->shadeSpan(x, y, colors, kTempColorCount);
    169         x += kTempColorCount;
    170 
    171         const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
    172         int quads = kTempColorQuadCount;
    173         do {
    174             U8CPU a0 = srcA[0];
    175             U8CPU a1 = srcA[4];
    176             U8CPU a2 = srcA[8];
    177             U8CPU a3 = srcA[12];
    178             srcA += 4*4;
    179             *alpha++ = SkToU8(a0);
    180             *alpha++ = SkToU8(a1);
    181             *alpha++ = SkToU8(a2);
    182             *alpha++ = SkToU8(a3);
    183         } while (--quads != 0);
    184     }
    185     SkASSERT(count < 0);
    186     SkASSERT(count + kTempColorCount >= 0);
    187     if (count += kTempColorCount) {
    188         this->shadeSpan(x, y, colors, count);
    189 
    190         const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
    191         do {
    192             *alpha++ = *srcA;
    193             srcA += 4;
    194         } while (--count != 0);
    195     }
    196 #if 0
    197     do {
    198         int n = count;
    199         if (n > kTempColorCount)
    200             n = kTempColorCount;
    201         SkASSERT(n > 0);
    202 
    203         this->shadeSpan(x, y, colors, n);
    204         x += n;
    205         count -= n;
    206 
    207         const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
    208         do {
    209             *alpha++ = *srcA;
    210             srcA += 4;
    211         } while (--n != 0);
    212     } while (count > 0);
    213 #endif
    214 }
    215 
    216 //////////////////////////////////////////////////////////////////////////////
    217 
    218 const SkMatrix& SkShader::getLocalMatrix() const {
    219     return as_SB(this)->getLocalMatrix();
    220 }
    221 
    222 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
    223 bool SkShader::isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const {
    224     return  as_SB(this)->onIsABitmap(outTexture, outMatrix, xy);
    225 }
    226 #endif
    227 
    228 SkImage* SkShader::isAImage(SkMatrix* localMatrix, TileMode xy[2]) const {
    229     return as_SB(this)->onIsAImage(localMatrix, xy);
    230 }
    231 
    232 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
    233     return kNone_GradientType;
    234 }
    235 
    236 #if SK_SUPPORT_GPU
    237 sk_sp<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const AsFPArgs&) const {
    238     return nullptr;
    239 }
    240 #endif
    241 
    242 sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const {
    243     return nullptr;
    244 }
    245 
    246 sk_sp<SkShader> SkShader::MakeEmptyShader() { return sk_make_sp<SkEmptyShader>(); }
    247 
    248 sk_sp<SkShader> SkShader::MakeColorShader(SkColor color) { return sk_make_sp<SkColorShader>(color); }
    249 
    250 sk_sp<SkShader> SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
    251                                            const SkMatrix* localMatrix) {
    252     if (localMatrix && !localMatrix->invert(nullptr)) {
    253         return nullptr;
    254     }
    255     return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode);
    256 }
    257 
    258 sk_sp<SkShader> SkShader::MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy,
    259                                             const SkMatrix* localMatrix, const SkRect* tile) {
    260     if (localMatrix && !localMatrix->invert(nullptr)) {
    261         return nullptr;
    262     }
    263     return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile);
    264 }
    265 
    266 #ifndef SK_IGNORE_TO_STRING
    267 void SkShaderBase::toString(SkString* str) const {
    268     if (!fLocalMatrix.isIdentity()) {
    269         str->append(" ");
    270         fLocalMatrix.toString(str);
    271     }
    272 }
    273 #endif
    274 
    275 bool SkShaderBase::appendStages(SkRasterPipeline* p,
    276                                 SkColorSpace* dstCS,
    277                                 SkArenaAlloc* alloc,
    278                                 const SkMatrix& ctm,
    279                                 const SkPaint& paint,
    280                                 const SkMatrix* localM) const {
    281     return this->onAppendStages(p, dstCS, alloc, ctm, paint, localM);
    282 }
    283 
    284 bool SkShaderBase::onAppendStages(SkRasterPipeline* p,
    285                                   SkColorSpace* dstCS,
    286                                   SkArenaAlloc* alloc,
    287                                   const SkMatrix& ctm,
    288                                   const SkPaint& paint,
    289                                   const SkMatrix* localM) const {
    290     // SkShader::Context::shadeSpan4f() handles the paint opacity internally,
    291     // but SkRasterPipelineBlitter applies it as a separate stage.
    292     // We skip the internal shadeSpan4f() step by forcing the paint opaque.
    293     SkTCopyOnFirstWrite<SkPaint> opaquePaint(paint);
    294     if (paint.getAlpha() != SK_AlphaOPAQUE) {
    295         opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE);
    296     }
    297 
    298     ContextRec rec(*opaquePaint, ctm, localM, ContextRec::kPM4f_DstType, dstCS);
    299 
    300     struct CallbackCtx : SkJumper_CallbackCtx {
    301         sk_sp<SkShader> shader;
    302         Context*        ctx;
    303     };
    304     auto cb = alloc->make<CallbackCtx>();
    305     cb->shader = dstCS ? SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(this)
    306                        : sk_ref_sp((SkShader*)this);
    307     cb->ctx = as_SB(cb->shader)->makeContext(rec, alloc);
    308     cb->fn  = [](SkJumper_CallbackCtx* self, int active_pixels) {
    309         auto c = (CallbackCtx*)self;
    310         int x = (int)c->rgba[0],
    311         y = (int)c->rgba[1];
    312         c->ctx->shadeSpan4f(x,y, (SkPM4f*)c->rgba, active_pixels);
    313     };
    314 
    315     if (cb->ctx) {
    316         p->append(SkRasterPipeline::seed_shader);
    317         p->append(SkRasterPipeline::callback, cb);
    318         return true;
    319     }
    320     return false;
    321 }
    322 
    323 ///////////////////////////////////////////////////////////////////////////////////////////////////
    324 
    325 sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) {
    326     return SkShader::MakeEmptyShader();
    327 }
    328 
    329 #ifndef SK_IGNORE_TO_STRING
    330 #include "SkEmptyShader.h"
    331 
    332 void SkEmptyShader::toString(SkString* str) const {
    333     str->append("SkEmptyShader: (");
    334 
    335     this->INHERITED::toString(str);
    336 
    337     str->append(")");
    338 }
    339 #endif
    340