• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 QuadPerEdgeAA_DEFINED
9 #define QuadPerEdgeAA_DEFINED
10 
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkPoint3.h"
13 #include "include/private/gpu/ganesh/GrTypesPriv.h"
14 #include "src/gpu/BufferWriter.h"
15 #include "src/gpu/ganesh/GrBuffer.h"
16 #include "src/gpu/ganesh/GrColor.h"
17 #include "src/gpu/ganesh/GrGeometryProcessor.h"
18 #include "src/gpu/ganesh/GrSamplerState.h"
19 #include "src/gpu/ganesh/geometry/GrQuad.h"
20 #include "src/gpu/ganesh/geometry/GrQuadUtils.h"
21 #include "src/gpu/ganesh/ops/TextureOp.h"
22 
23 class GrCaps;
24 class GrColorSpaceXform;
25 class GrMeshDrawTarget;
26 struct GrShaderCaps;
27 struct VertexWriter;
28 
29 namespace skgpu::v1::QuadPerEdgeAA {
30     using Saturate = skgpu::ganesh::TextureOp::Saturate;
31 
32     enum class CoverageMode { kNone, kWithPosition, kWithColor };
33     enum class Subset : bool { kNo = false, kYes = true };
34     enum class ColorType { kNone, kByte, kFloat, kLast = kFloat };
35     static const int kColorTypeCount = static_cast<int>(ColorType::kLast) + 1;
36 
37     enum class IndexBufferOption {
38         kPictureFramed,    // geometrically AA'd   -> 8 verts/quad + an index buffer
39         kIndexedRects,     // non-AA'd but indexed -> 4 verts/quad + an index buffer
40         kTriStrips,        // non-AA'd             -> 4 verts/quad but no index buffer
41         kLast = kTriStrips
42     };
43     static const int kIndexBufferOptionCount = static_cast<int>(IndexBufferOption::kLast) + 1;
44 
45     IndexBufferOption CalcIndexBufferOption(GrAAType aa, int numQuads);
46 
47     // Gets the minimum ColorType that can represent a color.
48     ColorType MinColorType(SkPMColor4f);
49 
50     // Specifies the vertex configuration for an op that renders per-edge AA quads. The vertex
51     // order (when enabled) is device position, color, local position, subset, aa edge equations.
52     // This order matches the constructor argument order of VertexSpec and is the order that
53     // GPAttributes maintains. If hasLocalCoords is false, then the local quad type can be ignored.
54     struct VertexSpec {
55     public:
VertexSpecVertexSpec56         VertexSpec()
57                 : fDeviceQuadType(0)     // kAxisAligned
58                 , fLocalQuadType(0)      // kAxisAligned
59                 , fIndexBufferOption(0)  // kPictureFramed
60                 , fHasLocalCoords(false)
61                 , fColorType(0)          // kNone
62                 , fHasSubset(false)
63                 , fUsesCoverageAA(false)
64                 , fCompatibleWithCoverageAsAlpha(false)
65                 , fRequiresGeometrySubset(false) {}
66 
VertexSpecVertexSpec67         VertexSpec(GrQuad::Type deviceQuadType, ColorType colorType, GrQuad::Type localQuadType,
68                    bool hasLocalCoords,
69                    Subset subset, GrAAType aa, bool coverageAsAlpha,
70                    IndexBufferOption indexBufferOption)
71                 : fDeviceQuadType(static_cast<unsigned>(deviceQuadType))
72                 , fLocalQuadType(static_cast<unsigned>(localQuadType))
73                 , fIndexBufferOption(static_cast<unsigned>(indexBufferOption))
74                 , fHasLocalCoords(hasLocalCoords)
75                 , fColorType(static_cast<unsigned>(colorType))
76                 , fHasSubset(static_cast<unsigned>(subset))
77                 , fUsesCoverageAA(aa == GrAAType::kCoverage)
78                 , fCompatibleWithCoverageAsAlpha(coverageAsAlpha)
79                 , fRequiresGeometrySubset(aa == GrAAType::kCoverage &&
80                                           deviceQuadType > GrQuad::Type::kRectilinear) { }
81 
deviceQuadTypeVertexSpec82         GrQuad::Type deviceQuadType() const { return static_cast<GrQuad::Type>(fDeviceQuadType); }
localQuadTypeVertexSpec83         GrQuad::Type localQuadType() const { return static_cast<GrQuad::Type>(fLocalQuadType); }
indexBufferOptionVertexSpec84         IndexBufferOption indexBufferOption() const {
85             return static_cast<IndexBufferOption>(fIndexBufferOption);
86         }
hasLocalCoordsVertexSpec87         bool hasLocalCoords() const { return fHasLocalCoords; }
colorTypeVertexSpec88         ColorType colorType() const { return static_cast<ColorType>(fColorType); }
hasVertexColorsVertexSpec89         bool hasVertexColors() const { return ColorType::kNone != this->colorType(); }
hasSubsetVertexSpec90         bool hasSubset() const { return fHasSubset; }
usesCoverageAAVertexSpec91         bool usesCoverageAA() const { return fUsesCoverageAA; }
compatibleWithCoverageAsAlphaVertexSpec92         bool compatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
requiresGeometrySubsetVertexSpec93         bool requiresGeometrySubset() const { return fRequiresGeometrySubset; }
94         // Will always be 2 or 3
95         int deviceDimensionality() const;
96         // Will always be 0 if hasLocalCoords is false, otherwise will be 2 or 3
97         int localDimensionality() const;
98 
verticesPerQuadVertexSpec99         int verticesPerQuad() const { return fUsesCoverageAA ? 8 : 4; }
100 
101         CoverageMode coverageMode() const;
102         size_t vertexSize() const;
103 
needsIndexBufferVertexSpec104         bool needsIndexBuffer() const { return this->indexBufferOption() !=
105                                                IndexBufferOption::kTriStrips; }
106 
primitiveTypeVertexSpec107         GrPrimitiveType primitiveType() const {
108             switch (this->indexBufferOption()) {
109                 case IndexBufferOption::kPictureFramed: return GrPrimitiveType::kTriangles;
110                 case IndexBufferOption::kIndexedRects:  return GrPrimitiveType::kTriangles;
111                 case IndexBufferOption::kTriStrips:     return GrPrimitiveType::kTriangleStrip;
112             }
113 
114             SkUNREACHABLE;
115         }
116 
117     private:
118         static_assert(GrQuad::kTypeCount <= 4, "GrQuad::Type doesn't fit in 2 bits");
119         static_assert(kColorTypeCount <= 4, "Color doesn't fit in 2 bits");
120         static_assert(kIndexBufferOptionCount <= 4, "IndexBufferOption doesn't fit in 2 bits");
121 
122         unsigned fDeviceQuadType: 2;
123         unsigned fLocalQuadType: 2;
124         unsigned fIndexBufferOption: 2;
125         unsigned fHasLocalCoords: 1;
126         unsigned fColorType : 2;
127         unsigned fHasSubset : 1;
128         unsigned fUsesCoverageAA: 1;
129         unsigned fCompatibleWithCoverageAsAlpha: 1;
130         // The geometry subset serves to clip off pixels touched by quads with sharp corners that
131         // would otherwise exceed the miter limit for the AA-outset geometry.
132         unsigned fRequiresGeometrySubset : 1;
133     };
134 
135     // A Tessellator is responsible for processing a series of device+local GrQuads into a VBO,
136     // as specified by a VertexSpec. This vertex data can then be processed by a GP created with
137     // MakeProcessor and/or MakeTexturedProcessor.
138     class Tessellator {
139     public:
140         explicit Tessellator(const VertexSpec& spec, char* vertices);
141 
142         // Calculates (as needed) inset and outset geometry for anti-aliasing, and appends all
143         // necessary position and vertex attributes required by this Tessellator's VertexSpec into
144         // the 'vertices' the Tessellator was called with. The insetting and outsetting may
145         // damage the provided GrQuads (as this is intended to work with GrQuadBuffer::Iter).
146         // 'localQuad' can be null if the VertexSpec does not use local coords.
147         void append(GrQuad* deviceQuad, GrQuad* localQuad,
148                     const SkPMColor4f& color, const SkRect& uvSubset, GrQuadAAFlags aaFlags);
149 
150         SkDEBUGCODE(skgpu::BufferWriter::Mark vertexMark() const { return fVertexWriter.mark(); })
151 
152     private:
153         // VertexSpec defines many unique ways to write vertex attributes, which can be handled
154         // generically by branching per-quad based on the VertexSpec. However, there are several
155         // specs that appear in the wild far more frequently, so they use explicit WriteQuadProcs
156         // that have no branches.
157         typedef void (*WriteQuadProc)(VertexWriter* vertices, const VertexSpec& spec,
158                                       const GrQuad* deviceQuad, const GrQuad* localQuad,
159                                       const float coverage[4], const SkPMColor4f& color,
160                                       const SkRect& geomSubset, const SkRect& texSubset);
161         static WriteQuadProc GetWriteQuadProc(const VertexSpec& spec);
162 
163         GrQuadUtils::TessellationHelper fAAHelper;
164         VertexSpec                      fVertexSpec;
165         VertexWriter                    fVertexWriter;
166         WriteQuadProc                   fWriteProc;
167     };
168 
169     GrGeometryProcessor* MakeProcessor(SkArenaAlloc*, const VertexSpec&);
170 
171     GrGeometryProcessor* MakeTexturedProcessor(SkArenaAlloc*,
172                                                const VertexSpec&,
173                                                const GrShaderCaps&,
174                                                const GrBackendFormat&,
175                                                GrSamplerState,
176                                                const skgpu::Swizzle&,
177                                                sk_sp<GrColorSpaceXform> textureColorSpaceXform,
178                                                Saturate);
179 
180     // This method will return the correct index buffer for the specified indexBufferOption.
181     // It will, correctly, return nullptr if the indexBufferOption is kTriStrips.
182     sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawTarget*, IndexBufferOption);
183 
184     // What is the maximum number of quads allowed for the specified indexBuffer option?
185     int QuadLimit(IndexBufferOption);
186 
187     // This method will issue the draw call on the provided GrOpsRenderPass, as specified by the
188     // indexing method in vertexSpec. It is up to the calling code to allocate, fill in, and bind a
189     // vertex buffer, and to acquire and bind the correct index buffer (if needed) with
190     // GrPrimitiveRestart::kNo.
191     //
192     // @param runningQuadCount  the number of quads already stored in 'vertexBuffer' and
193     //                          'indexBuffer' e.g., different GrMeshes have already been placed in
194     //                          the buffers to allow dynamic state changes.
195     // @param quadCount         the number of quads that will be drawn by the provided 'mesh'.
196     //                          A subsequent ConfigureMesh call would the use
197     //                          'runningQuadCount' + 'quadCount' for its new 'runningQuadCount'.
198     void IssueDraw(const GrCaps&, GrOpsRenderPass*, const VertexSpec&, int runningQuadCount,
199                    int quadCount, int maxVerts, int absVertBufferOffset);
200 
201 } // namespace skgpu::v1::QuadPerEdgeAA
202 
203 #endif // QuadPerEdgeAA_DEFINED
204