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 "src/gpu/GrDefaultGeoProcFactory.h" 9 10#include "include/core/SkRefCnt.h" 11#include "src/core/SkArenaAlloc.h" 12#include "src/gpu/GrCaps.h" 13#include "src/gpu/GrGeometryProcessor.h" 14#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 15#include "src/gpu/glsl/GrGLSLUniformHandler.h" 16#include "src/gpu/glsl/GrGLSLVarying.h" 17#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.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 25enum GPFlag { 26 kColorAttribute_GPFlag = 0x1, 27 kColorAttributeIsWide_GPFlag = 0x2, 28 kLocalCoordAttribute_GPFlag = 0x4, 29 kCoverageAttribute_GPFlag = 0x8, 30 kCoverageAttributeTweak_GPFlag = 0x10, 31 kCoverageAttributeUnclamped_GPFlag = 0x20, 32}; 33 34class DefaultGeoProc : public GrGeometryProcessor { 35public: 36 static GrGeometryProcessor* Make(SkArenaAlloc* arena, 37 uint32_t gpTypeFlags, 38 const SkPMColor4f& color, 39 const SkMatrix& viewMatrix, 40 const SkMatrix& localMatrix, 41 bool localCoordsWillBeRead, 42 uint8_t coverage) { 43 return arena->make([&](void* ptr) { 44 return new (ptr) DefaultGeoProc(gpTypeFlags, color, viewMatrix, localMatrix, coverage, 45 localCoordsWillBeRead); 46 }); 47 } 48 49 const char* name() const override { return "DefaultGeometryProcessor"; } 50 51 SkString getShaderDfxInfo() const override { 52 SkString format; 53 format.printf("ShaderDfx_DefaultGeoProc_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d", 54 fFlags, fCoverage, fLocalCoordsWillBeRead, fInLocalCoords.isInitialized(), 55 fViewMatrix.isIdentity(), fViewMatrix.isScaleTranslate(), fViewMatrix.hasPerspective(), 56 fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 57 return format; 58 } 59 60 void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 61 uint32_t key = fFlags; 62 key |= fCoverage == 0xff ? 0x80 : 0; 63 key |= fLocalCoordsWillBeRead ? 0x100 : 0; 64 65 bool usesLocalMatrix = fLocalCoordsWillBeRead && !fInLocalCoords.isInitialized(); 66 key = ProgramImpl::AddMatrixKeys(caps, 67 key, 68 fViewMatrix, 69 usesLocalMatrix ? fLocalMatrix : SkMatrix::I()); 70 b->add32(key); 71 } 72 73 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override { 74 return std::make_unique<Impl>(); 75 } 76 77private: 78 class Impl : public ProgramImpl { 79 public: 80 void setData(const GrGLSLProgramDataManager& pdman, 81 const GrShaderCaps& shaderCaps, 82 const GrGeometryProcessor& geomProc) override { 83 const DefaultGeoProc& dgp = geomProc.cast<DefaultGeoProc>(); 84 85 SetTransform(pdman, shaderCaps, fViewMatrixUniform, dgp.fViewMatrix, &fViewMatrixPrev); 86 SetTransform(pdman, 87 shaderCaps, 88 fLocalMatrixUniform, 89 dgp.fLocalMatrix, 90 &fLocalMatrixPrev); 91 92 if (!dgp.hasVertexColor() && dgp.fColor != fColor) { 93 pdman.set4fv(fColorUniform, 1, dgp.fColor.vec()); 94 fColor = dgp.fColor; 95 } 96 97 if (dgp.fCoverage != fCoverage && !dgp.hasVertexCoverage()) { 98 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.fCoverage)); 99 fCoverage = dgp.fCoverage; 100 } 101 } 102 103 private: 104 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 105 const DefaultGeoProc& gp = args.fGeomProc.cast<DefaultGeoProc>(); 106 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 107 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 108 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 109 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 110 111 // emit attributes 112 varyingHandler->emitAttributes(gp); 113 114 bool tweakAlpha = SkToBool(gp.fFlags & kCoverageAttributeTweak_GPFlag); 115 bool coverageNeedsSaturate = SkToBool(gp.fFlags & kCoverageAttributeUnclamped_GPFlag); 116 SkASSERT(!tweakAlpha || gp.hasVertexCoverage()); 117 SkASSERT(!tweakAlpha || !coverageNeedsSaturate); 118 119 // Setup pass through color 120 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 121 if (gp.hasVertexColor() || tweakAlpha) { 122 GrGLSLVarying varying(kHalf4_GrSLType); 123 varyingHandler->addVarying("color", &varying); 124 125 // Start with the attribute or with uniform color 126 if (gp.hasVertexColor()) { 127 vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name()); 128 } else { 129 const char* colorUniformName; 130 fColorUniform = uniformHandler->addUniform(nullptr, 131 kVertex_GrShaderFlag, 132 kHalf4_GrSLType, 133 "Color", 134 &colorUniformName); 135 vertBuilder->codeAppendf("half4 color = %s;", colorUniformName); 136 } 137 138 // Optionally fold coverage into alpha (color). 139 if (tweakAlpha) { 140 vertBuilder->codeAppendf("color = color * %s;", gp.fInCoverage.name()); 141 } 142 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut()); 143 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); 144 } else { 145 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, 146 &fColorUniform); 147 } 148 149 // Setup position 150 WriteOutputPosition(vertBuilder, 151 uniformHandler, 152 *args.fShaderCaps, 153 gpArgs, 154 gp.fInPosition.name(), 155 gp.fViewMatrix, 156 &fViewMatrixUniform); 157 158 // emit transforms using either explicit local coords or positions 159 if (gp.fInLocalCoords.isInitialized()) { 160 SkASSERT(gp.fLocalMatrix.isIdentity()); 161 gpArgs->fLocalCoordVar = gp.fInLocalCoords.asShaderVar(); 162 } else if (gp.fLocalCoordsWillBeRead) { 163 WriteLocalCoord(vertBuilder, 164 uniformHandler, 165 *args.fShaderCaps, 166 gpArgs, 167 gp.fInPosition.asShaderVar(), 168 gp.fLocalMatrix, 169 &fLocalMatrixUniform); 170 } 171 172 // Setup coverage as pass through 173 if (gp.hasVertexCoverage() && !tweakAlpha) { 174 fragBuilder->codeAppendf("half alpha = 1.0;"); 175 varyingHandler->addPassThroughAttribute(gp.fInCoverage.asShaderVar(), "alpha"); 176 if (coverageNeedsSaturate) { 177 fragBuilder->codeAppendf("half4 %s = half4(saturate(alpha));", 178 args.fOutputCoverage); 179 } else { 180 fragBuilder->codeAppendf("half4 %s = half4(alpha);", args.fOutputCoverage); 181 } 182 } else if (gp.fCoverage == 0xff) { 183 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage); 184 } else { 185 const char* fragCoverage; 186 fCoverageUniform = uniformHandler->addUniform(nullptr, 187 kFragment_GrShaderFlag, 188 kHalf_GrSLType, 189 "Coverage", 190 &fragCoverage); 191 fragBuilder->codeAppendf("half4 %s = half4(%s);", 192 args.fOutputCoverage, fragCoverage); 193 } 194 } 195 196 SkMatrix fViewMatrixPrev = SkMatrix::InvalidMatrix(); 197 SkMatrix fLocalMatrixPrev = SkMatrix::InvalidMatrix(); 198 SkPMColor4f fColor = SK_PMColor4fILLEGAL; 199 uint8_t fCoverage = 0xFF; 200 201 UniformHandle fViewMatrixUniform; 202 UniformHandle fLocalMatrixUniform; 203 UniformHandle fColorUniform; 204 UniformHandle fCoverageUniform; 205 }; 206 207 bool hasVertexColor() const { return fInColor.isInitialized(); } 208 bool hasVertexCoverage() const { return fInCoverage.isInitialized(); } 209 210 DefaultGeoProc(uint32_t gpTypeFlags, 211 const SkPMColor4f& color, 212 const SkMatrix& viewMatrix, 213 const SkMatrix& localMatrix, 214 uint8_t coverage, 215 bool localCoordsWillBeRead) 216 : INHERITED(kDefaultGeoProc_ClassID) 217 , fColor(color) 218 , fViewMatrix(viewMatrix) 219 , fLocalMatrix(localMatrix) 220 , fCoverage(coverage) 221 , fFlags(gpTypeFlags) 222 , fLocalCoordsWillBeRead(localCoordsWillBeRead) { 223 fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 224 if (fFlags & kColorAttribute_GPFlag) { 225 fInColor = MakeColorAttribute("inColor", 226 SkToBool(fFlags & kColorAttributeIsWide_GPFlag)); 227 } 228 if (fFlags & kLocalCoordAttribute_GPFlag) { 229 fInLocalCoords = {"inLocalCoord", kFloat2_GrVertexAttribType, 230 kFloat2_GrSLType}; 231 } 232 if (fFlags & kCoverageAttribute_GPFlag) { 233 fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, kHalf_GrSLType}; 234 } 235 this->setVertexAttributes(&fInPosition, 4); 236 } 237 238 Attribute fInPosition; 239 Attribute fInColor; 240 Attribute fInLocalCoords; 241 Attribute fInCoverage; 242 SkPMColor4f fColor; 243 SkMatrix fViewMatrix; 244 SkMatrix fLocalMatrix; 245 uint8_t fCoverage; 246 uint32_t fFlags; 247 bool fLocalCoordsWillBeRead; 248 249 GR_DECLARE_GEOMETRY_PROCESSOR_TEST 250 251 using INHERITED = GrGeometryProcessor; 252}; 253 254GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc); 255 256#if GR_TEST_UTILS 257GrGeometryProcessor* DefaultGeoProc::TestCreate(GrProcessorTestData* d) { 258 uint32_t flags = 0; 259 if (d->fRandom->nextBool()) { 260 flags |= kColorAttribute_GPFlag; 261 } 262 if (d->fRandom->nextBool()) { 263 flags |= kColorAttributeIsWide_GPFlag; 264 } 265 if (d->fRandom->nextBool()) { 266 flags |= kCoverageAttribute_GPFlag; 267 if (d->fRandom->nextBool()) { 268 flags |= (d->fRandom->nextBool()) ? kCoverageAttributeTweak_GPFlag 269 : kCoverageAttributeUnclamped_GPFlag; 270 } 271 } 272 if (d->fRandom->nextBool()) { 273 flags |= kLocalCoordAttribute_GPFlag; 274 } 275 276 GrColor color = GrTest::RandomColor(d->fRandom); 277 SkMatrix viewMtx = GrTest::TestMatrix(d->fRandom); 278 SkMatrix localMtx = GrTest::TestMatrix(d->fRandom); 279 bool readsLocalCoords = d->fRandom->nextBool(); 280 uint8_t coverage = GrTest::RandomCoverage(d->fRandom); 281 return DefaultGeoProc::Make(d->allocator(), 282 flags, 283 SkPMColor4f::FromBytes_RGBA(color), 284 viewMtx, 285 localMtx, 286 readsLocalCoords, 287 coverage); 288} 289#endif 290 291GrGeometryProcessor* GrDefaultGeoProcFactory::Make(SkArenaAlloc* arena, 292 const Color& color, 293 const Coverage& coverage, 294 const LocalCoords& localCoords, 295 const SkMatrix& viewMatrix) { 296 uint32_t flags = 0; 297 if (Color::kPremulGrColorAttribute_Type == color.fType) { 298 flags |= kColorAttribute_GPFlag; 299 } else if (Color::kPremulWideColorAttribute_Type == color.fType) { 300 flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag; 301 } 302 if (Coverage::kAttribute_Type == coverage.fType) { 303 flags |= kCoverageAttribute_GPFlag; 304 } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) { 305 flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag; 306 } else if (Coverage::kAttributeUnclamped_Type == coverage.fType) { 307 flags |= kCoverageAttribute_GPFlag | kCoverageAttributeUnclamped_GPFlag; 308 } 309 flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0; 310 311 uint8_t inCoverage = coverage.fCoverage; 312 bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type; 313 314 return DefaultGeoProc::Make(arena, 315 flags, 316 color.fColor, 317 viewMatrix, 318 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(), 319 localCoordsWillBeRead, 320 inCoverage); 321} 322 323GrGeometryProcessor* GrDefaultGeoProcFactory::MakeForDeviceSpace(SkArenaAlloc* arena, 324 const Color& color, 325 const Coverage& coverage, 326 const LocalCoords& localCoords, 327 const SkMatrix& viewMatrix) { 328 SkMatrix invert = SkMatrix::I(); 329 if (LocalCoords::kUnused_Type != localCoords.fType) { 330 SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType); 331 if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) { 332 return nullptr; 333 } 334 335 if (localCoords.hasLocalMatrix()) { 336 invert.postConcat(*localCoords.fMatrix); 337 } 338 } 339 340 LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert); 341 return Make(arena, color, coverage, inverted, SkMatrix::I()); 342} 343