Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2014 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 "GrDefaultGeoProcFactory.h"
      9 
     10 #include "SkRefCnt.h"
     11 #include "glsl/GrGLSLColorSpaceXformHelper.h"
     12 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     13 #include "glsl/GrGLSLGeometryProcessor.h"
     14 #include "glsl/GrGLSLVertexGeoBuilder.h"
     15 #include "glsl/GrGLSLVarying.h"
     16 #include "glsl/GrGLSLUniformHandler.h"
     17 #include "glsl/GrGLSLUtil.h"
     18 
     19 /*
     20  * The default Geometry Processor simply takes position and multiplies it by the uniform view
     21  * matrix. It also leaves coverage untouched.  Behind the scenes, we may add per vertex color or
     22  * local coords.
     23  */
     24 
     25 enum GPFlag {
     26     kColorAttribute_GPFlag          = 0x1,
     27     kColorAttributeIsSkColor_GPFlag = 0x2,
     28     kLocalCoordAttribute_GPFlag     = 0x4,
     29     kCoverageAttribute_GPFlag       = 0x8,
     30 
     31     kLinearizeColorAttribute_GPFlag = 0x10,
     32 };
     33 
     34 class DefaultGeoProc : public GrGeometryProcessor {
     35 public:
     36     static sk_sp<GrGeometryProcessor> Make(uint32_t gpTypeFlags,
     37                                            GrColor color,
     38                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
     39                                            const SkMatrix& viewMatrix,
     40                                            const SkMatrix& localMatrix,
     41                                            bool localCoordsWillBeRead,
     42                                            uint8_t coverage) {
     43         return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
     44                 gpTypeFlags, color, std::move(colorSpaceXform), viewMatrix, localMatrix, coverage,
     45                 localCoordsWillBeRead));
     46     }
     47 
     48     const char* name() const override { return "DefaultGeometryProcessor"; }
     49 
     50     const Attribute* inPosition() const { return fInPosition; }
     51     const Attribute* inColor() const { return fInColor; }
     52     const Attribute* inLocalCoords() const { return fInLocalCoords; }
     53     const Attribute* inCoverage() const { return fInCoverage; }
     54     GrColor color() const { return fColor; }
     55     bool hasVertexColor() const { return SkToBool(fInColor); }
     56     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     57     const SkMatrix& localMatrix() const { return fLocalMatrix; }
     58     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
     59     uint8_t coverage() const { return fCoverage; }
     60     bool hasVertexCoverage() const { return SkToBool(fInCoverage); }
     61     bool linearizeColor() const {
     62         // Linearization should only happen with SkColor
     63         bool linearize = SkToBool(fFlags & kLinearizeColorAttribute_GPFlag);
     64         SkASSERT(!linearize || (fFlags & kColorAttributeIsSkColor_GPFlag));
     65         return linearize;
     66     }
     67 
     68     class GLSLProcessor : public GrGLSLGeometryProcessor {
     69     public:
     70         GLSLProcessor()
     71             : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverage(0xff) {}
     72 
     73         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
     74             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
     75             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
     76             GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
     77             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
     78             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
     79 
     80             // emit attributes
     81             varyingHandler->emitAttributes(gp);
     82 
     83             // Setup pass through color
     84             if (gp.hasVertexColor()) {
     85                 GrGLSLVarying varying(kHalf4_GrSLType);
     86                 varyingHandler->addVarying("color", &varying);
     87 
     88                 // There are several optional steps to process the color. Start with the attribute:
     89                 vertBuilder->codeAppendf("half4 color = %s;", gp.inColor()->fName);
     90 
     91                 // Linearize
     92                 if (gp.linearizeColor()) {
     93                     SkString srgbFuncName;
     94                     static const GrShaderVar gSrgbArgs[] = {
     95                         GrShaderVar("x", kHalf_GrSLType),
     96                     };
     97                     vertBuilder->emitFunction(kHalf_GrSLType,
     98                                               "srgb_to_linear",
     99                                               SK_ARRAY_COUNT(gSrgbArgs),
    100                                               gSrgbArgs,
    101                                               "return (x <= 0.04045) ? (x / 12.92) "
    102                                               ": pow((x + 0.055) / 1.055, 2.4);",
    103                                               &srgbFuncName);
    104                     vertBuilder->codeAppendf("color = half4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);",
    105                                              srgbFuncName.c_str(), gp.inColor()->fName,
    106                                              srgbFuncName.c_str(), gp.inColor()->fName,
    107                                              srgbFuncName.c_str(), gp.inColor()->fName,
    108                                              gp.inColor()->fName);
    109                 }
    110 
    111                 // For SkColor, do a red/blue swap and premul
    112                 if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) {
    113                     vertBuilder->codeAppend("color = half4(color.a * color.bgr, color.a);");
    114                 }
    115 
    116                 // Do color-correction to destination gamut
    117                 if (gp.linearizeColor()) {
    118                     fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
    119                                                kVertex_GrShaderFlag);
    120                     if (fColorSpaceHelper.isValid()) {
    121                         SkString xformedColor;
    122                         vertBuilder->appendColorGamutXform(&xformedColor, "color",
    123                                                            &fColorSpaceHelper);
    124                         vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
    125                     }
    126                 }
    127                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
    128                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
    129             } else {
    130                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
    131                                         &fColorUniform);
    132             }
    133 
    134             // Setup position
    135             this->writeOutputPosition(vertBuilder,
    136                                       uniformHandler,
    137                                       gpArgs,
    138                                       gp.inPosition()->fName,
    139                                       gp.viewMatrix(),
    140                                       &fViewMatrixUniform);
    141 
    142             if (gp.hasExplicitLocalCoords()) {
    143                 // emit transforms with explicit local coords
    144                 this->emitTransforms(vertBuilder,
    145                                      varyingHandler,
    146                                      uniformHandler,
    147                                      gp.inLocalCoords()->asShaderVar(),
    148                                      gp.localMatrix(),
    149                                      args.fFPCoordTransformHandler);
    150             } else {
    151                 // emit transforms with position
    152                 this->emitTransforms(vertBuilder,
    153                                      varyingHandler,
    154                                      uniformHandler,
    155                                      gp.inPosition()->asShaderVar(),
    156                                      gp.localMatrix(),
    157                                      args.fFPCoordTransformHandler);
    158             }
    159 
    160             // Setup coverage as pass through
    161             if (gp.hasVertexCoverage()) {
    162                 fragBuilder->codeAppendf("half alpha = 1.0;");
    163                 varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
    164                 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
    165             } else if (gp.coverage() == 0xff) {
    166                 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
    167             } else {
    168                 const char* fragCoverage;
    169                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    170                                                               kHalf_GrSLType,
    171                                                               "Coverage",
    172                                                               &fragCoverage);
    173                 fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage);
    174             }
    175         }
    176 
    177         static inline void GenKey(const GrGeometryProcessor& gp,
    178                                   const GrShaderCaps&,
    179                                   GrProcessorKeyBuilder* b) {
    180             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
    181             uint32_t key = def.fFlags;
    182             key |= (def.coverage() == 0xff) ? 0x10 : 0;
    183             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
    184             key |= ComputePosKey(def.viewMatrix()) << 20;
    185             b->add32(key);
    186             if (def.linearizeColor()) {
    187                 b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
    188             }
    189         }
    190 
    191         void setData(const GrGLSLProgramDataManager& pdman,
    192                      const GrPrimitiveProcessor& gp,
    193                      FPCoordTransformIter&& transformIter) override {
    194             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
    195 
    196             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
    197                 fViewMatrix = dgp.viewMatrix();
    198                 float viewMatrix[3 * 3];
    199                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
    200                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
    201             }
    202 
    203             if (dgp.color() != fColor && !dgp.hasVertexColor()) {
    204                 float c[4];
    205                 GrColorToRGBAFloat(dgp.color(), c);
    206                 pdman.set4fv(fColorUniform, 1, c);
    207                 fColor = dgp.color();
    208             }
    209 
    210             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
    211                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
    212                 fCoverage = dgp.coverage();
    213             }
    214             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
    215 
    216             if (dgp.linearizeColor() && dgp.fColorSpaceXform) {
    217                 fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
    218             }
    219         }
    220 
    221     private:
    222         SkMatrix fViewMatrix;
    223         GrColor fColor;
    224         uint8_t fCoverage;
    225         UniformHandle fViewMatrixUniform;
    226         UniformHandle fColorUniform;
    227         UniformHandle fCoverageUniform;
    228         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
    229 
    230         typedef GrGLSLGeometryProcessor INHERITED;
    231     };
    232 
    233     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
    234         GLSLProcessor::GenKey(*this, caps, b);
    235     }
    236 
    237     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
    238         return new GLSLProcessor();
    239     }
    240 
    241 private:
    242     DefaultGeoProc(uint32_t gpTypeFlags,
    243                    GrColor color,
    244                    sk_sp<GrColorSpaceXform> colorSpaceXform,
    245                    const SkMatrix& viewMatrix,
    246                    const SkMatrix& localMatrix,
    247                    uint8_t coverage,
    248                    bool localCoordsWillBeRead)
    249             : INHERITED(kDefaultGeoProc_ClassID)
    250             , fColor(color)
    251             , fViewMatrix(viewMatrix)
    252             , fLocalMatrix(localMatrix)
    253             , fCoverage(coverage)
    254             , fFlags(gpTypeFlags)
    255             , fLocalCoordsWillBeRead(localCoordsWillBeRead)
    256             , fColorSpaceXform(std::move(colorSpaceXform)) {
    257         fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
    258         if (fFlags & kColorAttribute_GPFlag) {
    259             fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
    260         }
    261         if (fFlags & kLocalCoordAttribute_GPFlag) {
    262             fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kFloat2_GrVertexAttribType);
    263             this->setHasExplicitLocalCoords();
    264         }
    265         if (fFlags & kCoverageAttribute_GPFlag) {
    266             fInCoverage = &this->addVertexAttrib("inCoverage", kHalf_GrVertexAttribType);
    267         }
    268     }
    269 
    270     const Attribute* fInPosition = nullptr;
    271     const Attribute* fInColor = nullptr;
    272     const Attribute* fInLocalCoords = nullptr;
    273     const Attribute* fInCoverage = nullptr;
    274     GrColor fColor;
    275     SkMatrix fViewMatrix;
    276     SkMatrix fLocalMatrix;
    277     uint8_t fCoverage;
    278     uint32_t fFlags;
    279     bool fLocalCoordsWillBeRead;
    280     sk_sp<GrColorSpaceXform> fColorSpaceXform;
    281 
    282     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
    283 
    284     typedef GrGeometryProcessor INHERITED;
    285 };
    286 
    287 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
    288 
    289 #if GR_TEST_UTILS
    290 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
    291     uint32_t flags = 0;
    292     if (d->fRandom->nextBool()) {
    293         flags |= kColorAttribute_GPFlag;
    294     }
    295     if (d->fRandom->nextBool()) {
    296         flags |= kColorAttributeIsSkColor_GPFlag;
    297     }
    298     if (d->fRandom->nextBool()) {
    299         flags |= kCoverageAttribute_GPFlag;
    300     }
    301     if (d->fRandom->nextBool()) {
    302         flags |= kLocalCoordAttribute_GPFlag;
    303     }
    304 
    305     return DefaultGeoProc::Make(flags,
    306                                 GrRandomColor(d->fRandom),
    307                                 GrTest::TestColorXform(d->fRandom),
    308                                 GrTest::TestMatrix(d->fRandom),
    309                                 GrTest::TestMatrix(d->fRandom),
    310                                 d->fRandom->nextBool(),
    311                                 GrRandomCoverage(d->fRandom));
    312 }
    313 #endif
    314 
    315 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
    316                                                          const Coverage& coverage,
    317                                                          const LocalCoords& localCoords,
    318                                                          const SkMatrix& viewMatrix) {
    319     uint32_t flags = 0;
    320     if (Color::kPremulGrColorAttribute_Type == color.fType) {
    321         flags |= kColorAttribute_GPFlag;
    322     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
    323         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
    324     }
    325     if (color.fLinearize) {
    326         // It only makes sense to linearize SkColors (which are always sRGB). GrColor values should
    327         // have been linearized and gamut-converted during paint conversion
    328         SkASSERT(Color::kUnpremulSkColorAttribute_Type == color.fType);
    329         flags |= kLinearizeColorAttribute_GPFlag;
    330     }
    331     flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
    332     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
    333 
    334     uint8_t inCoverage = coverage.fCoverage;
    335     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
    336 
    337     GrColor inColor = color.fColor;
    338     return DefaultGeoProc::Make(flags,
    339                                 inColor,
    340                                 color.fColorSpaceXform,
    341                                 viewMatrix,
    342                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
    343                                 localCoordsWillBeRead,
    344                                 inCoverage);
    345 }
    346 
    347 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
    348                                                                      const Color& color,
    349                                                                      const Coverage& coverage,
    350                                                                      const LocalCoords& localCoords,
    351                                                                      const SkMatrix& viewMatrix) {
    352     SkMatrix invert = SkMatrix::I();
    353     if (LocalCoords::kUnused_Type != localCoords.fType) {
    354         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
    355         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
    356             return nullptr;
    357         }
    358 
    359         if (localCoords.hasLocalMatrix()) {
    360             invert.preConcat(*localCoords.fMatrix);
    361         }
    362     }
    363 
    364     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
    365     return Make(color, coverage, inverted, SkMatrix::I());
    366 }
    367