blob: a60a38ee5e48efd54d5af5f9946a0b0c96088de3 [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
Chris Dalton383a2ef2018-01-08 17:21:41 -05008#ifndef GrCCCoverageProcessor_DEFINED
9#define GrCCCoverageProcessor_DEFINED
Chris Dalton1a325d22017-07-14 15:17:41 -060010
Chris Dalton27059d32018-01-23 14:06:50 -070011#include "GrCaps.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060012#include "GrGeometryProcessor.h"
Chris Dalton90e8fb12017-12-22 02:24:53 -070013#include "GrShaderCaps.h"
Chris Daltona3e92712017-12-04 11:45:51 -070014#include "SkNx.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060015#include "glsl/GrGLSLGeometryProcessor.h"
16#include "glsl/GrGLSLVarying.h"
17
Chris Dalton60283612018-02-14 13:38:14 -070018class GrGLSLFPFragmentBuilder;
Chris Dalton1fbdb612017-12-12 12:48:47 -070019class GrGLSLVertexGeoBuilder;
Chris Dalton23261772017-12-10 16:41:45 -070020class GrMesh;
Chris Dalton1a325d22017-07-14 15:17:41 -060021
22/**
Chris Dalton1fbdb612017-12-12 12:48:47 -070023 * This is the geometry processor for the simple convex primitive shapes (triangles and closed,
24 * convex bezier curves) from which ccpr paths are composed. The output is a single-channel alpha
25 * value, positive for clockwise shapes and negative for counter-clockwise, that indicates coverage.
Chris Dalton1a325d22017-07-14 15:17:41 -060026 *
Chris Dalton6a3dbee2017-10-16 10:44:41 -060027 * The caller is responsible to execute all render passes for all applicable primitives into a
28 * cleared, floating point, alpha-only render target using SkBlendMode::kPlus (see RenderPass
29 * below). Once all of a path's primitives have been drawn, the render target contains a composite
Chris Dalton383a2ef2018-01-08 17:21:41 -050030 * coverage count that can then be used to draw the path (see GrCCPathProcessor).
Chris Dalton1a325d22017-07-14 15:17:41 -060031 *
Chris Dalton23261772017-12-10 16:41:45 -070032 * To draw a renderer pass, see appendMesh below.
Chris Dalton1a325d22017-07-14 15:17:41 -060033 */
Chris Dalton383a2ef2018-01-08 17:21:41 -050034class GrCCCoverageProcessor : public GrGeometryProcessor {
Chris Dalton1a325d22017-07-14 15:17:41 -060035public:
Chris Dalton84403d72018-02-13 21:46:17 -050036 // Defines a single primitive shape with 3 input points (i.e. Triangles and Quadratics).
37 // X,Y point values are transposed.
38 struct TriPointInstance {
Chris Daltona3e92712017-12-04 11:45:51 -070039 float fX[3];
40 float fY[3];
Chris Daltonc1e59632017-09-05 00:30:07 -060041
Chris Daltona3e92712017-12-04 11:45:51 -070042 void set(const SkPoint[3], const Sk2f& trans);
43 void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans);
Chris Daltonc1e59632017-09-05 00:30:07 -060044 };
45
Chris Dalton84403d72018-02-13 21:46:17 -050046 // Defines a single primitive shape with 4 input points, or 3 input points plus a W parameter
47 // duplicated in both 4th components (i.e. Cubics or Triangles with a custom winding number).
48 // X,Y point values are transposed.
49 struct QuadPointInstance {
Chris Daltona3e92712017-12-04 11:45:51 -070050 float fX[4];
51 float fY[4];
52
53 void set(const SkPoint[4], float dx, float dy);
Chris Dalton84403d72018-02-13 21:46:17 -050054 void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans, float w);
Chris Daltona3e92712017-12-04 11:45:51 -070055 };
Chris Daltonbaf3e782018-03-08 15:55:58 +000056
Chris Dalton8738cf42018-03-09 11:57:40 -070057 // All primitive shapes (triangles and closed, convex bezier curves) may require two render
58 // passes: One to draw a rough outline of the shape, and a second pass to touch up the corners.
59 // Check DoesRenderPass() before attempting to draw a given RenderPass. Here we enumerate every
60 // possible render pass needed in order to produce a complete coverage count mask. This is an
61 // exhaustive list of all ccpr coverage shaders.
Chris Dalton6a3dbee2017-10-16 10:44:41 -060062 enum class RenderPass {
Chris Dalton5183e642018-03-07 12:53:01 -070063 kTriangles,
Chris Daltonfe462ef2018-03-08 15:54:01 +000064 kTriangleCorners,
Chris Dalton5183e642018-03-07 12:53:01 -070065 kQuadratics,
Chris Daltonbaf3e782018-03-08 15:55:58 +000066 kQuadraticCorners,
Chris Dalton5183e642018-03-07 12:53:01 -070067 kCubics,
Chris Daltonbaf3e782018-03-08 15:55:58 +000068 kCubicCorners
Chris Dalton1a325d22017-07-14 15:17:41 -060069 };
Chris Daltonbaf3e782018-03-08 15:55:58 +000070 static bool RenderPassIsCubic(RenderPass);
Chris Dalton23261772017-12-10 16:41:45 -070071 static const char* RenderPassName(RenderPass);
Chris Dalton1a325d22017-07-14 15:17:41 -060072
Chris Dalton8738cf42018-03-09 11:57:40 -070073 constexpr static bool DoesRenderPass(RenderPass renderPass, const GrCaps& caps) {
74 return RenderPass::kTriangleCorners != renderPass ||
75 caps.shaderCaps()->geometryShaderSupport();
76 }
77
Chris Dalton84403d72018-02-13 21:46:17 -050078 enum class WindMethod : bool {
79 kCrossProduct, // Calculate wind = +/-1 by sign of the cross product.
80 kInstanceData // Instance data provides custom, signed wind values of any magnitude.
81 // (For tightly-wound tessellated triangles.)
82 };
83
84 GrCCCoverageProcessor(GrResourceProvider* rp, RenderPass pass, WindMethod windMethod)
Chris Dalton383a2ef2018-01-08 17:21:41 -050085 : INHERITED(kGrCCCoverageProcessor_ClassID)
Chris Dalton90e8fb12017-12-22 02:24:53 -070086 , fRenderPass(pass)
Chris Dalton84403d72018-02-13 21:46:17 -050087 , fWindMethod(windMethod)
88 , fImpl(rp->caps()->shaderCaps()->geometryShaderSupport() ? Impl::kGeometryShader
89 : Impl::kVertexShader) {
Chris Dalton8738cf42018-03-09 11:57:40 -070090 SkASSERT(DoesRenderPass(pass, *rp->caps()));
Chris Dalton90e8fb12017-12-22 02:24:53 -070091 if (Impl::kGeometryShader == fImpl) {
92 this->initGS();
93 } else {
Chris Dalton84403d72018-02-13 21:46:17 -050094 this->initVS(rp);
Chris Dalton90e8fb12017-12-22 02:24:53 -070095 }
Chris Daltona3e92712017-12-04 11:45:51 -070096 }
97
Chris Dalton23261772017-12-10 16:41:45 -070098 // GrPrimitiveProcessor overrides.
99 const char* name() const override { return RenderPassName(fRenderPass); }
100 SkString dumpInfo() const override {
101 return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
102 }
103 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
104 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
105
106#ifdef SK_DEBUG
107 // Increases the 1/2 pixel AA bloat by a factor of debugBloat and outputs color instead of
108 // coverage (coverage=+1 -> green, coverage=0 -> black, coverage=-1 -> red).
109 void enableDebugVisualizations(float debugBloat) { fDebugBloat = debugBloat; }
110 bool debugVisualizationsEnabled() const { return fDebugBloat > 0; }
111 float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
112#endif
113
Chris Dalton8738cf42018-03-09 11:57:40 -0700114 // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
115 // of either TriPointInstance or QuadPointInstance, depending on this processor's RendererPass,
116 // with coordinates in the desired shape's final atlas-space position.
117 void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
118 SkTArray<GrMesh>* out) const {
119 if (Impl::kGeometryShader == fImpl) {
120 this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out);
121 } else {
122 this->appendVSMesh(instanceBuffer, instanceCount, baseInstance, out);
123 }
124 }
125
Chris Daltonfe462ef2018-03-08 15:54:01 +0000126 // The Shader provides code to calculate each pixel's coverage in a RenderPass. It also
127 // provides details about shape-specific geometry.
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600128 class Shader {
129 public:
Chris Daltonfe462ef2018-03-08 15:54:01 +0000130 union GeometryVars {
131 struct {
132 const char* fAlternatePoints; // floatNx2 (if left null, will use input points).
133 } fHullVars;
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600134
Chris Daltonfe462ef2018-03-08 15:54:01 +0000135 struct {
136 const char* fPoint; // float2
137 } fCornerVars;
138
139 GeometryVars() { memset(this, 0, sizeof(*this)); }
140 };
141
142 // Called before generating geometry. Subclasses must fill out the applicable fields in
143 // GeometryVars (if any), and may also use this opportunity to setup internal member
144 // variables that will be needed during onEmitVaryings (e.g. transformation matrices).
145 //
146 // repetitionID is a 0-based index and indicates which edge or corner is being generated.
147 // It will be null when generating a hull.
148 virtual void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts,
149 const char* repetitionID, const char* wind,
150 GeometryVars*) const {}
151
152 void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
Chris Dalton04a1de52018-03-14 02:04:09 -0600153 SkString* code, const char* position, const char* coverage,
154 const char* attenuatedCoverage, const char* wind) {
Chris Daltonfe462ef2018-03-08 15:54:01 +0000155 SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
Chris Dalton04a1de52018-03-14 02:04:09 -0600156 this->onEmitVaryings(varyingHandler, scope, code, position, coverage,
157 attenuatedCoverage, wind);
Chris Daltonfe462ef2018-03-08 15:54:01 +0000158 }
Chris Dalton622650a2018-03-07 17:30:10 -0700159
Chris Dalton0a793812018-03-07 11:18:30 -0700160 void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600161 const char* skOutputColor, const char* skOutputCoverage) const;
162
Chris Daltonbaf3e782018-03-08 15:55:58 +0000163 // Defines an equation ("dot(float3(pt, 1), distance_equation)") that is -1 on the outside
164 // border of a conservative raster edge and 0 on the inside. 'leftPt' and 'rightPt' must be
165 // ordered clockwise.
166 static void EmitEdgeDistanceEquation(GrGLSLVertexGeoBuilder*, const char* leftPt,
167 const char* rightPt,
168 const char* outputDistanceEquation);
169
Chris Dalton0a793812018-03-07 11:18:30 -0700170 // Calculates an edge's coverage at a conservative raster vertex. The edge is defined by two
171 // clockwise-ordered points, 'leftPt' and 'rightPt'. 'rasterVertexDir' is a pair of +/-1
172 // values that point in the direction of conservative raster bloat, starting from an
173 // endpoint.
174 //
175 // Coverage values ramp from -1 (completely outside the edge) to 0 (completely inside).
176 static void CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGeoBuilder*, const char* leftPt,
177 const char* rightPt, const char* rasterVertexDir,
178 const char* outputCoverage);
179
Chris Dalton8738cf42018-03-09 11:57:40 -0700180 // Calculates an edge's coverage at two conservative raster vertices.
181 // (See CalcEdgeCoverageAtBloatVertex).
182 static void CalcEdgeCoveragesAtBloatVertices(GrGLSLVertexGeoBuilder*, const char* leftPt,
183 const char* rightPt, const char* bloatDir1,
184 const char* bloatDir2,
185 const char* outputCoverages);
186
Chris Dalton04a1de52018-03-14 02:04:09 -0600187 // Corner boxes require an additional "attenuation" varying that is multiplied by the
188 // regular (linearly-interpolated) coverage. This function calculates the attenuation value
189 // to use in the single, outermost vertex. The remaining three vertices of the corner box
190 // all use an attenuation value of 1.
191 static void CalcCornerCoverageAttenuation(GrGLSLVertexGeoBuilder*, const char* leftDir,
192 const char* rightDir,
193 const char* outputAttenuation);
194
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600195 virtual ~Shader() {}
196
197 protected:
Chris Dalton622650a2018-03-07 17:30:10 -0700198 // Here the subclass adds its internal varyings to the handler and produces code to
Chris Daltonfe462ef2018-03-08 15:54:01 +0000199 // initialize those varyings from a given position, input coverage value, and wind.
Chris Dalton622650a2018-03-07 17:30:10 -0700200 //
Chris Dalton04a1de52018-03-14 02:04:09 -0600201 // NOTE: the coverage inputs are only relevant for triangles. Otherwise they are null.
Chris Daltonfe462ef2018-03-08 15:54:01 +0000202 virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
Chris Dalton04a1de52018-03-14 02:04:09 -0600203 const char* position, const char* coverage,
204 const char* attenuatedCoverage, const char* wind) = 0;
Chris Dalton622650a2018-03-07 17:30:10 -0700205
Chris Daltonfe462ef2018-03-08 15:54:01 +0000206 // Emits the fragment code that calculates a pixel's signed coverage value.
Chris Daltonbaf3e782018-03-08 15:55:58 +0000207 virtual void onEmitFragmentCode(GrGLSLFPFragmentBuilder*,
Chris Daltonfe462ef2018-03-08 15:54:01 +0000208 const char* outputCoverage) const = 0;
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600209
Chris Dalton90e8fb12017-12-22 02:24:53 -0700210 // Returns the name of a Shader's internal varying at the point where where its value is
211 // assigned. This is intended to work whether called for a vertex or a geometry shader.
212 const char* OutName(const GrGLSLVarying& varying) const {
213 using Scope = GrGLSLVarying::Scope;
214 SkASSERT(Scope::kVertToGeo != varying.scope());
215 return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut();
216 }
Chris Daltonbaf3e782018-03-08 15:55:58 +0000217
218 // Defines a global float2 array that contains MSAA sample locations as offsets from pixel
219 // center. Subclasses can use this for software multisampling.
220 //
221 // Returns the number of samples.
222 static int DefineSoftSampleLocations(GrGLSLFPFragmentBuilder* f, const char* samplesName);
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600223 };
224
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600225 class GSImpl;
Chris Dalton90e8fb12017-12-22 02:24:53 -0700226 class VSImpl;
Chris Dalton1a325d22017-07-14 15:17:41 -0600227
228private:
Chris Dalton1a325d22017-07-14 15:17:41 -0600229 // Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't
230 // accidentally bleed into neighbor pixels.
231 static constexpr float kAABloatRadius = 0.491111f;
232
Chris Dalton1fbdb612017-12-12 12:48:47 -0700233 // Number of bezier points for curves, or 3 for triangles.
Chris Daltonbaf3e782018-03-08 15:55:58 +0000234 int numInputPoints() const { return RenderPassIsCubic(fRenderPass) ? 4 : 3; }
Chris Dalton1fbdb612017-12-12 12:48:47 -0700235
Chris Dalton90e8fb12017-12-22 02:24:53 -0700236 enum class Impl : bool {
237 kGeometryShader,
238 kVertexShader
239 };
240
Chris Dalton23261772017-12-10 16:41:45 -0700241 void initGS();
Chris Dalton84403d72018-02-13 21:46:17 -0500242 void initVS(GrResourceProvider*);
Chris Dalton90e8fb12017-12-22 02:24:53 -0700243
Chris Dalton23261772017-12-10 16:41:45 -0700244 void appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
Chris Dalton90e8fb12017-12-22 02:24:53 -0700245 SkTArray<GrMesh>* out) const;
246 void appendVSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
247 SkTArray<GrMesh>* out) const;
248
Chris Dalton1fbdb612017-12-12 12:48:47 -0700249 GrGLSLPrimitiveProcessor* createGSImpl(std::unique_ptr<Shader>) const;
Chris Dalton90e8fb12017-12-22 02:24:53 -0700250 GrGLSLPrimitiveProcessor* createVSImpl(std::unique_ptr<Shader>) const;
Chris Dalton1a325d22017-07-14 15:17:41 -0600251
Chris Daltona3e92712017-12-04 11:45:51 -0700252 const RenderPass fRenderPass;
Chris Dalton84403d72018-02-13 21:46:17 -0500253 const WindMethod fWindMethod;
Chris Dalton90e8fb12017-12-22 02:24:53 -0700254 const Impl fImpl;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500255 SkDEBUGCODE(float fDebugBloat = 0);
Chris Dalton1a325d22017-07-14 15:17:41 -0600256
Chris Dalton27059d32018-01-23 14:06:50 -0700257 // Used by VSImpl.
258 sk_sp<const GrBuffer> fVertexBuffer;
259 sk_sp<const GrBuffer> fIndexBuffer;
260 int fNumIndicesPerInstance;
261 GrPrimitiveType fPrimitiveType;
262
Chris Dalton6a3dbee2017-10-16 10:44:41 -0600263 typedef GrGeometryProcessor INHERITED;
Chris Dalton1a325d22017-07-14 15:17:41 -0600264};
265
Chris Dalton84403d72018-02-13 21:46:17 -0500266inline void GrCCCoverageProcessor::TriPointInstance::set(const SkPoint p[3], const Sk2f& trans) {
Chris Daltona3e92712017-12-04 11:45:51 -0700267 this->set(p[0], p[1], p[2], trans);
268}
269
Chris Dalton84403d72018-02-13 21:46:17 -0500270inline void GrCCCoverageProcessor::TriPointInstance::set(const SkPoint& p0, const SkPoint& p1,
Chris Dalton383a2ef2018-01-08 17:21:41 -0500271 const SkPoint& p2, const Sk2f& trans) {
Chris Daltona3e92712017-12-04 11:45:51 -0700272 Sk2f P0 = Sk2f::Load(&p0) + trans;
273 Sk2f P1 = Sk2f::Load(&p1) + trans;
274 Sk2f P2 = Sk2f::Load(&p2) + trans;
275 Sk2f::Store3(this, P0, P1, P2);
276}
277
Chris Dalton84403d72018-02-13 21:46:17 -0500278inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint p[4], float dx, float dy) {
Chris Daltona3e92712017-12-04 11:45:51 -0700279 Sk4f X,Y;
280 Sk4f::Load2(p, &X, &Y);
281 (X + dx).store(&fX);
282 (Y + dy).store(&fY);
283}
284
Chris Dalton84403d72018-02-13 21:46:17 -0500285inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint& p0, const SkPoint& p1,
286 const SkPoint& p2, const Sk2f& trans,
287 float w) {
288 Sk2f P0 = Sk2f::Load(&p0) + trans;
289 Sk2f P1 = Sk2f::Load(&p1) + trans;
290 Sk2f P2 = Sk2f::Load(&p2) + trans;
291 Sk2f W = Sk2f(w);
292 Sk2f::Store4(this, P0, P1, P2, W);
293}
294
Chris Daltonbaf3e782018-03-08 15:55:58 +0000295inline bool GrCCCoverageProcessor::RenderPassIsCubic(RenderPass pass) {
296 switch (pass) {
297 case RenderPass::kTriangles:
298 case RenderPass::kTriangleCorners:
299 case RenderPass::kQuadratics:
300 case RenderPass::kQuadraticCorners:
301 return false;
302 case RenderPass::kCubics:
303 case RenderPass::kCubicCorners:
304 return true;
305 }
306 SK_ABORT("Invalid RenderPass");
307 return false;
308}
309
Chris Dalton383a2ef2018-01-08 17:21:41 -0500310inline const char* GrCCCoverageProcessor::RenderPassName(RenderPass pass) {
Chris Dalton23261772017-12-10 16:41:45 -0700311 switch (pass) {
Chris Dalton5183e642018-03-07 12:53:01 -0700312 case RenderPass::kTriangles: return "kTriangles";
Chris Daltonfe462ef2018-03-08 15:54:01 +0000313 case RenderPass::kTriangleCorners: return "kTriangleCorners";
Chris Dalton5183e642018-03-07 12:53:01 -0700314 case RenderPass::kQuadratics: return "kQuadratics";
Chris Daltonbaf3e782018-03-08 15:55:58 +0000315 case RenderPass::kQuadraticCorners: return "kQuadraticCorners";
Chris Dalton5183e642018-03-07 12:53:01 -0700316 case RenderPass::kCubics: return "kCubics";
Chris Daltonbaf3e782018-03-08 15:55:58 +0000317 case RenderPass::kCubicCorners: return "kCubicCorners";
Chris Dalton23261772017-12-10 16:41:45 -0700318 }
Chris Dalton1fbdb612017-12-12 12:48:47 -0700319 SK_ABORT("Invalid RenderPass");
Chris Dalton23261772017-12-10 16:41:45 -0700320 return "";
321}
322
Chris Dalton1a325d22017-07-14 15:17:41 -0600323#endif