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 
     19 sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
     20                                       float lerpT) {
     21     if (!src || !dst || SkScalarIsNaN(lerpT)) {
     22         return nullptr;
     23     }
     24     lerpT = SkScalarPin(lerpT, 0, 1);
     25 
     26     if (lerpT == 0) {
     27         return dst;
     28     } else if (lerpT == 1) {
     29         if (mode == SkBlendMode::kSrc) {
     30             return src;
     31         }
     32         if (mode == SkBlendMode::kDst) {
     33             return dst;
     34         }
     35     }
     36     return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
     37 }
     38 
     39 ///////////////////////////////////////////////////////////////////////////////
     40 
     41 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
     42     sk_sp<SkShader> dst(buffer.readShader());
     43     sk_sp<SkShader> src(buffer.readShader());
     44     unsigned        mode = buffer.read32();
     45     float           lerp = buffer.readScalar();
     46 
     47     // check for valid mode before we cast to the enum type
     48     if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
     49         return nullptr;
     50     }
     51     return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
     52 }
     53 
     54 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
     55     buffer.writeFlattenable(fDst.get());
     56     buffer.writeFlattenable(fSrc.get());
     57     buffer.write32((int)fMode);
     58     buffer.writeScalar(fLerpT);
     59 }
     60 
     61 sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
     62     return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
     63                        fMode, fLerpT);
     64 }
     65 
     66 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     67 bool SkComposeShader::asACompose(ComposeRec* rec) const {
     68     if (!this->isJustMode()) {
     69         return false;
     70     }
     71 
     72     if (rec) {
     73         rec->fShaderA   = fDst.get();
     74         rec->fShaderB   = fSrc.get();
     75         rec->fBlendMode = fMode;
     76     }
     77     return true;
     78 }
     79 #endif
     80 
     81 bool SkComposeShader::onAppendStages(const StageRec& rec) const {
     82     struct Storage {
     83         float   fRGBA[4 * SkRasterPipeline_kMaxStride];
     84         float   fAlpha;
     85     };
     86     auto storage = rec.fAlloc->make<Storage>();
     87 
     88     if (!as_SB(fDst)->appendStages(rec)) {
     89         return false;
     90     }
     91     // This outputs r,g,b,a, which we'll need later when we apply the mode, so we save it off now
     92     rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRGBA);
     93 
     94     if (!as_SB(fSrc)->appendStages(rec)) {
     95         return false;
     96     }
     97     // r,g,b,a now have the right input for the next step (lerp and/or mode), but we need to
     98     // reload dr,dg,db,da from memory, since we stashed that from our fDst invocation earlier.
     99     rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRGBA);
    100 
    101     if (!this->isJustLerp()) {
    102         SkBlendMode_AppendStages(fMode, rec.fPipeline);
    103     }
    104     if (!this->isJustMode()) {
    105         rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
    106     }
    107     return true;
    108 }
    109 
    110 #if SK_SUPPORT_GPU
    111 
    112 #include "effects/GrConstColorProcessor.h"
    113 #include "effects/GrXfermodeFragmentProcessor.h"
    114 
    115 /////////////////////////////////////////////////////////////////////
    116 
    117 std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
    118         const GrFPArgs& args) const {
    119     if (this->isJustMode()) {
    120         SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
    121         if (fMode == SkBlendMode::kClear) {
    122             return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
    123                                                GrConstColorProcessor::InputMode::kIgnore);
    124         }
    125     }
    126 
    127     std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
    128     if (!fpA) {
    129         return nullptr;
    130     }
    131     std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
    132     if (!fpB) {
    133         return nullptr;
    134     }
    135     // TODO: account for fLerpT when it is < 1
    136     return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
    137                                                               std::move(fpA), fMode);
    138 }
    139 #endif
    140