blob: 83b5c7b60894e9d3637abef04a3e932950272d90 [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 "GrCCPRTriangleProcessor.h"
9
10#include "glsl/GrGLSLFragmentShaderBuilder.h"
11#include "glsl/GrGLSLGeometryShaderBuilder.h"
12#include "glsl/GrGLSLVertexShaderBuilder.h"
13
14void GrCCPRTriangleProcessor::onEmitVertexShader(const GrCCPRCoverageProcessor& proc,
15 GrGLSLVertexBuilder* v,
16 const TexelBufferHandle& pointsBuffer,
17 const char* atlasOffset, const char* rtAdjust,
18 GrGPArgs* gpArgs) const {
Chris Dalton29f642a2017-10-02 13:17:33 -060019 // Copy the input attrib to an intermediate array. The Intel GLSL compiler hits an internal
20 // assertion if we index the input attrib itself with sk_VertexID.
21 v->codeAppendf("int indices[3] = int[3](%s.x, %s.y, %s.z);",
22 proc.instanceAttrib(), proc.instanceAttrib(), proc.instanceAttrib());
Ethan Nicholas8aa45692017-09-20 11:24:15 -040023 v->codeAppend ("float2 self = ");
Chris Dalton29f642a2017-10-02 13:17:33 -060024 v->appendTexelFetch(pointsBuffer, "indices[sk_VertexID]");
Chris Dalton1a325d22017-07-14 15:17:41 -060025 v->codeAppendf(".xy + %s;", atlasOffset);
Ethan Nicholas8aa45692017-09-20 11:24:15 -040026 gpArgs->fPositionVar.set(kFloat2_GrSLType, "self");
Chris Dalton1a325d22017-07-14 15:17:41 -060027}
28
29void GrCCPRTriangleProcessor::defineInputVertices(GrGLSLGeometryBuilder* g) const {
30 // Prepend in_vertices at the start of the shader.
Ethan Nicholasbed683a2017-09-26 14:23:59 -040031 g->codePrependf("float3x2 in_vertices = float3x2(sk_in[0].sk_Position.xy, "
32 "sk_in[1].sk_Position.xy, "
33 "sk_in[2].sk_Position.xy);");
Chris Dalton1a325d22017-07-14 15:17:41 -060034}
35
36void GrCCPRTriangleProcessor::emitWind(GrGLSLGeometryBuilder* g, const char* /*rtAdjust*/,
37 const char* outputWind) const {
38 // We will define in_vertices in defineInputVertices.
Ethan Nicholas8aa45692017-09-20 11:24:15 -040039 g->codeAppendf("%s = sign(determinant(float2x2(in_vertices[1] - in_vertices[0], "
40 "in_vertices[2] - in_vertices[0])));",
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040041 outputWind);
Chris Dalton1a325d22017-07-14 15:17:41 -060042}
43
44void GrCCPRTriangleHullAndEdgeProcessor::onEmitGeometryShader(GrGLSLGeometryBuilder* g,
45 const char* emitVertexFn,
46 const char* wind,
47 const char* rtAdjust) const {
48 this->defineInputVertices(g);
49 int maxOutputVertices = 0;
50
51 if (GeometryType::kEdges != fGeometryType) {
52 maxOutputVertices += this->emitHullGeometry(g, emitVertexFn, "in_vertices", 3,
53 "sk_InvocationID");
54 }
55
56 if (GeometryType::kHulls != fGeometryType) {
57 g->codeAppend ("int edgeidx0 = sk_InvocationID, "
58 "edgeidx1 = (edgeidx0 + 1) % 3;");
Ethan Nicholas8aa45692017-09-20 11:24:15 -040059 g->codeAppendf("float2 edgept0 = in_vertices[%s > 0 ? edgeidx0 : edgeidx1];", wind);
60 g->codeAppendf("float2 edgept1 = in_vertices[%s > 0 ? edgeidx1 : edgeidx0];", wind);
Chris Dalton1a325d22017-07-14 15:17:41 -060061
62 maxOutputVertices += this->emitEdgeGeometry(g, emitVertexFn, "edgept0", "edgept1");
63 }
64
65 g->configure(GrGLSLGeometryBuilder::InputType::kTriangles,
66 GrGLSLGeometryBuilder::OutputType::kTriangleStrip,
67 maxOutputVertices, 3);
68}
69
Chris Dalton1a325d22017-07-14 15:17:41 -060070void GrCCPRTriangleCornerProcessor::onEmitGeometryShader(GrGLSLGeometryBuilder* g,
71 const char* emitVertexFn, const char* wind,
72 const char* rtAdjust) const {
73 this->defineInputVertices(g);
74
Ethan Nicholas8aa45692017-09-20 11:24:15 -040075 g->codeAppend ("float2 corner = in_vertices[sk_InvocationID];");
76 g->codeAppend ("float2x2 vectors = float2x2(corner - in_vertices[(sk_InvocationID + 2) % 3], "
77 "corner - in_vertices[(sk_InvocationID + 1) % 3]);");
Chris Dalton71e37972017-09-18 22:23:53 -060078
79 // Make sure neither vector is 0 in order to avoid a divide-by-zero. Wind will be zero anyway if
80 // this is the case, so whatever we output won't have any effect as long it isn't NaN or Inf.
81 g->codeAppendf("for (int i = 0; i < 2; ++i) {");
Ethan Nicholas8aa45692017-09-20 11:24:15 -040082 g->codeAppendf( "vectors[i] = any(notEqual(vectors[i], float2(0))) ? "
83 "vectors[i] : float2(1);");
Chris Dalton71e37972017-09-18 22:23:53 -060084 g->codeAppendf("}");
85
86 // Find the vector that bisects the region outside the incoming edges. Each edge is responsible
87 // to subtract the outside region on its own the side of the bisector.
Ethan Nicholas8aa45692017-09-20 11:24:15 -040088 g->codeAppendf("float2 leftdir = normalize(vectors[%s > 0 ? 0 : 1]);", wind);
89 g->codeAppendf("float2 rightdir = normalize(vectors[%s > 0 ? 1 : 0]);", wind);
90 g->codeAppendf("float2 bisect = dot(leftdir, rightdir) >= 0 ? leftdir + rightdir : "
91 "float2(leftdir.y - rightdir.y, rightdir.x - leftdir.x);");
Chris Dalton71e37972017-09-18 22:23:53 -060092
93 // In ccpr we don't calculate exact geometric pixel coverage. What the distance-to-edge method
94 // actually finds is coverage inside a logical "AA box", one that is rotated inline with the
95 // edge, and in our case, up-scaled to circumscribe the actual pixel. Below we set up
96 // transformations into normalized logical AA box space for both incoming edges. These will tell
97 // the fragment shader where the corner is located within each edge's AA box.
98 g->declareGlobal(fAABoxMatrices);
99 g->declareGlobal(fAABoxTranslates);
100 g->declareGlobal(fGeoShaderBisects);
101 g->codeAppendf("for (int i = 0; i < 2; ++i) {");
102 // The X component runs parallel to the edge (i.e. distance to the corner).
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400103 g->codeAppendf( "float2 n = -vectors[%s > 0 ? i : 1 - i];", wind);
104 g->codeAppendf( "float nwidth = dot(abs(n), bloat) * 2;");
Chris Dalton71e37972017-09-18 22:23:53 -0600105 g->codeAppendf( "n /= nwidth;"); // nwidth != 0 because both vectors != 0.
106 g->codeAppendf( "%s[i][0] = n;", fAABoxMatrices.c_str());
107 g->codeAppendf( "%s[i][0] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
108
109 // The Y component runs perpendicular to the edge (i.e. distance-to-edge).
110 // NOTE: once we are back in device space and bloat.x == bloat.y, we will not need to find and
111 // divide by nwidth a second time.
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400112 g->codeAppendf( "n = (i == 0) ? float2(-n.y, n.x) : float2(n.y, -n.x);");
Chris Dalton71e37972017-09-18 22:23:53 -0600113 g->codeAppendf( "nwidth = dot(abs(n), bloat) * 2;");
114 g->codeAppendf( "n /= nwidth;");
115 g->codeAppendf( "%s[i][1] = n;", fAABoxMatrices.c_str());
116 g->codeAppendf( "%s[i][1] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
117
118 // Translate the bisector into logical AA box space.
119 // NOTE: Since the region outside two edges of a convex shape is in [180 deg, 360 deg], the
120 // bisector will therefore be in [90 deg, 180 deg]. Or, x >= 0 and y <= 0 in AA box space.
121 g->codeAppendf( "%s[i] = -bisect * %s[i];",
122 fGeoShaderBisects.c_str(), fAABoxMatrices.c_str());
123 g->codeAppendf("}");
124
125 int numVertices = this->emitCornerGeometry(g, emitVertexFn, "corner");
Chris Dalton1a325d22017-07-14 15:17:41 -0600126
127 g->configure(GrGLSLGeometryBuilder::InputType::kTriangles,
128 GrGLSLGeometryBuilder::OutputType::kTriangleStrip,
Chris Daltonb072bb62017-08-07 09:00:46 -0600129 numVertices, 3);
Chris Dalton1a325d22017-07-14 15:17:41 -0600130}
131
132void GrCCPRTriangleCornerProcessor::emitPerVertexGeometryCode(SkString* fnBody,
133 const char* position,
134 const char* /*coverage*/,
135 const char* wind) const {
Chris Dalton71e37972017-09-18 22:23:53 -0600136 fnBody->appendf("for (int i = 0; i < 2; ++i) {");
137 fnBody->appendf( "%s[i] = %s * %s[i] + %s[i];",
138 fCornerLocationInAABoxes.gsOut(), position, fAABoxMatrices.c_str(),
139 fAABoxTranslates.c_str());
140 fnBody->appendf( "%s[i] = %s[i];", fBisectInAABoxes.gsOut(), fGeoShaderBisects.c_str());
141 fnBody->appendf("}");
Chris Dalton1a325d22017-07-14 15:17:41 -0600142}
143
144void GrCCPRTriangleCornerProcessor::emitShaderCoverage(GrGLSLFragmentBuilder* f,
145 const char* outputCoverage) const {
Chris Dalton71e37972017-09-18 22:23:53 -0600146 // By the time we reach this shader, the pixel is in the following state:
147 //
148 // 1. The hull shader has emitted a coverage of 1.
149 // 2. Both edges have subtracted the area on their outside.
150 //
151 // This generally works, but it is a problem for corner pixels. There is a region within corner
152 // pixels that is outside both edges at the same time. This means the region has been double
153 // subtracted (once by each edge). The purpose of this shader is to fix these corner pixels.
154 //
155 // More specifically, each edge redoes its coverage analysis so that it only subtracts the
156 // outside area that falls on its own side of the bisector line.
157 //
158 // NOTE: unless the edges fall on multiples of 90 deg from one another, they will have different
159 // AA boxes. (For an explanation of AA boxes, see comments in onEmitGeometryShader.) This means
160 // the coverage analysis will only be approximate. It seems acceptable, but if we want exact
161 // coverage we will need to switch to a more expensive model.
162 f->codeAppendf("%s = 0;", outputCoverage);
Chris Dalton1a325d22017-07-14 15:17:41 -0600163
Chris Dalton71e37972017-09-18 22:23:53 -0600164 // Loop through both edges.
165 f->codeAppendf("for (int i = 0; i < 2; ++i) {");
166 f->codeAppendf( "half2 corner = %s[i];", fCornerLocationInAABoxes.fsIn());
167 f->codeAppendf( "half2 bisect = %s[i];", fBisectInAABoxes.fsIn());
Chris Dalton1a325d22017-07-14 15:17:41 -0600168
Chris Dalton71e37972017-09-18 22:23:53 -0600169 // Find the point at which the bisector exits the logical AA box.
170 // (The inequality works because bisect.x is known >= 0 and bisect.y is known <= 0.)
171 f->codeAppendf( "half2 d = half2(1 - corner.x, -corner.y);");
172 f->codeAppendf( "half T = d.y * bisect.x >= d.x * bisect.y ? d.y / bisect.y "
173 ": d.x / bisect.x;");
174 f->codeAppendf( "half2 exit = corner + bisect * T;");
Chris Dalton1a325d22017-07-14 15:17:41 -0600175
Chris Dalton71e37972017-09-18 22:23:53 -0600176 // These lines combined (and the final multiply by .5) accomplish the following:
177 // 1. Add back the area beyond the corner that was subtracted out previously.
178 // 2. Subtract out the area beyond the corner, but under the bisector.
179 // The other edge will take care of the area on its own side of the bisector.
180 f->codeAppendf( "%s += (2 - corner.x - exit.x) * corner.y;", outputCoverage);
181 f->codeAppendf( "%s += (corner.x - 1) * exit.y;", outputCoverage);
182 f->codeAppendf("}");
Chris Dalton1a325d22017-07-14 15:17:41 -0600183
Chris Dalton71e37972017-09-18 22:23:53 -0600184 f->codeAppendf("%s *= .5;", outputCoverage);
Chris Dalton1a325d22017-07-14 15:17:41 -0600185}