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 "SkBlendModePriv.h"
     10 #include "SkComposeShader.h"
     11 #include "SkColorFilter.h"
     12 #include "SkColorData.h"
     13 #include "SkColorShader.h"
     14 #include "SkRasterPipeline.h"
     15 #include "SkReadBuffer.h"
     16 #include "SkWriteBuffer.h"
     17 #include "SkString.h"
     18 #include "../jumper/SkJumper.h"
     19 
     20 sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
     21                                       float lerpT) {
     22     if (!src || !dst || SkScalarIsNaN(lerpT)) {
     23         return nullptr;
     24     }
     25     lerpT = SkScalarPin(lerpT, 0, 1);
     26 
     27     if (lerpT == 0) {
     28         return dst;
     29     } else if (lerpT == 1) {
     30         if (mode == SkBlendMode::kSrc) {
     31             return src;
     32         }
     33         if (mode == SkBlendMode::kDst) {
     34             return dst;
     35         }
     36     }
     37     return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
     38 }
     39 
     40 ///////////////////////////////////////////////////////////////////////////////
     41 
     42 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
     43     sk_sp<SkShader> dst(buffer.readShader());
     44     sk_sp<SkShader> src(buffer.readShader());
     45     unsigned        mode = buffer.read32();
     46     float           lerp = buffer.readScalar();
     47 
     48     // check for valid mode before we cast to the enum type
     49     if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
     50         return nullptr;
     51     }
     52     return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
     53 }
     54 
     55 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
     56     buffer.writeFlattenable(fDst.get());
     57     buffer.writeFlattenable(fSrc.get());
     58     buffer.write32((int)fMode);
     59     buffer.writeScalar(fLerpT);
     60 }
     61 
     62 sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
     63     return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
     64                        fMode, fLerpT);
     65 }
     66 
     67 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     68 bool SkComposeShader::asACompose(ComposeRec* rec) const {
     69     if (!this->isJustMode()) {
     70         return false;
     71     }
     72 
     73     if (rec) {
     74         rec->fShaderA   = fDst.get();
     75         rec->fShaderB   = fSrc.get();
     76         rec->fBlendMode = fMode;
     77     }
     78     return true;
     79 }
     80 #endif
     81 
     82 bool SkComposeShader::onAppendStages(const StageRec& rec) const {
     83     struct Storage {
     84         float   fRGBA[4 * SkJumper_kMaxStride];
     85         float   fAlpha;
     86     };
     87     auto storage = rec.fAlloc->make<Storage>();
     88 
     89     if (!as_SB(fSrc)->appendStages(rec)) {
     90         return false;
     91     }
     92     // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
     93     // since fShaderB will overwrite them.
     94     rec.fPipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
     95 
     96     if (!as_SB(fDst)->appendStages(rec)) {
     97         return false;
     98     }
     99     // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp
    100     // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
    101     // reverse the two shader invocations, and avoid this move...
    102     rec.fPipeline->append(SkRasterPipeline::move_src_dst);
    103     rec.fPipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
    104 
    105     if (!this->isJustLerp()) {
    106         SkBlendMode_AppendStages(fMode, rec.fPipeline);
    107     }
    108     if (!this->isJustMode()) {
    109         rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
    110     }
    111     return true;
    112 }
    113 
    114 #if SK_SUPPORT_GPU
    115 
    116 #include "effects/GrConstColorProcessor.h"
    117 #include "effects/GrXfermodeFragmentProcessor.h"
    118 
    119 /////////////////////////////////////////////////////////////////////
    120 
    121 std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
    122         const GrFPArgs& args) const {
    123     if (this->isJustMode()) {
    124         SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
    125         if (fMode == SkBlendMode::kClear) {
    126             return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
    127                                                GrConstColorProcessor::InputMode::kIgnore);
    128         }
    129     }
    130 
    131     std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
    132     if (!fpA) {
    133         return nullptr;
    134     }
    135     std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
    136     if (!fpB) {
    137         return nullptr;
    138     }
    139     // TODO: account for fLerpT when it is < 1
    140     return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
    141                                                               std::move(fpA), fMode);
    142 }
    143 #endif
    144 
    145 #ifndef SK_IGNORE_TO_STRING
    146 void SkComposeShader::toString(SkString* str) const {
    147     str->append("SkComposeShader: (");
    148 
    149     str->append("dst: ");
    150     as_SB(fDst)->toString(str);
    151     str->append(" src: ");
    152     as_SB(fSrc)->toString(str);
    153     str->appendf(" mode: %s", SkBlendMode_Name(fMode));
    154     str->appendf(" lerpT: %g", fLerpT);
    155 
    156     this->INHERITED::toString(str);
    157 
    158     str->append(")");
    159 }
    160 #endif
    161