Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2015 Google Inc.
      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 "SkArithmeticMode_gpu.h"
      9 
     10 #if SK_SUPPORT_GPU
     11 #include "GrContext.h"
     12 #include "GrFragmentProcessor.h"
     13 #include "GrInvariantOutput.h"
     14 #include "GrProcessor.h"
     15 #include "GrTexture.h"
     16 #include "gl/GrGLCaps.h"
     17 #include "gl/GrGLProcessor.h"
     18 #include "gl/GrGLProgramDataManager.h"
     19 #include "gl/builders/GrGLProgramBuilder.h"
     20 
     21 static const bool gUseUnpremul = false;
     22 
     23 static void add_arithmetic_code(GrGLFragmentBuilder* fsBuilder,
     24                                 const char* inputColor,
     25                                 const char* dstColor,
     26                                 const char* outputColor,
     27                                 const char* kUni,
     28                                 bool enforcePMColor) {
     29     // We don't try to optimize for this case at all
     30     if (NULL == inputColor) {
     31         fsBuilder->codeAppend("const vec4 src = vec4(1);");
     32     } else {
     33         fsBuilder->codeAppendf("vec4 src = %s;", inputColor);
     34         if (gUseUnpremul) {
     35             fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
     36         }
     37     }
     38 
     39     fsBuilder->codeAppendf("vec4 dst = %s;", dstColor);
     40     if (gUseUnpremul) {
     41         fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);");
     42     }
     43 
     44     fsBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
     45                            outputColor, kUni, kUni, kUni, kUni);
     46     fsBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
     47     if (gUseUnpremul) {
     48         fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
     49     } else if (enforcePMColor) {
     50         fsBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);",
     51                                outputColor, outputColor, outputColor);
     52     }
     53 }
     54 
     55 class GLArithmeticFP : public GrGLFragmentProcessor {
     56 public:
     57     GLArithmeticFP(const GrProcessor&)
     58         : fEnforcePMColor(true) {
     59     }
     60 
     61     ~GLArithmeticFP() override {}
     62 
     63     void emitCode(GrGLFPBuilder* builder,
     64                   const GrFragmentProcessor& fp,
     65                   const char* outputColor,
     66                   const char* inputColor,
     67                   const TransformedCoordsArray& coords,
     68                   const TextureSamplerArray& samplers) override {
     69         GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     70         fsBuilder->codeAppend("vec4 bgColor = ");
     71         fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
     72         fsBuilder->codeAppendf(";");
     73         const char* dstColor = "bgColor";
     74 
     75         fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
     76                                     kVec4f_GrSLType, kDefault_GrSLPrecision,
     77                                     "k");
     78         const char* kUni = builder->getUniformCStr(fKUni);
     79 
     80         add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni, fEnforcePMColor);
     81     }
     82 
     83     void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) override {
     84         const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
     85         pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
     86         fEnforcePMColor = arith.enforcePMColor();
     87     }
     88 
     89     static void GenKey(const GrProcessor& proc, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
     90         const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
     91         uint32_t key = arith.enforcePMColor() ? 1 : 0;
     92         b->add32(key);
     93     }
     94 
     95 private:
     96     GrGLProgramDataManager::UniformHandle fKUni;
     97     bool fEnforcePMColor;
     98 
     99     typedef GrGLFragmentProcessor INHERITED;
    100 };
    101 
    102 ///////////////////////////////////////////////////////////////////////////////
    103 
    104 GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4,
    105                                bool enforcePMColor, GrTexture* background)
    106   : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
    107     this->initClassID<GrArithmeticFP>();
    108 
    109     SkASSERT(background);
    110 
    111     fBackgroundTransform.reset(kLocal_GrCoordSet, background,
    112                                GrTextureParams::kNone_FilterMode);
    113     this->addCoordTransform(&fBackgroundTransform);
    114     fBackgroundAccess.reset(background);
    115     this->addTextureAccess(&fBackgroundAccess);
    116 }
    117 
    118 void GrArithmeticFP::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
    119     GLArithmeticFP::GenKey(*this, caps, b);
    120 }
    121 
    122 GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const {
    123     return SkNEW_ARGS(GLArithmeticFP, (*this));
    124 }
    125 
    126 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
    127     const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
    128     return fK1 == fp.fK1 &&
    129            fK2 == fp.fK2 &&
    130            fK3 == fp.fK3 &&
    131            fK4 == fp.fK4 &&
    132            fEnforcePMColor == fp.fEnforcePMColor;
    133 }
    134 
    135 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    136     // TODO: optimize this
    137     inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
    138 }
    139 
    140 ///////////////////////////////////////////////////////////////////////////////
    141 
    142 GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand,
    143                                                 GrContext*,
    144                                                 const GrDrawTargetCaps&,
    145                                                 GrTexture* textures[]) {
    146     float k1 = rand->nextF();
    147     float k2 = rand->nextF();
    148     float k3 = rand->nextF();
    149     float k4 = rand->nextF();
    150     bool enforcePMColor = rand->nextBool();
    151 
    152     return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, textures[0]));
    153 }
    154 
    155 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
    156 
    157 ///////////////////////////////////////////////////////////////////////////////
    158 // Xfer Processor
    159 ///////////////////////////////////////////////////////////////////////////////
    160 
    161 class ArithmeticXP : public GrXferProcessor {
    162 public:
    163     static GrXferProcessor* Create(float k1, float k2, float k3, float k4, bool enforcePMColor,
    164                                    const GrDeviceCoordTexture* dstCopy,
    165                                    bool willReadDstColor) {
    166         return SkNEW_ARGS(ArithmeticXP, (k1, k2, k3, k4, enforcePMColor, dstCopy,
    167                                          willReadDstColor));
    168     }
    169 
    170     ~ArithmeticXP() override {};
    171 
    172     const char* name() const override { return "Arithmetic"; }
    173 
    174     GrGLXferProcessor* createGLInstance() const override;
    175 
    176     bool hasSecondaryOutput() const override { return false; }
    177 
    178     float k1() const { return fK1; }
    179     float k2() const { return fK2; }
    180     float k3() const { return fK3; }
    181     float k4() const { return fK4; }
    182     bool enforcePMColor() const { return fEnforcePMColor; }
    183 
    184 private:
    185     ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
    186                    const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
    187 
    188     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
    189                                                  const GrProcOptInfo& coveragePOI,
    190                                                  bool doesStencilWrite,
    191                                                  GrColor* overrideColor,
    192                                                  const GrDrawTargetCaps& caps) override;
    193 
    194     void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
    195 
    196     bool onIsEqual(const GrXferProcessor& xpBase) const override {
    197         const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
    198         if (fK1 != xp.fK1 ||
    199             fK2 != xp.fK2 ||
    200             fK3 != xp.fK3 ||
    201             fK4 != xp.fK4 ||
    202             fEnforcePMColor != xp.fEnforcePMColor) {
    203             return false;
    204         }
    205         return true;
    206     }
    207 
    208     float                       fK1, fK2, fK3, fK4;
    209     bool                        fEnforcePMColor;
    210 
    211     typedef GrXferProcessor INHERITED;
    212 };
    213 
    214 ///////////////////////////////////////////////////////////////////////////////
    215 
    216 class GLArithmeticXP : public GrGLXferProcessor {
    217 public:
    218     GLArithmeticXP(const GrProcessor&)
    219         : fEnforcePMColor(true) {
    220     }
    221 
    222     ~GLArithmeticXP() override {}
    223 
    224     static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
    225                        GrProcessorKeyBuilder* b) {
    226         const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
    227         uint32_t key = arith.enforcePMColor() ? 1 : 0;
    228         b->add32(key);
    229     }
    230 
    231 private:
    232     void onEmitCode(const EmitArgs& args) override {
    233         GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
    234 
    235         const char* dstColor = fsBuilder->dstColor();
    236 
    237         fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
    238                                      kVec4f_GrSLType, kDefault_GrSLPrecision,
    239                                      "k");
    240         const char* kUni = args.fPB->getUniformCStr(fKUni);
    241 
    242         add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni,
    243                             fEnforcePMColor);
    244 
    245         fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
    246                                args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
    247                                args.fInputCoverage, dstColor);
    248     }
    249 
    250     void onSetData(const GrGLProgramDataManager& pdman,
    251                    const GrXferProcessor& processor) override {
    252         const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
    253         pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
    254         fEnforcePMColor = arith.enforcePMColor();
    255     };
    256 
    257     GrGLProgramDataManager::UniformHandle fKUni;
    258     bool fEnforcePMColor;
    259 
    260     typedef GrGLXferProcessor INHERITED;
    261 };
    262 
    263 ///////////////////////////////////////////////////////////////////////////////
    264 
    265 ArithmeticXP::ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
    266                            const GrDeviceCoordTexture* dstCopy, bool willReadDstColor)
    267     : INHERITED(dstCopy, willReadDstColor)
    268     , fK1(k1)
    269     , fK2(k2)
    270     , fK3(k3)
    271     , fK4(k4)
    272     , fEnforcePMColor(enforcePMColor) {
    273     this->initClassID<ArithmeticXP>();
    274 }
    275 
    276 void ArithmeticXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
    277     GLArithmeticXP::GenKey(*this, caps, b);
    278 }
    279 
    280 GrGLXferProcessor* ArithmeticXP::createGLInstance() const {
    281     return SkNEW_ARGS(GLArithmeticXP, (*this));
    282 }
    283 
    284 GrXferProcessor::OptFlags ArithmeticXP::onGetOptimizations(const GrProcOptInfo& colorPOI,
    285                                                            const GrProcOptInfo& coveragePOI,
    286                                                            bool doesStencilWrite,
    287                                                            GrColor* overrideColor,
    288                                                            const GrDrawTargetCaps& caps) {
    289    return GrXferProcessor::kNone_Opt;
    290 }
    291 
    292 ///////////////////////////////////////////////////////////////////////////////
    293 
    294 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
    295                                              bool enforcePMColor)
    296     : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
    297     this->initClassID<GrArithmeticXPFactory>();
    298 }
    299 
    300 GrXferProcessor*
    301 GrArithmeticXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
    302                                              const GrProcOptInfo& colorPOI,
    303                                              const GrProcOptInfo& coveragePOI,
    304                                              const GrDeviceCoordTexture* dstCopy) const {
    305     return ArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor, dstCopy,
    306                                 this->willReadDstColor(caps, colorPOI, coveragePOI));
    307 }
    308 
    309 
    310 void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
    311                                                const GrProcOptInfo& coveragePOI,
    312                                                GrXPFactory::InvariantOutput* output) const {
    313     output->fWillBlendWithDst = true;
    314 
    315     // TODO: We could try to optimize this more. For example if we have solid coverage and fK1 and
    316     // fK3 are zero, then we won't be blending the color with dst at all so we can know what the
    317     // output color is (up to the valid color components passed in).
    318     output->fBlendedColorFlags = 0;
    319 }
    320 
    321 GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
    322 
    323 GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random,
    324                                                GrContext*,
    325                                                const GrDrawTargetCaps&,
    326                                                GrTexture*[]) {
    327     float k1 = random->nextF();
    328     float k2 = random->nextF();
    329     float k3 = random->nextF();
    330     float k4 = random->nextF();
    331     bool enforcePMColor = random->nextBool();
    332 
    333     return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);
    334 }
    335 
    336 #endif
    337