blob: d27ea4c0778dcba4c351af5a10980099f04a5b69 [file] [log] [blame]
Chris Dalton1a325d22017-07-14 15:17:41 -06001/*
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
Eric Borend6365e52017-10-16 12:31:14 +000010#include "GrRenderTargetProxy.h"
11#include "ccpr/GrCCPRTriangleProcessor.h"
12#include "ccpr/GrCCPRQuadraticProcessor.h"
13#include "ccpr/GrCCPRCubicProcessor.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060014#include "glsl/GrGLSLFragmentShaderBuilder.h"
Eric Borend6365e52017-10-16 12:31:14 +000015#include "glsl/GrGLSLGeometryShaderBuilder.h"
16#include "glsl/GrGLSLProgramBuilder.h"
17#include "glsl/GrGLSLVertexShaderBuilder.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060018
Eric Borend6365e52017-10-16 12:31:14 +000019const char* GrCCPRCoverageProcessor::GetProcessorName(Mode mode) {
20 switch (mode) {
21 case Mode::kTriangleHulls:
22 return "GrCCPRTriangleHullAndEdgeProcessor (hulls)";
23 case Mode::kTriangleEdges:
24 return "GrCCPRTriangleHullAndEdgeProcessor (edges)";
25 case Mode::kTriangleCorners:
26 return "GrCCPRTriangleCornerProcessor";
27 case Mode::kQuadraticHulls:
28 return "GrCCPRQuadraticHullProcessor";
29 case Mode::kQuadraticCorners:
30 return "GrCCPRQuadraticCornerProcessor";
31 case Mode::kSerpentineHulls:
32 return "GrCCPRCubicHullProcessor (serpentine)";
33 case Mode::kLoopHulls:
34 return "GrCCPRCubicHullProcessor (loop)";
35 case Mode::kSerpentineCorners:
36 return "GrCCPRCubicCornerProcessor (serpentine)";
37 case Mode::kLoopCorners:
38 return "GrCCPRCubicCornerProcessor (loop)";
Chris Dalton1a325d22017-07-14 15:17:41 -060039 }
Eric Borend6365e52017-10-16 12:31:14 +000040 SK_ABORT("Unexpected ccpr coverage processor mode.");
41 return nullptr;
Chris Dalton1a325d22017-07-14 15:17:41 -060042}
43
Eric Borend6365e52017-10-16 12:31:14 +000044GrCCPRCoverageProcessor::GrCCPRCoverageProcessor(Mode mode, GrBuffer* pointsBuffer)
Ethan Nicholasabff9562017-10-09 10:54:08 -040045 : INHERITED(kGrCCPRCoverageProcessor_ClassID)
Eric Borend6365e52017-10-16 12:31:14 +000046 , fMode(mode)
47 , fInstanceAttrib(this->addInstanceAttrib("instance", InstanceArrayFormat(mode))) {
Chris Dalton1a325d22017-07-14 15:17:41 -060048 fPointsBufferAccess.reset(kRG_float_GrPixelConfig, pointsBuffer, kVertex_GrShaderFlag);
49 this->addBufferAccess(&fPointsBufferAccess);
50
51 this->setWillUseGeoShader();
Chris Dalton1a325d22017-07-14 15:17:41 -060052}
53
Eric Borend6365e52017-10-16 12:31:14 +000054void GrCCPRCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
55 GrProcessorKeyBuilder* b) const {
56 b->add32(int(fMode));
Chris Dalton1a325d22017-07-14 15:17:41 -060057}
58
Eric Borend6365e52017-10-16 12:31:14 +000059GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const {
60 switch (fMode) {
61 using GeometryType = GrCCPRTriangleHullAndEdgeProcessor::GeometryType;
62
63 case Mode::kTriangleHulls:
64 return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kHulls);
65 case Mode::kTriangleEdges:
66 return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kEdges);
67 case Mode::kTriangleCorners:
68 return new GrCCPRTriangleCornerProcessor();
69 case Mode::kQuadraticHulls:
70 return new GrCCPRQuadraticHullProcessor();
71 case Mode::kQuadraticCorners:
72 return new GrCCPRQuadraticCornerProcessor();
73 case Mode::kSerpentineHulls:
74 return new GrCCPRCubicHullProcessor(GrCCPRCubicProcessor::CubicType::kSerpentine);
75 case Mode::kLoopHulls:
76 return new GrCCPRCubicHullProcessor(GrCCPRCubicProcessor::CubicType::kLoop);
77 case Mode::kSerpentineCorners:
78 return new GrCCPRCubicCornerProcessor(GrCCPRCubicProcessor::CubicType::kSerpentine);
79 case Mode::kLoopCorners:
80 return new GrCCPRCubicCornerProcessor(GrCCPRCubicProcessor::CubicType::kLoop);
Chris Dalton1a325d22017-07-14 15:17:41 -060081 }
Eric Borend6365e52017-10-16 12:31:14 +000082 SK_ABORT("Unexpected ccpr coverage processor mode.");
83 return nullptr;
84}
85
86using PrimitiveProcessor = GrCCPRCoverageProcessor::PrimitiveProcessor;
87
88void PrimitiveProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
89 const GrCCPRCoverageProcessor& proc = args.fGP.cast<GrCCPRCoverageProcessor>();
90
91 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
92 switch (fCoverageType) {
93 case CoverageType::kOne:
94 case CoverageType::kShader:
95 varyingHandler->addFlatVarying("wind", &fFragWind, kLow_GrSLPrecision);
96 break;
97 case CoverageType::kInterpolated:
98 varyingHandler->addVarying("coverage_times_wind", &fFragCoverageTimesWind,
99 kMedium_GrSLPrecision);
100 break;
101 }
102 this->resetVaryings(varyingHandler);
103
104 varyingHandler->emitAttributes(proc);
105
106 this->emitVertexShader(proc, args.fVertBuilder, args.fTexelBuffers[0], args.fRTAdjustName,
107 gpArgs);
108 this->emitGeometryShader(proc, args.fGeomBuilder, args.fRTAdjustName);
109 this->emitCoverage(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
110
111 SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
112}
113
114void PrimitiveProcessor::emitVertexShader(const GrCCPRCoverageProcessor& proc,
115 GrGLSLVertexBuilder* v,
116 const TexelBufferHandle& pointsBuffer,
117 const char* rtAdjust, GrGPArgs* gpArgs) const {
118 v->codeAppendf("int packedoffset = %s[%i];", proc.instanceAttrib(), proc.atlasOffsetIdx());
119 v->codeAppend ("float2 atlasoffset = float2((packedoffset<<16) >> 16, "
120 "packedoffset >> 16);");
121
122 this->onEmitVertexShader(proc, v, pointsBuffer, "atlasoffset", rtAdjust, gpArgs);
123}
124
125void PrimitiveProcessor::emitGeometryShader(const GrCCPRCoverageProcessor& proc,
126 GrGLSLGeometryBuilder* g, const char* rtAdjust) const {
127 g->declareGlobal(fGeomWind);
128 this->emitWind(g, rtAdjust, fGeomWind.c_str());
129
130 SkString emitVertexFn;
131 SkSTArray<2, GrShaderVar> emitArgs;
132 const char* position = emitArgs.emplace_back("position", kFloat2_GrSLType,
133 GrShaderVar::kNonArray).c_str();
134 const char* coverage = emitArgs.emplace_back("coverage", kFloat_GrSLType,
135 GrShaderVar::kNonArray).c_str();
136 g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
137 SkString fnBody;
138 this->emitPerVertexGeometryCode(&fnBody, position, coverage, fGeomWind.c_str());
139 if (fFragWind.gsOut()) {
140 fnBody.appendf("%s = %s;", fFragWind.gsOut(), fGeomWind.c_str());
141 }
142 if (fFragCoverageTimesWind.gsOut()) {
143 fnBody.appendf("%s = %s * %s;",
144 fFragCoverageTimesWind.gsOut(), coverage, fGeomWind.c_str());
145 }
146 fnBody.append ("sk_Position = float4(position, 0, 1);");
147 fnBody.append ("EmitVertex();");
148 return fnBody;
149 }().c_str(), &emitVertexFn);
150
151 g->codeAppendf("float2 bloat = %f * abs(%s.xz);", kAABloatRadius, rtAdjust);
152
Chris Dalton1a325d22017-07-14 15:17:41 -0600153#ifdef SK_DEBUG
Chris Daltona640c492017-09-11 22:04:03 -0700154 if (proc.debugVisualizationsEnabled()) {
Eric Borend6365e52017-10-16 12:31:14 +0000155 g->codeAppendf("bloat *= %f;", proc.debugBloat());
156 }
157#endif
158
159 return this->onEmitGeometryShader(g, emitVertexFn.c_str(), fGeomWind.c_str(), rtAdjust);
160}
161
162int PrimitiveProcessor::emitHullGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn,
163 const char* polygonPts, int numSides,
164 const char* wedgeIdx, const char* midpoint) const {
165 SkASSERT(numSides >= 3);
166
167 if (!midpoint) {
168 g->codeAppendf("float2 midpoint = %s * float%i(%f);",
169 polygonPts, numSides, 1.0 / numSides);
170 midpoint = "midpoint";
171 }
172
173 g->codeAppendf("int previdx = (%s + %i) %% %i, "
174 "nextidx = (%s + 1) %% %i;",
175 wedgeIdx, numSides - 1, numSides, wedgeIdx, numSides);
176
177 g->codeAppendf("float2 self = %s[%s];"
178 "int leftidx = %s > 0 ? previdx : nextidx;"
179 "int rightidx = %s > 0 ? nextidx : previdx;",
180 polygonPts, wedgeIdx, fGeomWind.c_str(), fGeomWind.c_str());
181
182 // Which quadrant does the vector from self -> right fall into?
183 g->codeAppendf("float2 right = %s[rightidx];", polygonPts);
184 if (3 == numSides) {
185 // TODO: evaluate perf gains.
186 g->codeAppend ("float2 qsr = sign(right - self);");
187 } else {
188 SkASSERT(4 == numSides);
189 g->codeAppendf("float2 diag = %s[(%s + 2) %% 4];", polygonPts, wedgeIdx);
190 g->codeAppend ("float2 qsr = sign((right != self ? right : diag) - self);");
191 }
192
193 // Which quadrant does the vector from left -> self fall into?
194 g->codeAppendf("float2 qls = sign(self - %s[leftidx]);", polygonPts);
195
196 // d2 just helps us reduce triangle counts with orthogonal, axis-aligned lines.
197 // TODO: evaluate perf gains.
198 const char* dr2 = "dr";
199 if (3 == numSides) {
200 // TODO: evaluate perf gains.
201 g->codeAppend ("float2 dr = float2(qsr.y != 0 ? +qsr.y : +qsr.x, "
202 "qsr.x != 0 ? -qsr.x : +qsr.y);");
203 g->codeAppend ("float2 dr2 = float2(qsr.y != 0 ? +qsr.y : -qsr.x, "
204 "qsr.x != 0 ? -qsr.x : -qsr.y);");
205 g->codeAppend ("float2 dl = float2(qls.y != 0 ? +qls.y : +qls.x, "
206 "qls.x != 0 ? -qls.x : +qls.y);");
207 dr2 = "dr2";
208 } else {
209 g->codeAppend ("float2 dr = float2(qsr.y != 0 ? +qsr.y : 1, "
210 "qsr.x != 0 ? -qsr.x : 1);");
211 g->codeAppend ("float2 dl = (qls == float2(0)) ? dr : "
212 "float2(qls.y != 0 ? +qls.y : 1, qls.x != 0 ? -qls.x : 1);");
213 }
214 g->codeAppendf("bool2 dnotequal = notEqual(%s, dl);", dr2);
215
216 // Emit one third of what is the convex hull of pixel-size boxes centered on the vertices.
217 // Each invocation emits a different third.
218 g->codeAppendf("%s(right + bloat * dr, 1);", emitVertexFn);
219 g->codeAppendf("%s(%s, 1);", emitVertexFn, midpoint);
220 g->codeAppendf("%s(self + bloat * %s, 1);", emitVertexFn, dr2);
221 g->codeAppend ("if (any(dnotequal)) {");
222 g->codeAppendf( "%s(self + bloat * dl, 1);", emitVertexFn);
223 g->codeAppend ("}");
224 g->codeAppend ("if (all(dnotequal)) {");
225 g->codeAppendf( "%s(self + bloat * float2(-dl.y, dl.x), 1);", emitVertexFn);
226 g->codeAppend ("}");
227 g->codeAppend ("EndPrimitive();");
228
229 return 5;
230}
231
232int PrimitiveProcessor::emitEdgeGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn,
233 const char* leftPt, const char* rightPt,
234 const char* distanceEquation) const {
235 if (!distanceEquation) {
236 this->emitEdgeDistanceEquation(g, leftPt, rightPt, "float3 edge_distance_equation");
237 distanceEquation = "edge_distance_equation";
238 }
239
240 // qlr is defined in emitEdgeDistanceEquation.
241 g->codeAppendf("float2x2 endpts = float2x2(%s - bloat * qlr, %s + bloat * qlr);",
242 leftPt, rightPt);
243 g->codeAppendf("half2 endpts_coverage = %s.xy * endpts + %s.z;",
244 distanceEquation, distanceEquation);
245
246 // d1 is defined in emitEdgeDistanceEquation.
247 g->codeAppend ("float2 d2 = d1;");
248 g->codeAppend ("bool aligned = qlr.x == 0 || qlr.y == 0;");
249 g->codeAppend ("if (aligned) {");
250 g->codeAppend ( "d1 -= qlr;");
251 g->codeAppend ( "d2 += qlr;");
252 g->codeAppend ("}");
253
254 // Emit the convex hull of 2 pixel-size boxes centered on the endpoints of the edge. Each
255 // invocation emits a different edge. Emit negative coverage that subtracts the appropiate
256 // amount back out from the hull we drew above.
257 g->codeAppend ("if (!aligned) {");
258 g->codeAppendf( "%s(endpts[0], endpts_coverage[0]);", emitVertexFn);
259 g->codeAppend ("}");
260 g->codeAppendf("%s(%s + bloat * d1, -1);", emitVertexFn, leftPt);
261 g->codeAppendf("%s(%s - bloat * d2, 0);", emitVertexFn, leftPt);
262 g->codeAppendf("%s(%s + bloat * d2, -1);", emitVertexFn, rightPt);
263 g->codeAppendf("%s(%s - bloat * d1, 0);", emitVertexFn, rightPt);
264 g->codeAppend ("if (!aligned) {");
265 g->codeAppendf( "%s(endpts[1], endpts_coverage[1]);", emitVertexFn);
266 g->codeAppend ("}");
267 g->codeAppend ("EndPrimitive();");
268
269 return 6;
270}
271
272void PrimitiveProcessor::emitEdgeDistanceEquation(GrGLSLGeometryBuilder* g,
273 const char* leftPt, const char* rightPt,
274 const char* outputDistanceEquation) const {
275 // Which quadrant does the vector from left -> right fall into?
276 g->codeAppendf("float2 qlr = sign(%s - %s);", rightPt, leftPt);
277 g->codeAppend ("float2 d1 = float2(qlr.y, -qlr.x);");
278
279 g->codeAppendf("float2 n = float2(%s.y - %s.y, %s.x - %s.x);",
280 rightPt, leftPt, leftPt, rightPt);
281 g->codeAppendf("float2 kk = n * float2x2(%s + bloat * d1, %s - bloat * d1);",
282 leftPt, leftPt);
283 // Clamp for when n=0. wind=0 when n=0 so as long as we don't get Inf or NaN we are fine.
284 g->codeAppendf("float scale = 1 / max(kk[0] - kk[1], 1e-30);");
285
286 g->codeAppendf("%s = half3(-n, kk[1]) * scale;", outputDistanceEquation);
287}
288
289int PrimitiveProcessor::emitCornerGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn,
290 const char* pt) const {
291 g->codeAppendf("%s(%s + float2(-bloat.x, -bloat.y), 1);", emitVertexFn, pt);
292 g->codeAppendf("%s(%s + float2(-bloat.x, +bloat.y), 1);", emitVertexFn, pt);
293 g->codeAppendf("%s(%s + float2(+bloat.x, -bloat.y), 1);", emitVertexFn, pt);
294 g->codeAppendf("%s(%s + float2(+bloat.x, +bloat.y), 1);", emitVertexFn, pt);
295 g->codeAppend ("EndPrimitive();");
296
297 return 4;
298}
299
300void 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("half 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 = half4(1);", outputCoverage);
317
318#ifdef SK_DEBUG
319 if (proc.debugVisualizationsEnabled()) {
320 f->codeAppendf("%s = half4(-%s.a, %s.a, 0, 1);", outputColor, outputColor, outputColor);
Chris Dalton1a325d22017-07-14 15:17:41 -0600321 }
322#endif
Chris Dalton1a325d22017-07-14 15:17:41 -0600323}
324
Eric Borend6365e52017-10-16 12:31:14 +0000325int PrimitiveProcessor::defineSoftSampleLocations(GrGLSLFragmentBuilder* f,
326 const char* samplesName) const {
Chris Dalton1a325d22017-07-14 15:17:41 -0600327 // Standard DX11 sample locations.
328#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400329 f->defineConstant("float2[8]", samplesName, "float2[8]("
330 "float2(+1, -3)/16, float2(-1, +3)/16, float2(+5, +1)/16, float2(-3, -5)/16, "
331 "float2(-5, +5)/16, float2(-7, -1)/16, float2(+3, +7)/16, float2(+7, -7)/16."
Chris Dalton1a325d22017-07-14 15:17:41 -0600332 ")");
333 return 8;
334#else
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400335 f->defineConstant("float2[16]", samplesName, "float2[16]("
336 "float2(+1, +1)/16, float2(-1, -3)/16, float2(-3, +2)/16, float2(+4, -1)/16, "
337 "float2(-5, -2)/16, float2(+2, +5)/16, float2(+5, +3)/16, float2(+3, -5)/16, "
338 "float2(-2, +6)/16, float2( 0, -7)/16, float2(-4, -6)/16, float2(-6, +4)/16, "
339 "float2(-8, 0)/16, float2(+7, -4)/16, float2(+6, +7)/16, float2(-7, -8)/16."
Chris Dalton1a325d22017-07-14 15:17:41 -0600340 ")");
341 return 16;
342#endif
343}
344
345#ifdef SK_DEBUG
346
Eric Borend6365e52017-10-16 12:31:14 +0000347#include "GrRenderTarget.h"
Chris Dalton1a325d22017-07-14 15:17:41 -0600348
Robert Phillips2890fbf2017-07-26 15:48:41 -0400349void GrCCPRCoverageProcessor::Validate(GrRenderTargetProxy* atlasProxy) {
350 SkASSERT(kAtlasOrigin == atlasProxy->origin());
351 SkASSERT(GrPixelConfigIsAlphaOnly(atlasProxy->config()));
352 SkASSERT(GrPixelConfigIsFloatingPoint(atlasProxy->config()));
Chris Dalton1a325d22017-07-14 15:17:41 -0600353}
354
355#endif