blob: 9a70850a444f987a363547eb009170005e0c4895 [file] [log] [blame]
Michael Ludwig460eb5e2018-10-29 11:09:29 -04001/*
2 * Copyright 2018 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 GrQuadPerEdgeAA_DEFINED
9#define GrQuadPerEdgeAA_DEFINED
10
11#include "GrColor.h"
Michael Ludwig20e909e2018-10-30 10:43:57 -040012#include "GrPrimitiveProcessor.h"
Michael Ludwig460eb5e2018-10-29 11:09:29 -040013#include "GrSamplerState.h"
14#include "GrTypesPriv.h"
Michael Ludwig20e909e2018-10-30 10:43:57 -040015#include "glsl/GrGLSLPrimitiveProcessor.h"
Michael Ludwig460eb5e2018-10-29 11:09:29 -040016#include "SkPoint.h"
17#include "SkPoint3.h"
18
Michael Ludwig20e909e2018-10-30 10:43:57 -040019class GrGLSLColorSpaceXformHelper;
Michael Ludwig460eb5e2018-10-29 11:09:29 -040020class GrPerspQuad;
21
22class GrQuadPerEdgeAA {
23public:
24 enum class Domain : bool { kNo = false, kYes = true };
25
26 // The vertex template provides a clean way of specifying the layout and components of a vertex
27 // for a per-edge aa quad. However, because there are so many permutations possible, the struct
28 // is defined this way to take away all layout control from the compiler and make
29 // sure that it matches what we need to send to the GPU.
30 //
31 // It is expected that most code using these vertices will only need to call the templated
32 // Tessellate() function with an appropriately sized vertex buffer and not need to modify or
33 // read the fields of a particular vertex.
34 template <int PosDim, typename C, int LocalPosDim, Domain D, GrAA AA>
35 struct Vertex {
36 using Color = C;
37 static constexpr GrAA kAA = AA;
38 static constexpr Domain kDomain = D;
39 static constexpr size_t kPositionDim = PosDim;
40 static constexpr size_t kLocalPositionDim = LocalPosDim;
41
42 static constexpr size_t kPositionOffset = 0;
43 static constexpr size_t kPositionSize = PosDim * sizeof(float);
44
45 static constexpr size_t kColorOffset = kPositionOffset + kPositionSize;
46 static constexpr size_t kColorSize = sizeof(Color);
47
48 static constexpr size_t kLocalPositionOffset = kColorOffset + kColorSize;
49 static constexpr size_t kLocalPositionSize = LocalPosDim * sizeof(float);
50
51 static constexpr size_t kDomainOffset = kLocalPositionOffset + kLocalPositionSize;
52 static constexpr size_t kDomainSize = D == Domain::kYes ? sizeof(SkRect) : 0;
53
54 static constexpr size_t kAAOffset = kDomainOffset + kDomainSize;
55 static constexpr size_t kAASize = AA == GrAA::kYes ? 4 * sizeof(SkPoint3) : 0;
56
57 static constexpr size_t kVertexSize = kAAOffset + kAASize;
58
59 // Make sure sizeof(Vertex<...>) == kVertexSize
60 char fData[kVertexSize];
61 };
62
Michael Ludwig20e909e2018-10-30 10:43:57 -040063 // Utility class that manages the attribute state necessary to render a particular batch of
64 // quads. It is similar to a geometry processor but is meant to be included in a has-a
65 // relationship by specialized GP's that provide further functionality on top of the per-edge AA
66 // coverage.
67 //
68 // For performance reasons, this uses fixed names for the attribute variables; since it defines
69 // the majority of attributes a GP will likely need, this shouldn't be too limiting.
70 //
71 // In terms of responsibilities, the actual geometry processor must still call emitTransforms(),
72 // using the localCoords() attribute as the 4th argument; it must set the transform data helper
73 // to use the identity matrix; it must manage the color space transform for the quad's paint
74 // color; it should include getKey() in the geometry processor's key builder; and it should
75 // return these managed attributes from its onVertexAttribute() function.
76 class GPAttributes {
77 public:
78 using Attribute = GrPrimitiveProcessor::Attribute;
79
80 GPAttributes(int posDim, int localDim, bool hasColor, GrAAType aa, Domain domain);
81
82 const Attribute& positions() const { return fPositions; }
83 const Attribute& colors() const { return fColors; }
84 const Attribute& localCoords() const { return fLocalCoords; }
85 const Attribute& domain() const { return fDomain; }
86 const Attribute& edges(int i) const { return fAAEdges[i]; }
87
88 bool hasVertexColors() const { return fColors.isInitialized(); }
89
90 bool usesCoverageAA() const { return fAAEdges[0].isInitialized(); }
91
92 bool hasLocalCoords() const { return fLocalCoords.isInitialized(); }
93
94 bool hasDomain() const { return fDomain.isInitialized(); }
95
96 bool needsPerspectiveInterpolation() const;
97
98 int vertexAttributeCount() const;
99
100 uint32_t getKey() const;
101
102 // Functions to be called at appropriate times in a processor's onEmitCode() block. These
103 // are separated into discrete pieces so that they can be interleaved with the rest of the
104 // processor's shader code as needed. The functions take char* arguments for the names of
105 // variables the emitted code must declare, so that the calling GP can ensure there's no
106 // naming conflicts with their own code.
107
108 void emitColor(GrGLSLPrimitiveProcessor::EmitArgs& args,
109 GrGLSLColorSpaceXformHelper* colorSpaceXformHelper,
110 const char* colorVarName) const;
111
112 // localCoordName will be declared as a float2, with any domain applied after any
113 // perspective division is performed.
114 //
115 // Note: this should only be used if the local coordinates need to be passed separately
116 // from the standard coord transform process that is used by FPs.
117 // FIXME: This can go in two directions from here, if GrTextureOp stops needing per-quad
118 // domains it can be removed and GrTextureOp rewritten to use coord transforms. Or
119 // emitTransform() in the primitive builder can be updated to have a notion of domain for
120 // local coords, and all domain-needing code (blurs, filters, etc.) can switch to that magic
121 void emitExplicitLocalCoords(GrGLSLPrimitiveProcessor::EmitArgs& args,
122 const char* localCoordName, const char* domainVarName) const;
123
124 void emitCoverage(GrGLSLPrimitiveProcessor::EmitArgs& args, const char* edgeDistName) const;
125 private:
126 Attribute fPositions; // named "position" in SkSL
127 Attribute fColors; // named "color" in SkSL
128 Attribute fLocalCoords; // named "localCoord" in SkSL
129 Attribute fDomain; // named "domain" in SkSL
130 Attribute fAAEdges[4]; // named "aaEdgeX" for X = 0,1,2,3
131 };
132
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400133 // Tessellate the given quad specification into the vertices buffer. If the specific vertex
134 // type does not use color, local positions, domain, etc. then the passed in values used for
135 // that field will be ignored.
136 template<typename V>
137 static void Tessellate(V* vertices, const GrPerspQuad& deviceQuad, typename V::Color color,
138 const GrPerspQuad& srcQuad, const SkRect& domain, GrQuadAAFlags aa) {
139 static_assert(sizeof(V) == V::kVertexSize, "Incorrect vertex size");
140 static constexpr bool useCoverageAA = V::kAA == GrAA::kYes;
141 float localStorage[4 * (V::kPositionDim + V::kLocalPositionDim + (useCoverageAA ? 3 : 0))];
142 TessellateImpl(vertices, V::kVertexSize, localStorage,
143 deviceQuad, V::kPositionDim, V::kPositionOffset, V::kPositionSize,
144 &color, V::kColorOffset, V::kColorSize,
145 srcQuad, V::kLocalPositionDim, V::kLocalPositionOffset, V::kLocalPositionSize,
146 &domain, V::kDomainOffset, V::kDomainSize,
147 aa, V::kAAOffset, V::kAASize);
148 }
149
150private:
151 // Don't let the "namespace" class be instantiated
152 GrQuadPerEdgeAA();
153
154 // Internal implementation that can handle all vertex template variations without being
155 // replicated by the template in order to keep code size down.
156 //
157 // This uses the field sizes to determine if particular data needs to be computed. The arguments
158 // are arranged so that the data and field specification match the field declaration order of
159 // the vertex type (pos, color, localPos, domain, aa).
160 //
161 // localStorage must be have a length > 4 * (devDimCt + srcDimCt + (aa ? 3 : 0)) and is assumed
162 // to be a pointer to a local variable in the wrapping template's stack. This is done instead of
163 // always allocating 36 floats in this function (36 is maximum needed). The minimum needed for a
164 // non-AA 2D quad with no local coordinates is just 8.
165 static void TessellateImpl(void* vertices, size_t vertexSize, float* localStorage,
166 const GrPerspQuad& deviceQuad, int posDim, size_t posOffset, size_t posSize,
167 const void* color, size_t colorOffset, size_t colorSize,
168 const GrPerspQuad& srcQuad, int srcDim, size_t srcOffset, size_t srcSize,
169 const void* domain, size_t domainOffset, size_t domainSize,
170 GrQuadAAFlags aaFlags, size_t aaOffset, size_t aaSize);
171};
172
173#endif // GrQuadPerEdgeAA_DEFINED