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/GrGLSLVertexShaderBuilder.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                 GrGLSLVertToFrag varying(kVec4f_GrSLType);
     86                 varyingHandler->addVarying("color", &varying);
     87 
     88                 // There are several optional steps to process the color. Start with the attribute:
     89                 vertBuilder->codeAppendf("vec4 color = %s;", gp.inColor()->fName);
     90 
     91                 // Linearize
     92                 if (gp.linearizeColor()) {
     93                     SkString srgbFuncName;
     94                     static const GrShaderVar gSrgbArgs[] = {
     95                         GrShaderVar("x", kFloat_GrSLType),
     96                     };
     97                     vertBuilder->emitFunction(kFloat_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 = vec4(%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 = vec4(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->setupPosition(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                                      gpArgs->fPositionVar,
    148                                      gp.inLocalCoords()->fName,
    149                                      gp.localMatrix(),
    150                                      args.fFPCoordTransformHandler);
    151             } else {
    152                 // emit transforms with position
    153                 this->emitTransforms(vertBuilder,
    154                                      varyingHandler,
    155                                      uniformHandler,
    156                                      gpArgs->fPositionVar,
    157                                      gp.inPosition()->fName,
    158                                      gp.localMatrix(),
    159                                      args.fFPCoordTransformHandler);
    160             }
    161 
    162             // Setup coverage as pass through
    163             if (gp.hasVertexCoverage()) {
    164                 fragBuilder->codeAppendf("float alpha = 1.0;");
    165                 varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
    166                 fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
    167             } else if (gp.coverage() == 0xff) {
    168                 fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
    169             } else {
    170                 const char* fragCoverage;
    171                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    172                                                               kFloat_GrSLType,
    173                                                               kDefault_GrSLPrecision,
    174                                                               "Coverage",
    175                                                               &fragCoverage);
    176                 fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage);
    177             }
    178         }
    179 
    180         static inline void GenKey(const GrGeometryProcessor& gp,
    181                                   const GrShaderCaps&,
    182                                   GrProcessorKeyBuilder* b) {
    183             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
    184             uint32_t key = def.fFlags;
    185             key |= (def.coverage() == 0xff) ? 0x10 : 0;
    186             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
    187             key |= ComputePosKey(def.viewMatrix()) << 20;
    188             b->add32(key);
    189             if (def.linearizeColor()) {
    190                 b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
    191             }
    192         }
    193 
    194         void setData(const GrGLSLProgramDataManager& pdman,
    195                      const GrPrimitiveProcessor& gp,
    196                      FPCoordTransformIter&& transformIter) override {
    197             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
    198 
    199             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
    200                 fViewMatrix = dgp.viewMatrix();
    201                 float viewMatrix[3 * 3];
    202                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
    203                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
    204             }
    205 
    206             if (dgp.color() != fColor && !dgp.hasVertexColor()) {
    207                 float c[4];
    208                 GrColorToRGBAFloat(dgp.color(), c);
    209                 pdman.set4fv(fColorUniform, 1, c);
    210                 fColor = dgp.color();
    211             }
    212 
    213             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
    214                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
    215                 fCoverage = dgp.coverage();
    216             }
    217             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
    218 
    219             if (dgp.linearizeColor() && dgp.fColorSpaceXform) {
    220                 fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
    221             }
    222         }
    223 
    224     private:
    225         SkMatrix fViewMatrix;
    226         GrColor fColor;
    227         uint8_t fCoverage;
    228         UniformHandle fViewMatrixUniform;
    229         UniformHandle fColorUniform;
    230         UniformHandle fCoverageUniform;
    231         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
    232 
    233         typedef GrGLSLGeometryProcessor INHERITED;
    234     };
    235 
    236     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
    237         GLSLProcessor::GenKey(*this, caps, b);
    238     }
    239 
    240     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
    241         return new GLSLProcessor();
    242     }
    243 
    244 private:
    245     DefaultGeoProc(uint32_t gpTypeFlags,
    246                    GrColor color,
    247                    sk_sp<GrColorSpaceXform> colorSpaceXform,
    248                    const SkMatrix& viewMatrix,
    249                    const SkMatrix& localMatrix,
    250                    uint8_t coverage,
    251                    bool localCoordsWillBeRead)
    252             : fColor(color)
    253             , fViewMatrix(viewMatrix)
    254             , fLocalMatrix(localMatrix)
    255             , fCoverage(coverage)
    256             , fFlags(gpTypeFlags)
    257             , fLocalCoordsWillBeRead(localCoordsWillBeRead)
    258             , fColorSpaceXform(std::move(colorSpaceXform)) {
    259         this->initClassID<DefaultGeoProc>();
    260         fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
    261                                              kHigh_GrSLPrecision);
    262         if (fFlags & kColorAttribute_GPFlag) {
    263             fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
    264         }
    265         if (fFlags & kLocalCoordAttribute_GPFlag) {
    266             fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kVec2f_GrVertexAttribType,
    267                                                     kHigh_GrSLPrecision);
    268             this->setHasExplicitLocalCoords();
    269         }
    270         if (fFlags & kCoverageAttribute_GPFlag) {
    271             fInCoverage = &this->addVertexAttrib("inCoverage", kFloat_GrVertexAttribType);
    272         }
    273     }
    274 
    275     const Attribute* fInPosition = nullptr;
    276     const Attribute* fInColor = nullptr;
    277     const Attribute* fInLocalCoords = nullptr;
    278     const Attribute* fInCoverage = nullptr;
    279     GrColor fColor;
    280     SkMatrix fViewMatrix;
    281     SkMatrix fLocalMatrix;
    282     uint8_t fCoverage;
    283     uint32_t fFlags;
    284     bool fLocalCoordsWillBeRead;
    285     sk_sp<GrColorSpaceXform> fColorSpaceXform;
    286 
    287     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
    288 
    289     typedef GrGeometryProcessor INHERITED;
    290 };
    291 
    292 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
    293 
    294 #if GR_TEST_UTILS
    295 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
    296     uint32_t flags = 0;
    297     if (d->fRandom->nextBool()) {
    298         flags |= kColorAttribute_GPFlag;
    299     }
    300     if (d->fRandom->nextBool()) {
    301         flags |= kColorAttributeIsSkColor_GPFlag;
    302     }
    303     if (d->fRandom->nextBool()) {
    304         flags |= kCoverageAttribute_GPFlag;
    305     }
    306     if (d->fRandom->nextBool()) {
    307         flags |= kLocalCoordAttribute_GPFlag;
    308     }
    309 
    310     return DefaultGeoProc::Make(flags,
    311                                 GrRandomColor(d->fRandom),
    312                                 GrTest::TestColorXform(d->fRandom),
    313                                 GrTest::TestMatrix(d->fRandom),
    314                                 GrTest::TestMatrix(d->fRandom),
    315                                 d->fRandom->nextBool(),
    316                                 GrRandomCoverage(d->fRandom));
    317 }
    318 #endif
    319 
    320 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
    321                                                          const Coverage& coverage,
    322                                                          const LocalCoords& localCoords,
    323                                                          const SkMatrix& viewMatrix) {
    324     uint32_t flags = 0;
    325     if (Color::kPremulGrColorAttribute_Type == color.fType) {
    326         flags |= kColorAttribute_GPFlag;
    327     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
    328         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
    329     }
    330     if (color.fLinearize) {
    331         // It only makes sense to linearize SkColors (which are always sRGB). GrColor values should
    332         // have been linearized and gamut-converted during paint conversion
    333         SkASSERT(Color::kUnpremulSkColorAttribute_Type == color.fType);
    334         flags |= kLinearizeColorAttribute_GPFlag;
    335     }
    336     flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
    337     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
    338 
    339     uint8_t inCoverage = coverage.fCoverage;
    340     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
    341 
    342     GrColor inColor = color.fColor;
    343     return DefaultGeoProc::Make(flags,
    344                                 inColor,
    345                                 color.fColorSpaceXform,
    346                                 viewMatrix,
    347                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
    348                                 localCoordsWillBeRead,
    349                                 inCoverage);
    350 }
    351 
    352 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
    353                                                                      const Color& color,
    354                                                                      const Coverage& coverage,
    355                                                                      const LocalCoords& localCoords,
    356                                                                      const SkMatrix& viewMatrix) {
    357     SkMatrix invert = SkMatrix::I();
    358     if (LocalCoords::kUnused_Type != localCoords.fType) {
    359         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
    360         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
    361             return nullptr;
    362         }
    363 
    364         if (localCoords.hasLocalMatrix()) {
    365             invert.preConcat(*localCoords.fMatrix);
    366         }
    367     }
    368 
    369     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
    370     return Make(color, coverage, inverted, SkMatrix::I());
    371 }
    372