• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 "GrCCPRCoverageProcessor.h"
9 
10 #include "ccpr/GrCCPRTriangleProcessor.h"
11 #include "ccpr/GrCCPRQuadraticProcessor.h"
12 #include "ccpr/GrCCPRCubicProcessor.h"
13 #include "glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "glsl/GrGLSLGeometryShaderBuilder.h"
15 #include "glsl/GrGLSLProgramBuilder.h"
16 #include "glsl/GrGLSLVertexShaderBuilder.h"
17 
GetProcessorName(Mode mode)18 const char* GrCCPRCoverageProcessor::GetProcessorName(Mode mode) {
19     switch (mode) {
20         case Mode::kTriangleHulls:
21             return "GrCCPRTriangleHullAndEdgeProcessor (hulls)";
22         case Mode::kTriangleEdges:
23             return "GrCCPRTriangleHullAndEdgeProcessor (edges)";
24         case Mode::kCombinedTriangleHullsAndEdges:
25             return "GrCCPRTriangleHullAndEdgeProcessor (combined hulls & edges)";
26         case Mode::kTriangleCorners:
27             return "GrCCPRTriangleCornerProcessor";
28         case Mode::kQuadraticHulls:
29             return "GrCCPRQuadraticHullProcessor";
30         case Mode::kQuadraticFlatEdges:
31             return "GrCCPRQuadraticSharedEdgeProcessor";
32         case Mode::kSerpentineInsets:
33             return "GrCCPRCubicInsetProcessor (serpentine)";
34         case Mode::kSerpentineBorders:
35             return "GrCCPRCubicBorderProcessor (serpentine)";
36         case Mode::kLoopInsets:
37             return "GrCCPRCubicInsetProcessor (loop)";
38         case Mode::kLoopBorders:
39             return "GrCCPRCubicBorderProcessor (loop)";
40     }
41     SkFAIL("Unexpected ccpr coverage processor mode.");
42     return nullptr;
43 }
44 
GrCCPRCoverageProcessor(Mode mode,GrBuffer * pointsBuffer)45 GrCCPRCoverageProcessor::GrCCPRCoverageProcessor(Mode mode, GrBuffer* pointsBuffer)
46         : fMode(mode)
47         , fInstanceAttrib(this->addInstanceAttrib("instance", kVec4i_GrVertexAttribType,
48                                                   kHigh_GrSLPrecision)) {
49     fPointsBufferAccess.reset(kRG_float_GrPixelConfig, pointsBuffer, kVertex_GrShaderFlag);
50     this->addBufferAccess(&fPointsBufferAccess);
51 
52     this->setWillUseGeoShader();
53 
54     this->initClassID<GrCCPRCoverageProcessor>();
55 }
56 
getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const57 void GrCCPRCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
58                                                   GrProcessorKeyBuilder* b) const {
59     b->add32(int(fMode));
60 }
61 
createGLSLInstance(const GrShaderCaps &) const62 GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const {
63     switch (fMode) {
64         using GeometryType = GrCCPRTriangleHullAndEdgeProcessor::GeometryType;
65 
66         case Mode::kTriangleHulls:
67             return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kHulls);
68         case Mode::kTriangleEdges:
69             return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kEdges);
70         case Mode::kCombinedTriangleHullsAndEdges:
71             return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kHullsAndEdges);
72         case Mode::kTriangleCorners:
73             return new GrCCPRTriangleCornerProcessor();
74         case Mode::kQuadraticHulls:
75             return new GrCCPRQuadraticHullProcessor();
76         case Mode::kQuadraticFlatEdges:
77             return new GrCCPRQuadraticSharedEdgeProcessor();
78         case Mode::kSerpentineInsets:
79             return new GrCCPRCubicInsetProcessor(GrCCPRCubicProcessor::Type::kSerpentine);
80         case Mode::kSerpentineBorders:
81             return new GrCCPRCubicBorderProcessor(GrCCPRCubicProcessor::Type::kSerpentine);
82         case Mode::kLoopInsets:
83             return new GrCCPRCubicInsetProcessor(GrCCPRCubicProcessor::Type::kLoop);
84         case Mode::kLoopBorders:
85             return new GrCCPRCubicBorderProcessor(GrCCPRCubicProcessor::Type::kLoop);
86     }
87     SkFAIL("Unexpected ccpr coverage processor mode.");
88     return nullptr;
89 }
90 
91 using PrimitiveProcessor = GrCCPRCoverageProcessor::PrimitiveProcessor;
92 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)93 void PrimitiveProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
94     const GrCCPRCoverageProcessor& proc = args.fGP.cast<GrCCPRCoverageProcessor>();
95 
96     GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
97     switch (fCoverageType) {
98         case CoverageType::kOne:
99         case CoverageType::kShader:
100             varyingHandler->addFlatVarying("wind", &fFragWind, kLow_GrSLPrecision);
101             break;
102         case CoverageType::kInterpolated:
103             varyingHandler->addVarying("coverage_times_wind", &fFragCoverageTimesWind,
104                                        kMedium_GrSLPrecision);
105             break;
106     }
107     this->resetVaryings(varyingHandler);
108 
109     varyingHandler->emitAttributes(proc);
110 
111     this->emitVertexShader(proc, args.fVertBuilder, args.fTexelBuffers[0], args.fRTAdjustName,
112                            gpArgs);
113     this->emitGeometryShader(proc, args.fGeomBuilder, args.fRTAdjustName);
114     this->emitCoverage(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
115 
116     SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
117 }
118 
emitVertexShader(const GrCCPRCoverageProcessor & proc,GrGLSLVertexBuilder * v,const TexelBufferHandle & pointsBuffer,const char * rtAdjust,GrGPArgs * gpArgs) const119 void PrimitiveProcessor::emitVertexShader(const GrCCPRCoverageProcessor& proc,
120                                           GrGLSLVertexBuilder* v,
121                                           const TexelBufferHandle& pointsBuffer,
122                                           const char* rtAdjust, GrGPArgs* gpArgs) const {
123     v->codeAppendf("int packedoffset = %s.w;", proc.instanceAttrib());
124     v->codeAppend ("highp vec2 atlasoffset = vec2((packedoffset<<16) >> 16, packedoffset >> 16);");
125 
126     this->onEmitVertexShader(proc, v, pointsBuffer, "atlasoffset", rtAdjust, gpArgs);
127 }
128 
emitGeometryShader(const GrCCPRCoverageProcessor & proc,GrGLSLGeometryBuilder * g,const char * rtAdjust) const129 void PrimitiveProcessor::emitGeometryShader(const GrCCPRCoverageProcessor& proc,
130                                             GrGLSLGeometryBuilder* g, const char* rtAdjust) const {
131     g->declareGlobal(fGeomWind);
132     this->emitWind(g, rtAdjust, fGeomWind.c_str());
133 
134     SkString emitVertexFn;
135     SkSTArray<2, GrShaderVar> emitArgs;
136     const char* position = emitArgs.emplace_back("position", kVec2f_GrSLType,
137                                                  GrShaderVar::kNonArray,
138                                                  kHigh_GrSLPrecision).c_str();
139     const char* coverage = emitArgs.emplace_back("coverage", kFloat_GrSLType,
140                                                  GrShaderVar::kNonArray,
141                                                  kHigh_GrSLPrecision).c_str();
142     g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
143         SkString fnBody;
144         this->emitPerVertexGeometryCode(&fnBody, position, coverage, fGeomWind.c_str());
145         if (fFragWind.gsOut()) {
146             fnBody.appendf("%s = %s;", fFragWind.gsOut(), fGeomWind.c_str());
147         }
148         if (fFragCoverageTimesWind.gsOut()) {
149             fnBody.appendf("%s = %s * %s;",
150                            fFragCoverageTimesWind.gsOut(), coverage, fGeomWind.c_str());
151         }
152         fnBody.append ("gl_Position = vec4(position, 0, 1);");
153         fnBody.append ("EmitVertex();");
154         return fnBody;
155     }().c_str(), &emitVertexFn);
156 
157     g->codeAppendf("highp vec2 bloat = %f * abs(%s.xz);", kAABloatRadius, rtAdjust);
158 
159 #ifdef SK_DEBUG
160     if (proc.debugVisualizations()) {
161         g->codeAppendf("bloat *= %f;", GrCCPRCoverageProcessor::kDebugBloat);
162     }
163 #endif
164 
165     return this->onEmitGeometryShader(g, emitVertexFn.c_str(), fGeomWind.c_str(), rtAdjust);
166 }
167 
emitHullGeometry(GrGLSLGeometryBuilder * g,const char * emitVertexFn,const char * polygonPts,int numSides,const char * wedgeIdx,const char * insetPts) const168 int PrimitiveProcessor::emitHullGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn,
169                                          const char* polygonPts, int numSides,
170                                          const char* wedgeIdx, const char* insetPts) const {
171     SkASSERT(numSides >= 3);
172 
173     if (!insetPts) {
174         g->codeAppendf("highp vec2 centroidpt = %s * vec%i(%f);",
175                        polygonPts, numSides, 1.0 / numSides);
176     }
177 
178     g->codeAppendf("int previdx = (%s + %i) %% %i, "
179                        "nextidx = (%s + 1) %% %i;",
180                    wedgeIdx, numSides - 1, numSides, wedgeIdx, numSides);
181 
182     g->codeAppendf("highp vec2 self = %s[%s];"
183                    "highp int leftidx = %s > 0 ? previdx : nextidx;"
184                    "highp int rightidx = %s > 0 ? nextidx : previdx;",
185                    polygonPts, wedgeIdx, fGeomWind.c_str(), fGeomWind.c_str());
186 
187     // Which quadrant does the vector from self -> right fall into?
188     g->codeAppendf("highp vec2 right = %s[rightidx];", polygonPts);
189     if (3 == numSides) {
190         // TODO: evaluate perf gains.
191         g->codeAppend ("highp vec2 qsr = sign(right - self);");
192     } else {
193         SkASSERT(4 == numSides);
194         g->codeAppendf("highp vec2 diag = %s[(%s + 2) %% 4];", polygonPts, wedgeIdx);
195         g->codeAppend ("highp vec2 qsr = sign((right != self ? right : diag) - self);");
196     }
197 
198     // Which quadrant does the vector from left -> self fall into?
199     g->codeAppendf("highp vec2 qls = sign(self - %s[leftidx]);", polygonPts);
200 
201     // d2 just helps us reduce triangle counts with orthogonal, axis-aligned lines.
202     // TODO: evaluate perf gains.
203     const char* dr2 = "dr";
204     if (3 == numSides) {
205         // TODO: evaluate perf gains.
206         g->codeAppend ("highp vec2 dr = vec2(qsr.y != 0 ? +qsr.y : +qsr.x, "
207                                             "qsr.x != 0 ? -qsr.x : +qsr.y);");
208         g->codeAppend ("highp vec2 dr2 = vec2(qsr.y != 0 ? +qsr.y : -qsr.x, "
209                                              "qsr.x != 0 ? -qsr.x : -qsr.y);");
210         g->codeAppend ("highp vec2 dl = vec2(qls.y != 0 ? +qls.y : +qls.x, "
211                                             "qls.x != 0 ? -qls.x : +qls.y);");
212         dr2 = "dr2";
213     } else {
214         g->codeAppend ("highp vec2 dr = vec2(qsr.y != 0 ? +qsr.y : 1, "
215                                             "qsr.x != 0 ? -qsr.x : 1);");
216         g->codeAppend ("highp vec2 dl = (qls == vec2(0)) ? dr : vec2(qls.y != 0 ? +qls.y : 1, "
217                                                                     "qls.x != 0 ? -qls.x : 1);");
218     }
219     g->codeAppendf("bvec2 dnotequal = notEqual(%s, dl);", dr2);
220 
221     // Emit one third of what is the convex hull of pixel-size boxes centered on the vertices.
222     // Each invocation emits a different third.
223     if (insetPts) {
224         g->codeAppendf("%s(%s[rightidx], 1);", emitVertexFn, insetPts);
225     }
226     g->codeAppendf("%s(right + bloat * dr, 1);", emitVertexFn);
227     if (insetPts) {
228         g->codeAppendf("%s(%s[%s], 1);", emitVertexFn, insetPts, wedgeIdx);
229     } else {
230         g->codeAppendf("%s(centroidpt, 1);", emitVertexFn);
231     }
232     g->codeAppendf("%s(self + bloat * %s, 1);", emitVertexFn, dr2);
233     g->codeAppend ("if (any(dnotequal)) {");
234     g->codeAppendf(    "%s(self + bloat * dl, 1);", emitVertexFn);
235     g->codeAppend ("}");
236     g->codeAppend ("if (all(dnotequal)) {");
237     g->codeAppendf(    "%s(self + bloat * vec2(-dl.y, dl.x), 1);", emitVertexFn);
238     g->codeAppend ("}");
239     g->codeAppend ("EndPrimitive();");
240 
241     return insetPts ? 6 : 5;
242 }
243 
emitEdgeGeometry(GrGLSLGeometryBuilder * g,const char * emitVertexFn,const char * leftPt,const char * rightPt,const char * distanceEquation) const244 int PrimitiveProcessor::emitEdgeGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn,
245                                          const char* leftPt, const char* rightPt,
246                                          const char* distanceEquation) const {
247     if (!distanceEquation) {
248         this->emitEdgeDistanceEquation(g, leftPt, rightPt, "highp vec3 edge_distance_equation");
249         distanceEquation = "edge_distance_equation";
250     }
251 
252     // qlr is defined in emitEdgeDistanceEquation.
253     g->codeAppendf("highp mat2 endpts = mat2(%s - bloat * qlr, %s + bloat * qlr);",
254                    leftPt, rightPt);
255     g->codeAppendf("mediump vec2 endpts_coverage = %s.xy * endpts + %s.z;",
256                    distanceEquation, distanceEquation);
257 
258     // d1 is defined in emitEdgeDistanceEquation.
259     g->codeAppend ("highp vec2 d2 = d1;");
260     g->codeAppend ("bool aligned = qlr.x == 0 || qlr.y == 0;");
261     g->codeAppend ("if (aligned) {");
262     g->codeAppend (    "d1 -= qlr;");
263     g->codeAppend (    "d2 += qlr;");
264     g->codeAppend ("}");
265 
266     // Emit the convex hull of 2 pixel-size boxes centered on the endpoints of the edge. Each
267     // invocation emits a different edge. Emit negative coverage that subtracts the appropiate
268     // amount back out from the hull we drew above.
269     g->codeAppend ("if (!aligned) {");
270     g->codeAppendf(    "%s(endpts[0], endpts_coverage[0]);", emitVertexFn);
271     g->codeAppend ("}");
272     g->codeAppendf("%s(%s + bloat * d1, -1);", emitVertexFn, leftPt);
273     g->codeAppendf("%s(%s - bloat * d2, 0);", emitVertexFn, leftPt);
274     g->codeAppendf("%s(%s + bloat * d2, -1);", emitVertexFn, rightPt);
275     g->codeAppendf("%s(%s - bloat * d1, 0);", emitVertexFn, rightPt);
276     g->codeAppend ("if (!aligned) {");
277     g->codeAppendf(    "%s(endpts[1], endpts_coverage[1]);", emitVertexFn);
278     g->codeAppend ("}");
279     g->codeAppend ("EndPrimitive();");
280 
281     return 6;
282 }
283 
emitEdgeDistanceEquation(GrGLSLGeometryBuilder * g,const char * leftPt,const char * rightPt,const char * outputDistanceEquation) const284 void PrimitiveProcessor::emitEdgeDistanceEquation(GrGLSLGeometryBuilder* g,
285                                                   const char* leftPt, const char* rightPt,
286                                                   const char* outputDistanceEquation) const {
287     // Which quadrant does the vector from left -> right fall into?
288     g->codeAppendf("highp vec2 qlr = sign(%s - %s);", rightPt, leftPt);
289     g->codeAppend ("highp vec2 d1 = vec2(qlr.y, -qlr.x);");
290 
291     g->codeAppendf("highp vec2 n = vec2(%s.y - %s.y, %s.x - %s.x);",
292                    rightPt, leftPt, leftPt, rightPt);
293     g->codeAppendf("highp vec2 kk = n * mat2(%s + bloat * d1, %s - bloat * d1);", leftPt, leftPt);
294     // Clamp for when n=0. wind=0 when n=0 so as long as we don't get Inf or NaN we are fine.
295     g->codeAppendf("highp float scale = 1 / max(kk[0] - kk[1], 1e-30);");
296 
297     g->codeAppendf("%s = vec3(-n, kk[1]) * scale;", outputDistanceEquation);
298 }
299 
emitCoverage(const GrCCPRCoverageProcessor & proc,GrGLSLFragmentBuilder * f,const char * outputColor,const char * outputCoverage) const300 void PrimitiveProcessor::emitCoverage(const GrCCPRCoverageProcessor& proc, GrGLSLFragmentBuilder* f,
301                                       const char* outputColor, const char* outputCoverage) const {
302     switch (fCoverageType) {
303         case CoverageType::kOne:
304             f->codeAppendf("%s.a = %s;", outputColor, fFragWind.fsIn());
305             break;
306         case CoverageType::kInterpolated:
307             f->codeAppendf("%s.a = %s;", outputColor, fFragCoverageTimesWind.fsIn());
308             break;
309         case CoverageType::kShader:
310             f->codeAppendf("mediump float coverage = 0;");
311             this->emitShaderCoverage(f, "coverage");
312             f->codeAppendf("%s.a = coverage * %s;", outputColor, fFragWind.fsIn());
313             break;
314     }
315 
316     f->codeAppendf("%s = vec4(1);", outputCoverage);
317 
318 #ifdef SK_DEBUG
319     if (proc.debugVisualizations()) {
320         f->codeAppendf("%s = vec4(-%s.a, %s.a, 0, 1);", outputColor, outputColor, outputColor);
321     }
322 #endif
323 }
324 
defineSoftSampleLocations(GrGLSLFragmentBuilder * f,const char * samplesName) const325 int PrimitiveProcessor::defineSoftSampleLocations(GrGLSLFragmentBuilder* f,
326                                                   const char* samplesName) const {
327     // Standard DX11 sample locations.
328 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
329     f->defineConstant("highp vec2[8]", samplesName, "vec2[8]("
330         "vec2(+1, -3)/16, vec2(-1, +3)/16, vec2(+5, +1)/16, vec2(-3, -5)/16, "
331         "vec2(-5, +5)/16, vec2(-7, -1)/16, vec2(+3, +7)/16, vec2(+7, -7)/16."
332     ")");
333     return 8;
334 #else
335     f->defineConstant("highp vec2[16]", samplesName, "vec2[16]("
336         "vec2(+1, +1)/16, vec2(-1, -3)/16, vec2(-3, +2)/16, vec2(+4, -1)/16, "
337         "vec2(-5, -2)/16, vec2(+2, +5)/16, vec2(+5, +3)/16, vec2(+3, -5)/16, "
338         "vec2(-2, +6)/16, vec2( 0, -7)/16, vec2(-4, -6)/16, vec2(-6, +4)/16, "
339         "vec2(-8,  0)/16, vec2(+7, -4)/16, vec2(+6, +7)/16, vec2(-7, -8)/16."
340     ")");
341     return 16;
342 #endif
343 }
344 
345 #ifdef SK_DEBUG
346 
347 #include "GrRenderTarget.h"
348 
Validate(GrRenderTarget * atlasTexture)349 void GrCCPRCoverageProcessor::Validate(GrRenderTarget* atlasTexture) {
350     SkASSERT(kAtlasOrigin == atlasTexture->origin());
351     SkASSERT(GrPixelConfigIsAlphaOnly(atlasTexture->config()));
352     SkASSERT(GrPixelConfigIsFloatingPoint(atlasTexture->config()));
353 }
354 
355 #endif
356