blob: f31dad793ece56431f83e4a4a3f9650037a33e5e [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#ifndef GrCCPRCubicProcessor_DEFINED
9#define GrCCPRCubicProcessor_DEFINED
10
11#include "ccpr/GrCCPRCoverageProcessor.h"
12
13class GrGLSLGeometryBuilder;
14
15/**
16 * This class renders the coverage of convex closed cubic segments using the techniques outlined in
17 * "Resolution Independent Curve Rendering using Programmable Graphics Hardware" by Charles Loop and
18 * Jim Blinn:
19 *
20 * https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf
21 *
22 * The caller is expected to chop cubics at the KLM roots (a.k.a. inflection points and loop
23 * intersection points, resulting in necessarily convex segments) before feeding them into this
24 * processor.
25 *
26 * The curves are rendered in two passes:
27 *
28 * Pass 1: Draw the (convex) bezier quadrilateral, inset by 1/2 pixel all around, and use the
29 * gradient-based AA technique outlined in the Loop/Blinn paper to compute coverage.
30 *
31 * Pass 2: Draw a border around the previous inset, up to the bezier quadrilatral's conservative
32 * raster hull, and compute coverage using pseudo MSAA. This pass is necessary because the
33 * gradient approach does not work near the L and M lines.
34 *
35 * FIXME: The pseudo MSAA border is slow and ugly. We should investigate an alternate solution of
36 * just approximating the curve with straight lines for short distances across the problem points
37 * instead.
38 */
39class GrCCPRCubicProcessor : public GrCCPRCoverageProcessor::PrimitiveProcessor {
40public:
41 enum class Type {
42 kSerpentine,
43 kLoop
44 };
45
46 GrCCPRCubicProcessor(Type type)
47 : INHERITED(CoverageType::kShader)
48 , fType(type)
49 , fInset(kVec3f_GrSLType)
50 , fTS(kFloat_GrSLType)
51 , fKLMMatrix("klm_matrix", kMat33f_GrSLType, GrShaderVar::kNonArray,
52 kHigh_GrSLPrecision)
53 , fKLMDerivatives("klm_derivatives", kVec2f_GrSLType, 3, kHigh_GrSLPrecision) {}
54
55 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override {
56 varyingHandler->addVarying("insets", &fInset, kHigh_GrSLPrecision);
57 varyingHandler->addVarying("ts", &fTS, kHigh_GrSLPrecision);
58 }
59
60 void onEmitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*,
61 const TexelBufferHandle& pointsBuffer, const char* atlasOffset,
62 const char* rtAdjust, GrGPArgs*) const override;
63 void emitWind(GrGLSLGeometryBuilder*, const char* rtAdjust, const char* outputWind) const final;
64 void onEmitGeometryShader(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* wind,
65 const char* rtAdjust) const final;
66
67protected:
68 virtual void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn,
69 const char* wind, const char* rtAdjust) const = 0;
70
71 const Type fType;
72 GrGLSLVertToGeo fInset;
73 GrGLSLVertToGeo fTS;
74 GrShaderVar fKLMMatrix;
75 GrShaderVar fKLMDerivatives;
76
77 typedef GrCCPRCoverageProcessor::PrimitiveProcessor INHERITED;
78};
79
80class GrCCPRCubicInsetProcessor : public GrCCPRCubicProcessor {
81public:
82 GrCCPRCubicInsetProcessor(Type type)
83 : INHERITED(type)
84 , fKLM(kVec3f_GrSLType)
85 , fGradMatrix(kMat22f_GrSLType) {}
86
87 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override {
88 this->INHERITED::resetVaryings(varyingHandler);
89 varyingHandler->addVarying("klm", &fKLM, kHigh_GrSLPrecision);
90 varyingHandler->addVarying("grad_matrix", &fGradMatrix, kHigh_GrSLPrecision);
91 }
92
93 void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn,
94 const char* wind, const char* rtAdjust) const override;
95 void emitPerVertexGeometryCode(SkString* fnBody, const char* position, const char* coverage,
96 const char* wind) const override;
97 void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const override;
98
99protected:
100 GrGLSLGeoToFrag fKLM;
101 GrGLSLGeoToFrag fGradMatrix;
102
103 typedef GrCCPRCubicProcessor INHERITED;
104};
105
106class GrCCPRCubicBorderProcessor : public GrCCPRCubicProcessor {
107public:
108 GrCCPRCubicBorderProcessor(Type type)
109 : INHERITED(type)
110 , fEdgeDistanceEquation("edge_distance_equation", kVec3f_GrSLType,
111 GrShaderVar::kNonArray, kHigh_GrSLPrecision)
112 , fEdgeDistanceDerivatives("edge_distance_derivatives", kVec2f_GrSLType,
113 GrShaderVar::kNonArray, kHigh_GrSLPrecision)
114 , fEdgeSpaceTransform("edge_space_transform", kVec4f_GrSLType, GrShaderVar::kNonArray,
115 kHigh_GrSLPrecision)
116 , fKLMD(kVec4f_GrSLType)
117 , fdKLMDdx(kVec4f_GrSLType)
118 , fdKLMDdy(kVec4f_GrSLType)
119 , fEdgeSpaceCoord(kVec2f_GrSLType) {}
120
121 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override {
122 this->INHERITED::resetVaryings(varyingHandler);
123 varyingHandler->addVarying("klmd", &fKLMD, kHigh_GrSLPrecision);
124 varyingHandler->addFlatVarying("dklmddx", &fdKLMDdx, kHigh_GrSLPrecision);
125 varyingHandler->addFlatVarying("dklmddy", &fdKLMDdy, kHigh_GrSLPrecision);
126 varyingHandler->addVarying("edge_space_coord", &fEdgeSpaceCoord, kHigh_GrSLPrecision);
127 }
128
129 void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn,
130 const char* wind, const char* rtAdjust) const override;
131 void emitPerVertexGeometryCode(SkString* fnBody, const char* position, const char* coverage,
132 const char* wind) const override;
133 void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const override;
134
135protected:
136 GrShaderVar fEdgeDistanceEquation;
137 GrShaderVar fEdgeDistanceDerivatives;
138 GrShaderVar fEdgeSpaceTransform;
139 GrGLSLGeoToFrag fKLMD;
140 GrGLSLGeoToFrag fdKLMDdx;
141 GrGLSLGeoToFrag fdKLMDdy;
142 GrGLSLGeoToFrag fEdgeSpaceCoord;
143
144 typedef GrCCPRCubicProcessor INHERITED;
145};
146
147#endif