• 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::ganesh::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,
68                ColorType colorType,
69                GrQuad::Type localQuadType,
70                bool hasLocalCoords,
71                Subset subset,
72                GrAAType aa,
73                bool coverageAsAlpha,
74                IndexBufferOption indexBufferOption)
75             : fDeviceQuadType(static_cast<unsigned>(deviceQuadType))
76             , fLocalQuadType(static_cast<unsigned>(localQuadType))
77             , fIndexBufferOption(static_cast<unsigned>(indexBufferOption))
78             , fHasLocalCoords(hasLocalCoords)
79             , fColorType(static_cast<unsigned>(colorType))
80             , fHasSubset(static_cast<unsigned>(subset))
81             , fUsesCoverageAA(aa == GrAAType::kCoverage)
82             , fCompatibleWithCoverageAsAlpha(coverageAsAlpha)
83             , fRequiresGeometrySubset(aa == GrAAType::kCoverage &&
84                                       deviceQuadType > GrQuad::Type::kRectilinear) {}
85 
deviceQuadTypeVertexSpec86     GrQuad::Type deviceQuadType() const { return static_cast<GrQuad::Type>(fDeviceQuadType); }
localQuadTypeVertexSpec87     GrQuad::Type localQuadType() const { return static_cast<GrQuad::Type>(fLocalQuadType); }
indexBufferOptionVertexSpec88     IndexBufferOption indexBufferOption() const {
89         return static_cast<IndexBufferOption>(fIndexBufferOption);
90     }
hasLocalCoordsVertexSpec91     bool hasLocalCoords() const { return fHasLocalCoords; }
colorTypeVertexSpec92     ColorType colorType() const { return static_cast<ColorType>(fColorType); }
hasVertexColorsVertexSpec93     bool hasVertexColors() const { return ColorType::kNone != this->colorType(); }
hasSubsetVertexSpec94     bool hasSubset() const { return fHasSubset; }
usesCoverageAAVertexSpec95     bool usesCoverageAA() const { return fUsesCoverageAA; }
compatibleWithCoverageAsAlphaVertexSpec96     bool compatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
requiresGeometrySubsetVertexSpec97     bool requiresGeometrySubset() const { return fRequiresGeometrySubset; }
98     // Will always be 2 or 3
99     int deviceDimensionality() const;
100     // Will always be 0 if hasLocalCoords is false, otherwise will be 2 or 3
101     int localDimensionality() const;
102 
verticesPerQuadVertexSpec103     int verticesPerQuad() const { return fUsesCoverageAA ? 8 : 4; }
104 
105     CoverageMode coverageMode() const;
106     size_t vertexSize() const;
107 
needsIndexBufferVertexSpec108     bool needsIndexBuffer() const {
109         return this->indexBufferOption() != IndexBufferOption::kTriStrips;
110     }
111 
primitiveTypeVertexSpec112     GrPrimitiveType primitiveType() const {
113         switch (this->indexBufferOption()) {
114             case IndexBufferOption::kPictureFramed:
115                 return GrPrimitiveType::kTriangles;
116             case IndexBufferOption::kIndexedRects:
117                 return GrPrimitiveType::kTriangles;
118             case IndexBufferOption::kTriStrips:
119                 return GrPrimitiveType::kTriangleStrip;
120         }
121 
122         SkUNREACHABLE;
123     }
124 
125 private:
126     static_assert(GrQuad::kTypeCount <= 4, "GrQuad::Type doesn't fit in 2 bits");
127     static_assert(kColorTypeCount <= 4, "Color doesn't fit in 2 bits");
128     static_assert(kIndexBufferOptionCount <= 4, "IndexBufferOption doesn't fit in 2 bits");
129 
130     unsigned fDeviceQuadType : 2;
131     unsigned fLocalQuadType : 2;
132     unsigned fIndexBufferOption : 2;
133     unsigned fHasLocalCoords : 1;
134     unsigned fColorType : 2;
135     unsigned fHasSubset : 1;
136     unsigned fUsesCoverageAA : 1;
137     unsigned fCompatibleWithCoverageAsAlpha : 1;
138     // The geometry subset serves to clip off pixels touched by quads with sharp corners that
139     // would otherwise exceed the miter limit for the AA-outset geometry.
140     unsigned fRequiresGeometrySubset : 1;
141     };
142 
143     // A Tessellator is responsible for processing a series of device+local GrQuads into a VBO,
144     // as specified by a VertexSpec. This vertex data can then be processed by a GP created with
145     // MakeProcessor and/or MakeTexturedProcessor.
146     class Tessellator {
147     public:
148         explicit Tessellator(const VertexSpec& spec, char* vertices);
149 
150         // Calculates (as needed) inset and outset geometry for anti-aliasing, and appends all
151         // necessary position and vertex attributes required by this Tessellator's VertexSpec into
152         // the 'vertices' the Tessellator was called with. The insetting and outsetting may
153         // damage the provided GrQuads (as this is intended to work with GrQuadBuffer::Iter).
154         // 'localQuad' can be null if the VertexSpec does not use local coords.
155         void append(GrQuad* deviceQuad, GrQuad* localQuad,
156                     const SkPMColor4f& color, const SkRect& uvSubset, GrQuadAAFlags aaFlags);
157 
158         SkDEBUGCODE(skgpu::BufferWriter::Mark vertexMark() const { return fVertexWriter.mark(); })
159 
160     private:
161         // VertexSpec defines many unique ways to write vertex attributes, which can be handled
162         // generically by branching per-quad based on the VertexSpec. However, there are several
163         // specs that appear in the wild far more frequently, so they use explicit WriteQuadProcs
164         // that have no branches.
165         typedef void (*WriteQuadProc)(VertexWriter* vertices, const VertexSpec& spec,
166                                       const GrQuad* deviceQuad, const GrQuad* localQuad,
167                                       const float coverage[4], const SkPMColor4f& color,
168                                       const SkRect& geomSubset, const SkRect& texSubset);
169         static WriteQuadProc GetWriteQuadProc(const VertexSpec& spec);
170 
171         GrQuadUtils::TessellationHelper fAAHelper;
172         VertexSpec                      fVertexSpec;
173         VertexWriter                    fVertexWriter;
174         WriteQuadProc                   fWriteProc;
175     };
176 
177     GrGeometryProcessor* MakeProcessor(SkArenaAlloc*, const VertexSpec&);
178 
179     GrGeometryProcessor* MakeTexturedProcessor(SkArenaAlloc*,
180                                                const VertexSpec&,
181                                                const GrShaderCaps&,
182                                                const GrBackendFormat&,
183                                                GrSamplerState,
184                                                const skgpu::Swizzle&,
185                                                sk_sp<GrColorSpaceXform> textureColorSpaceXform,
186                                                Saturate);
187 
188     // This method will return the correct index buffer for the specified indexBufferOption.
189     // It will, correctly, return nullptr if the indexBufferOption is kTriStrips.
190     sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawTarget*, IndexBufferOption);
191 
192     // What is the maximum number of quads allowed for the specified indexBuffer option?
193     int QuadLimit(IndexBufferOption);
194 
195     // This method will issue the draw call on the provided GrOpsRenderPass, as specified by the
196     // indexing method in vertexSpec. It is up to the calling code to allocate, fill in, and bind a
197     // vertex buffer, and to acquire and bind the correct index buffer (if needed) with
198     // GrPrimitiveRestart::kNo.
199     //
200     // @param runningQuadCount  the number of quads already stored in 'vertexBuffer' and
201     //                          'indexBuffer' e.g., different GrMeshes have already been placed in
202     //                          the buffers to allow dynamic state changes.
203     // @param quadCount         the number of quads that will be drawn by the provided 'mesh'.
204     //                          A subsequent ConfigureMesh call would the use
205     //                          'runningQuadCount' + 'quadCount' for its new 'runningQuadCount'.
206     void IssueDraw(const GrCaps&, GrOpsRenderPass*, const VertexSpec&, int runningQuadCount,
207                    int quadCount, int maxVerts, int absVertBufferOffset);
208 
209     }  // namespace skgpu::ganesh::QuadPerEdgeAA
210 
211 #endif // QuadPerEdgeAA_DEFINED
212