blob: a1f4198f86f0469ad957e4aa5cd7579c0e3b2dfd [file] [log] [blame]
Chris Dalton6a3dbee2017-10-16 10:44: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 "GrCCPRTriangleShader.h"
9
10#include "glsl/GrGLSLFragmentShaderBuilder.h"
Chris Daltonc17bf322017-10-24 10:59:03 -060011#include "glsl/GrGLSLVertexGeoBuilder.h"
Chris Dalton6a3dbee2017-10-16 10:44:41 -060012
13void GrCCPRTriangleShader::appendInputPointFetch(const GrCCPRCoverageProcessor& proc,
14 GrGLSLShaderBuilder* s,
15 const TexelBufferHandle& pointsBuffer,
16 const char* pointId) const {
17 s->appendTexelFetch(pointsBuffer,
18 SkStringPrintf("%s[%s]", proc.instanceAttrib(), pointId).c_str());
19}
20
Chris Daltonc17bf322017-10-24 10:59:03 -060021void GrCCPRTriangleShader::emitWind(GrGLSLShaderBuilder* s, const char* pts,
22 const char* outputWind) const {
Chris Dalton6a3dbee2017-10-16 10:44:41 -060023 s->codeAppendf("%s = sign(determinant(float2x2(%s[1] - %s[0], %s[2] - %s[0])));",
24 outputWind, pts, pts, pts, pts);
25}
26
27GrCCPRTriangleHullShader::WindHandling
28GrCCPRTriangleHullShader::onEmitVaryings(GrGLSLVaryingHandler*, SkString* code,
29 const char* /*position*/, const char* /*coverage*/,
30 const char* /*wind*/) {
31 return WindHandling::kNotHandled; // No varyings.Let the base class handle wind.
32}
33
34void GrCCPRTriangleHullShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f,
35 const char* outputCoverage) const {
36 f->codeAppendf("%s = 1;", outputCoverage);
37}
38
39GrCCPRTriangleEdgeShader::WindHandling
40GrCCPRTriangleEdgeShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, SkString* code,
41 const char* position, const char* coverage,
42 const char* wind) {
Chris Daltonfdde34e2017-10-16 14:15:26 -060043 varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
Chris Dalton6a3dbee2017-10-16 10:44:41 -060044 code->appendf("%s = %s * %s;", fCoverageTimesWind.gsOut(), coverage, wind);
45 return WindHandling::kHandled;
46}
47
48void GrCCPRTriangleEdgeShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f,
49 const char* outputCoverage) const {
50 f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn());
51}
52
53void GrCCPRTriangleCornerShader::emitSetupCode(GrGLSLShaderBuilder* s, const char* pts,
Chris Daltonc17bf322017-10-24 10:59:03 -060054 const char* cornerId, const char* wind,
Chris Dalton6a3dbee2017-10-16 10:44:41 -060055 GeometryVars* vars) const {
56 s->codeAppendf("float2 corner = %s[sk_InvocationID];", pts);
57 vars->fCornerVars.fPoint = "corner";
58
59 s->codeAppendf("float2x2 vectors = float2x2(corner - %s[(sk_InvocationID + 2) %% 3], "
60 "corner - %s[(sk_InvocationID + 1) %% 3]);",
61 pts, pts);
62
63 // Make sure neither vector is 0 to avoid a divide-by-zero. Wind will be zero anyway if this
64 // is the case, so whatever we output won't have any effect as long it isn't NaN or Inf.
65 s->codeAppend ("for (int i = 0; i < 2; ++i) {");
66 s->codeAppend ( "vectors[i] = (vectors[i] != float2(0)) ? vectors[i] : float2(1);");
67 s->codeAppend ("}");
68
69 // Find the vector that bisects the region outside the incoming edges. Each edge is
70 // responsible to subtract the outside region on its own the side of the bisector.
71 s->codeAppendf("float2 leftdir = normalize(vectors[%s > 0 ? 0 : 1]);", wind);
72 s->codeAppendf("float2 rightdir = normalize(vectors[%s > 0 ? 1 : 0]);", wind);
73 s->codeAppend ("float2 bisect = dot(leftdir, rightdir) >= 0 ? "
74 "leftdir + rightdir : "
75 "float2(leftdir.y - rightdir.y, rightdir.x - leftdir.x);");
76
77 // In ccpr we don't calculate exact geometric pixel coverage. What the distance-to-edge
78 // method actually finds is coverage inside a logical "AA box", one that is rotated inline
79 // with the edge, and in our case, up-scaled to circumscribe the actual pixel. Below we set
80 // up transformations into normalized logical AA box space for both incoming edges. These
81 // will tell the fragment shader where the corner is located within each edge's AA box.
82 s->declareGlobal(fAABoxMatrices);
83 s->declareGlobal(fAABoxTranslates);
84 s->declareGlobal(fGeoShaderBisects);
85 s->codeAppendf("for (int i = 0; i < 2; ++i) {");
86 // The X component runs parallel to the edge (i.e. distance to the corner).
87 s->codeAppendf( "float2 n = -vectors[%s > 0 ? i : 1 - i];", wind);
Chris Daltonc17bf322017-10-24 10:59:03 -060088 s->codeAppend ( "float nwidth = (abs(n.x) + abs(n.y)) * (bloat * 2);");
Chris Dalton6a3dbee2017-10-16 10:44:41 -060089 s->codeAppend ( "n /= nwidth;"); // nwidth != 0 because both vectors != 0.
90 s->codeAppendf( "%s[i][0] = n;", fAABoxMatrices.c_str());
91 s->codeAppendf( "%s[i][0] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
92
93 // The Y component runs perpendicular to the edge (i.e. distance-to-edge).
Chris Dalton6a3dbee2017-10-16 10:44:41 -060094 s->codeAppend ( "n = (i == 0) ? float2(-n.y, n.x) : float2(n.y, -n.x);");
Chris Dalton6a3dbee2017-10-16 10:44:41 -060095 s->codeAppendf( "%s[i][1] = n;", fAABoxMatrices.c_str());
96 s->codeAppendf( "%s[i][1] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
97
98 // Translate the bisector into logical AA box space.
99 // NOTE: Since the region outside two edges of a convex shape is in [180 deg, 360 deg], the
100 // bisector will therefore be in [90 deg, 180 deg]. Or, x >= 0 and y <= 0 in AA box space.
101 s->codeAppendf( "%s[i] = -bisect * %s[i];",
102 fGeoShaderBisects.c_str(), fAABoxMatrices.c_str());
103 s->codeAppend ("}");
104}
105
106GrCCPRTriangleCornerShader::WindHandling
107GrCCPRTriangleCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, SkString* code,
108 const char* position, const char* /*coverage*/,
109 const char* /*wind*/) {
110 varyingHandler->addVarying("corner_location_in_aa_boxes", &fCornerLocationInAABoxes);
111 varyingHandler->addFlatVarying("bisect_in_aa_boxes", &fBisectInAABoxes);
112 code->appendf("for (int i = 0; i < 2; ++i) {");
113 code->appendf( "%s[i] = %s * %s[i] + %s[i];",
114 fCornerLocationInAABoxes.gsOut(), position, fAABoxMatrices.c_str(),
115 fAABoxTranslates.c_str());
116 code->appendf( "%s[i] = %s[i];", fBisectInAABoxes.gsOut(), fGeoShaderBisects.c_str());
117 code->appendf("}");
118
119 return WindHandling::kNotHandled;
120}
121
122void GrCCPRTriangleCornerShader::onEmitFragmentCode(GrGLSLPPFragmentBuilder* f,
123 const char* outputCoverage) const {
124 // By the time we reach this shader, the pixel is in the following state:
125 //
126 // 1. The hull shader has emitted a coverage of 1.
127 // 2. Both edges have subtracted the area on their outside.
128 //
129 // This generally works, but it is a problem for corner pixels. There is a region within
130 // corner pixels that is outside both edges at the same time. This means the region has been
131 // double subtracted (once by each edge). The purpose of this shader is to fix these corner
132 // pixels.
133 //
134 // More specifically, each edge redoes its coverage analysis so that it only subtracts the
135 // outside area that falls on its own side of the bisector line.
136 //
137 // NOTE: unless the edges fall on multiples of 90 deg from one another, they will have
138 // different AA boxes. (For an explanation of AA boxes, see comments in
139 // onEmitGeometryShader.) This means the coverage analysis will only be approximate. It
140 // seems acceptable, but if we want exact coverage we will need to switch to a more
141 // expensive model.
142 f->codeAppendf("for (int i = 0; i < 2; ++i) {"); // Loop through both edges.
143 f->codeAppendf( "half2 corner = %s[i];", fCornerLocationInAABoxes.fsIn());
144 f->codeAppendf( "half2 bisect = %s[i];", fBisectInAABoxes.fsIn());
145
146 // Find the point at which the bisector exits the logical AA box.
147 // (The inequality works because bisect.x is known >= 0 and bisect.y is known <= 0.)
148 f->codeAppendf( "half2 d = half2(1 - corner.x, -corner.y);");
149 f->codeAppendf( "half T = d.y * bisect.x >= d.x * bisect.y ? d.y / bisect.y "
150 ": d.x / bisect.x;");
151 f->codeAppendf( "half2 exit = corner + bisect * T;");
152
153 // These lines combined (and the final multiply by .5) accomplish the following:
154 // 1. Add back the area beyond the corner that was subtracted out previously.
155 // 2. Subtract out the area beyond the corner, but under the bisector.
156 // The other edge will take care of the area on its own side of the bisector.
157 f->codeAppendf( "%s += (2 - corner.x - exit.x) * corner.y;", outputCoverage);
158 f->codeAppendf( "%s += (corner.x - 1) * exit.y;", outputCoverage);
159 f->codeAppendf("}");
160
161 f->codeAppendf("%s *= .5;", outputCoverage);
162}