1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/QuadPerEdgeAA.h"
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkVx.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpsRenderPass.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderVar.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrQuadUtils.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
33*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
34*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
35*c8dee2aaSAndroid Build Coastguard Worker
36*c8dee2aaSAndroid Build Coastguard Worker class GrBackendFormat;
37*c8dee2aaSAndroid Build Coastguard Worker class GrGLSLProgramDataManager;
38*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
39*c8dee2aaSAndroid Build Coastguard Worker class Swizzle;
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kLeft == SkCanvas::kLeft_QuadAAFlag);
43*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kTop == SkCanvas::kTop_QuadAAFlag);
44*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kRight == SkCanvas::kRight_QuadAAFlag);
45*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kBottom == SkCanvas::kBottom_QuadAAFlag);
46*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kNone == SkCanvas::kNone_QuadAAFlags);
47*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)GrQuadAAFlags::kAll == SkCanvas::kAll_QuadAAFlags);
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh::QuadPerEdgeAA {
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker namespace {
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker using VertexSpec = skgpu::ganesh::QuadPerEdgeAA::VertexSpec;
54*c8dee2aaSAndroid Build Coastguard Worker using CoverageMode = skgpu::ganesh::QuadPerEdgeAA::CoverageMode;
55*c8dee2aaSAndroid Build Coastguard Worker using ColorType = skgpu::ganesh::QuadPerEdgeAA::ColorType;
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker // Generic WriteQuadProc that can handle any VertexSpec. It writes the 4 vertices in triangle strip
58*c8dee2aaSAndroid Build Coastguard Worker // order, although the data per-vertex is dependent on the VertexSpec.
write_quad_generic(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)59*c8dee2aaSAndroid Build Coastguard Worker void write_quad_generic(VertexWriter* vb,
60*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
61*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
62*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
63*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
64*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
65*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
66*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
67*c8dee2aaSAndroid Build Coastguard Worker static constexpr auto If = VertexWriter::If<float>;
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasLocalCoords() || localQuad);
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker CoverageMode mode = spec.coverageMode();
72*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
73*c8dee2aaSAndroid Build Coastguard Worker // save position, this is a float2 or float3 or float4 depending on the combination of
74*c8dee2aaSAndroid Build Coastguard Worker // perspective and coverage mode.
75*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
76*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
77*c8dee2aaSAndroid Build Coastguard Worker << If(spec.deviceQuadType() == GrQuad::Type::kPerspective, deviceQuad->w(i))
78*c8dee2aaSAndroid Build Coastguard Worker << If(mode == CoverageMode::kWithPosition, coverage[i]);
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker // save color
81*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasVertexColors()) {
82*c8dee2aaSAndroid Build Coastguard Worker bool wide = spec.colorType() == ColorType::kFloat;
83*c8dee2aaSAndroid Build Coastguard Worker *vb << VertexColor(color * (mode == CoverageMode::kWithColor ? coverage[i] : 1), wide);
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker // save local position
87*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasLocalCoords()) {
88*c8dee2aaSAndroid Build Coastguard Worker *vb << localQuad->x(i)
89*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i)
90*c8dee2aaSAndroid Build Coastguard Worker << If(spec.localQuadType() == GrQuad::Type::kPerspective, localQuad->w(i));
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker // save the geometry subset
94*c8dee2aaSAndroid Build Coastguard Worker if (spec.requiresGeometrySubset()) {
95*c8dee2aaSAndroid Build Coastguard Worker *vb << geomSubset;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker // save the texture subset
99*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasSubset()) {
100*c8dee2aaSAndroid Build Coastguard Worker *vb << texSubset;
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker // Specialized WriteQuadProcs for particular VertexSpecs that show up frequently (determined
106*c8dee2aaSAndroid Build Coastguard Worker // experimentally through recorded GMs, SKPs, and SVGs, as well as SkiaRenderer's usage patterns):
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), no explicit coverage, vertex color, no locals, no geometry subset, no texture subsetn
109*c8dee2aaSAndroid Build Coastguard Worker // This represents simple, solid color or shader, non-AA (or AA with cov. as alpha) rects.
write_2d_color(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)110*c8dee2aaSAndroid Build Coastguard Worker void write_2d_color(VertexWriter* vb,
111*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
112*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
113*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
114*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
115*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
116*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
117*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
118*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
119*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
120*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasLocalCoords());
121*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kNone ||
122*c8dee2aaSAndroid Build Coastguard Worker spec.coverageMode() == CoverageMode::kWithColor);
123*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasVertexColors());
124*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
125*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasSubset());
126*c8dee2aaSAndroid Build Coastguard Worker // We don't assert that localQuad == nullptr, since it is possible for FillRectOp to
127*c8dee2aaSAndroid Build Coastguard Worker // accumulate local coords conservatively (paint not trivial), and then after analysis realize
128*c8dee2aaSAndroid Build Coastguard Worker // the processors don't need local coordinates.
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker bool wide = spec.colorType() == ColorType::kFloat;
131*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
132*c8dee2aaSAndroid Build Coastguard Worker // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
133*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f);
134*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
135*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
136*c8dee2aaSAndroid Build Coastguard Worker << VertexColor(color * coverage[i], wide);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), no explicit coverage, UV locals, no color, no geometry subset, no texture subset
141*c8dee2aaSAndroid Build Coastguard Worker // This represents opaque, non AA, textured rects
write_2d_uv(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)142*c8dee2aaSAndroid Build Coastguard Worker void write_2d_uv(VertexWriter* vb,
143*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
144*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
145*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
146*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
147*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
148*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
149*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
150*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
151*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
152*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
153*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kNone);
154*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasVertexColors());
155*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
156*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasSubset());
157*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
160*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
161*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
162*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
163*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), no explicit coverage, UV locals, vertex color, no geometry or texture subsets
168*c8dee2aaSAndroid Build Coastguard Worker // This represents transparent, non AA (or AA with cov. as alpha), textured rects
write_2d_color_uv(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)169*c8dee2aaSAndroid Build Coastguard Worker void write_2d_color_uv(VertexWriter* vb,
170*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
171*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
172*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
173*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
174*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
175*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
176*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
177*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
178*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
179*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
180*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kNone ||
181*c8dee2aaSAndroid Build Coastguard Worker spec.coverageMode() == CoverageMode::kWithColor);
182*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasVertexColors());
183*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
184*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasSubset());
185*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker bool wide = spec.colorType() == ColorType::kFloat;
188*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
189*c8dee2aaSAndroid Build Coastguard Worker // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
190*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f);
191*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
192*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
193*c8dee2aaSAndroid Build Coastguard Worker << VertexColor(color * coverage[i], wide)
194*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
195*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i);
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker }
198*c8dee2aaSAndroid Build Coastguard Worker
199*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), explicit coverage, UV locals, no color, no geometry subset, no texture subset
200*c8dee2aaSAndroid Build Coastguard Worker // This represents opaque, AA, textured rects
write_2d_cov_uv(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)201*c8dee2aaSAndroid Build Coastguard Worker void write_2d_cov_uv(VertexWriter* vb,
202*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
203*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
204*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
205*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
206*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
207*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
208*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
209*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
210*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
211*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
212*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kWithPosition);
213*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasVertexColors());
214*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
215*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasSubset());
216*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
217*c8dee2aaSAndroid Build Coastguard Worker
218*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
219*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
220*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
221*c8dee2aaSAndroid Build Coastguard Worker << coverage[i]
222*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
223*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i);
224*c8dee2aaSAndroid Build Coastguard Worker }
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker // NOTE: The three _strict specializations below match the non-strict uv functions above, except
228*c8dee2aaSAndroid Build Coastguard Worker // that they also write the UV subset. These are included to benefit SkiaRenderer, which must make
229*c8dee2aaSAndroid Build Coastguard Worker // use of both fast and strict constrained subsets. When testing _strict was not that common across
230*c8dee2aaSAndroid Build Coastguard Worker // GMS, SKPs, and SVGs but we have little visibility into actual SkiaRenderer statistics. If
231*c8dee2aaSAndroid Build Coastguard Worker // SkiaRenderer can avoid subsets more, these 3 functions should probably be removed for simplicity.
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), no explicit coverage, UV locals, no color, tex subset but no geometry subset
234*c8dee2aaSAndroid Build Coastguard Worker // This represents opaque, non AA, textured rects with strict uv sampling
write_2d_uv_strict(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)235*c8dee2aaSAndroid Build Coastguard Worker void write_2d_uv_strict(VertexWriter* vb,
236*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
237*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
238*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
239*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
240*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
241*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
242*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
243*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
244*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
245*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
246*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kNone);
247*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasVertexColors());
248*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
249*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasSubset());
250*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
251*c8dee2aaSAndroid Build Coastguard Worker
252*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
253*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
254*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
255*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
256*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i)
257*c8dee2aaSAndroid Build Coastguard Worker << texSubset;
258*c8dee2aaSAndroid Build Coastguard Worker }
259*c8dee2aaSAndroid Build Coastguard Worker }
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), no explicit coverage, UV locals, vertex color, tex subset but no geometry subset
262*c8dee2aaSAndroid Build Coastguard Worker // This represents transparent, non AA (or AA with cov. as alpha), textured rects with strict sample
write_2d_color_uv_strict(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)263*c8dee2aaSAndroid Build Coastguard Worker void write_2d_color_uv_strict(VertexWriter* vb,
264*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
265*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
266*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
267*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
268*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
269*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
270*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
271*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
272*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
273*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
274*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kNone ||
275*c8dee2aaSAndroid Build Coastguard Worker spec.coverageMode() == CoverageMode::kWithColor);
276*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasVertexColors());
277*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
278*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasSubset());
279*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
280*c8dee2aaSAndroid Build Coastguard Worker
281*c8dee2aaSAndroid Build Coastguard Worker bool wide = spec.colorType() == ColorType::kFloat;
282*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
283*c8dee2aaSAndroid Build Coastguard Worker // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
284*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f);
285*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
286*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
287*c8dee2aaSAndroid Build Coastguard Worker << VertexColor(color * coverage[i], wide)
288*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
289*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i)
290*c8dee2aaSAndroid Build Coastguard Worker << texSubset;
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker }
293*c8dee2aaSAndroid Build Coastguard Worker
294*c8dee2aaSAndroid Build Coastguard Worker // 2D (XY), explicit coverage, UV locals, no color, tex subset but no geometry subset
295*c8dee2aaSAndroid Build Coastguard Worker // This represents opaque, AA, textured rects with strict uv sampling
write_2d_cov_uv_strict(VertexWriter * vb,const VertexSpec & spec,const GrQuad * deviceQuad,const GrQuad * localQuad,const float coverage[4],const SkPMColor4f & color,const SkRect & geomSubset,const SkRect & texSubset)296*c8dee2aaSAndroid Build Coastguard Worker void write_2d_cov_uv_strict(VertexWriter* vb,
297*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
298*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* deviceQuad,
299*c8dee2aaSAndroid Build Coastguard Worker const GrQuad* localQuad,
300*c8dee2aaSAndroid Build Coastguard Worker const float coverage[4],
301*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
302*c8dee2aaSAndroid Build Coastguard Worker const SkRect& geomSubset,
303*c8dee2aaSAndroid Build Coastguard Worker const SkRect& texSubset) {
304*c8dee2aaSAndroid Build Coastguard Worker // Assert assumptions about VertexSpec
305*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
306*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
307*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.coverageMode() == CoverageMode::kWithPosition);
308*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasVertexColors());
309*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.requiresGeometrySubset());
310*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasSubset());
311*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad);
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
314*c8dee2aaSAndroid Build Coastguard Worker *vb << deviceQuad->x(i)
315*c8dee2aaSAndroid Build Coastguard Worker << deviceQuad->y(i)
316*c8dee2aaSAndroid Build Coastguard Worker << coverage[i]
317*c8dee2aaSAndroid Build Coastguard Worker << localQuad->x(i)
318*c8dee2aaSAndroid Build Coastguard Worker << localQuad->y(i)
319*c8dee2aaSAndroid Build Coastguard Worker << texSubset;
320*c8dee2aaSAndroid Build Coastguard Worker }
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
324*c8dee2aaSAndroid Build Coastguard Worker
CalcIndexBufferOption(GrAAType aa,int numQuads)325*c8dee2aaSAndroid Build Coastguard Worker IndexBufferOption CalcIndexBufferOption(GrAAType aa, int numQuads) {
326*c8dee2aaSAndroid Build Coastguard Worker if (aa == GrAAType::kCoverage) {
327*c8dee2aaSAndroid Build Coastguard Worker return IndexBufferOption::kPictureFramed;
328*c8dee2aaSAndroid Build Coastguard Worker } else if (numQuads > 1) {
329*c8dee2aaSAndroid Build Coastguard Worker return IndexBufferOption::kIndexedRects;
330*c8dee2aaSAndroid Build Coastguard Worker } else {
331*c8dee2aaSAndroid Build Coastguard Worker return IndexBufferOption::kTriStrips;
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker }
334*c8dee2aaSAndroid Build Coastguard Worker
335*c8dee2aaSAndroid Build Coastguard Worker // This is a more elaborate version of fitsInBytes() that allows "no color" for white
MinColorType(SkPMColor4f color)336*c8dee2aaSAndroid Build Coastguard Worker ColorType MinColorType(SkPMColor4f color) {
337*c8dee2aaSAndroid Build Coastguard Worker if (color == SK_PMColor4fWHITE) {
338*c8dee2aaSAndroid Build Coastguard Worker return ColorType::kNone;
339*c8dee2aaSAndroid Build Coastguard Worker } else {
340*c8dee2aaSAndroid Build Coastguard Worker return color.fitsInBytes() ? ColorType::kByte : ColorType::kFloat;
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker ////////////////// Tessellator Implementation
345*c8dee2aaSAndroid Build Coastguard Worker
GetWriteQuadProc(const VertexSpec & spec)346*c8dee2aaSAndroid Build Coastguard Worker Tessellator::WriteQuadProc Tessellator::GetWriteQuadProc(const VertexSpec& spec) {
347*c8dee2aaSAndroid Build Coastguard Worker // All specialized writing functions requires 2D geometry and no geometry subset. This is not
348*c8dee2aaSAndroid Build Coastguard Worker // the same as just checking device type vs. kRectilinear since non-AA general 2D quads do not
349*c8dee2aaSAndroid Build Coastguard Worker // require a geometry subset and could then go through a fast path.
350*c8dee2aaSAndroid Build Coastguard Worker if (spec.deviceQuadType() != GrQuad::Type::kPerspective && !spec.requiresGeometrySubset()) {
351*c8dee2aaSAndroid Build Coastguard Worker CoverageMode mode = spec.coverageMode();
352*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasVertexColors()) {
353*c8dee2aaSAndroid Build Coastguard Worker if (mode != CoverageMode::kWithPosition) {
354*c8dee2aaSAndroid Build Coastguard Worker // Vertex colors, but no explicit coverage
355*c8dee2aaSAndroid Build Coastguard Worker if (!spec.hasLocalCoords()) {
356*c8dee2aaSAndroid Build Coastguard Worker // Non-UV with vertex colors (possibly with coverage folded into alpha)
357*c8dee2aaSAndroid Build Coastguard Worker return write_2d_color;
358*c8dee2aaSAndroid Build Coastguard Worker } else if (spec.localQuadType() != GrQuad::Type::kPerspective) {
359*c8dee2aaSAndroid Build Coastguard Worker // UV locals with vertex colors (possibly with coverage-as-alpha)
360*c8dee2aaSAndroid Build Coastguard Worker return spec.hasSubset() ? write_2d_color_uv_strict : write_2d_color_uv;
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker }
363*c8dee2aaSAndroid Build Coastguard Worker // Else fall through; this is a spec that requires vertex colors and explicit coverage,
364*c8dee2aaSAndroid Build Coastguard Worker // which means it's anti-aliased and the FPs don't support coverage as alpha, or
365*c8dee2aaSAndroid Build Coastguard Worker // it uses 3D local coordinates.
366*c8dee2aaSAndroid Build Coastguard Worker } else if (spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective) {
367*c8dee2aaSAndroid Build Coastguard Worker if (mode == CoverageMode::kWithPosition) {
368*c8dee2aaSAndroid Build Coastguard Worker // UV locals with explicit coverage
369*c8dee2aaSAndroid Build Coastguard Worker return spec.hasSubset() ? write_2d_cov_uv_strict : write_2d_cov_uv;
370*c8dee2aaSAndroid Build Coastguard Worker } else {
371*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(mode == CoverageMode::kNone);
372*c8dee2aaSAndroid Build Coastguard Worker return spec.hasSubset() ? write_2d_uv_strict : write_2d_uv;
373*c8dee2aaSAndroid Build Coastguard Worker }
374*c8dee2aaSAndroid Build Coastguard Worker }
375*c8dee2aaSAndroid Build Coastguard Worker // Else fall through to generic vertex function; this is a spec that has no vertex colors
376*c8dee2aaSAndroid Build Coastguard Worker // and [no|uvr] local coords, which doesn't happen often enough to warrant specialization.
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker // Arbitrary spec hits the slow path
380*c8dee2aaSAndroid Build Coastguard Worker return write_quad_generic;
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker
Tessellator(const VertexSpec & spec,char * vertices)383*c8dee2aaSAndroid Build Coastguard Worker Tessellator::Tessellator(const VertexSpec& spec, char* vertices)
384*c8dee2aaSAndroid Build Coastguard Worker : fVertexSpec(spec)
385*c8dee2aaSAndroid Build Coastguard Worker , fVertexWriter{vertices}
386*c8dee2aaSAndroid Build Coastguard Worker , fWriteProc(Tessellator::GetWriteQuadProc(spec)) {}
387*c8dee2aaSAndroid Build Coastguard Worker
append(GrQuad * deviceQuad,GrQuad * localQuad,const SkPMColor4f & color,const SkRect & uvSubset,GrQuadAAFlags aaFlags)388*c8dee2aaSAndroid Build Coastguard Worker void Tessellator::append(GrQuad* deviceQuad, GrQuad* localQuad,
389*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color, const SkRect& uvSubset, GrQuadAAFlags aaFlags) {
390*c8dee2aaSAndroid Build Coastguard Worker // We allow Tessellator to be created with a null vertices pointer for convenience, but it is
391*c8dee2aaSAndroid Build Coastguard Worker // assumed it will never actually be used in those cases.
392*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertexWriter);
393*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(deviceQuad->quadType() <= fVertexSpec.deviceQuadType());
394*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(localQuad || !fVertexSpec.hasLocalCoords());
395*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fVertexSpec.hasLocalCoords() || localQuad->quadType() <= fVertexSpec.localQuadType());
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker static const float kFullCoverage[4] = {1.f, 1.f, 1.f, 1.f};
398*c8dee2aaSAndroid Build Coastguard Worker static const float kZeroCoverage[4] = {0.f, 0.f, 0.f, 0.f};
399*c8dee2aaSAndroid Build Coastguard Worker static const SkRect kIgnoredSubset = SkRect::MakeEmpty();
400*c8dee2aaSAndroid Build Coastguard Worker
401*c8dee2aaSAndroid Build Coastguard Worker if (fVertexSpec.usesCoverageAA()) {
402*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kWithColor ||
403*c8dee2aaSAndroid Build Coastguard Worker fVertexSpec.coverageMode() == CoverageMode::kWithPosition);
404*c8dee2aaSAndroid Build Coastguard Worker // Must calculate inner and outer quadrilaterals for the vertex coverage ramps, and possibly
405*c8dee2aaSAndroid Build Coastguard Worker // a geometry subset if corners are not right angles
406*c8dee2aaSAndroid Build Coastguard Worker SkRect geomSubset;
407*c8dee2aaSAndroid Build Coastguard Worker if (fVertexSpec.requiresGeometrySubset()) {
408*c8dee2aaSAndroid Build Coastguard Worker // Our GP code expects a 0.5 outset rect (coverage is computed as 0 at the values of
409*c8dee2aaSAndroid Build Coastguard Worker // the uniform). However, if we have quad edges that aren't supposed to be antialiased
410*c8dee2aaSAndroid Build Coastguard Worker // they may lie close to the bounds. So in that case we outset by an additional 0.5.
411*c8dee2aaSAndroid Build Coastguard Worker // This is a sort of backup clipping mechanism for cases where quad outsetting of nearly
412*c8dee2aaSAndroid Build Coastguard Worker // parallel edges produces long thin extrusions from the original geometry.
413*c8dee2aaSAndroid Build Coastguard Worker float outset = aaFlags == GrQuadAAFlags::kAll ? 0.5f : 1.f;
414*c8dee2aaSAndroid Build Coastguard Worker geomSubset = deviceQuad->bounds().makeOutset(outset, outset);
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker
417*c8dee2aaSAndroid Build Coastguard Worker if (aaFlags == GrQuadAAFlags::kNone) {
418*c8dee2aaSAndroid Build Coastguard Worker // Have to write the coverage AA vertex structure, but there's no math to be done for a
419*c8dee2aaSAndroid Build Coastguard Worker // non-aa quad batched into a coverage AA op.
420*c8dee2aaSAndroid Build Coastguard Worker fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
421*c8dee2aaSAndroid Build Coastguard Worker geomSubset, uvSubset);
422*c8dee2aaSAndroid Build Coastguard Worker // Since we pass the same corners in, the outer vertex structure will have 0 area and
423*c8dee2aaSAndroid Build Coastguard Worker // the coverage interpolation from 1 to 0 will not be visible.
424*c8dee2aaSAndroid Build Coastguard Worker fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
425*c8dee2aaSAndroid Build Coastguard Worker geomSubset, uvSubset);
426*c8dee2aaSAndroid Build Coastguard Worker } else {
427*c8dee2aaSAndroid Build Coastguard Worker // Reset the tessellation helper to match the current geometry
428*c8dee2aaSAndroid Build Coastguard Worker fAAHelper.reset(*deviceQuad, localQuad);
429*c8dee2aaSAndroid Build Coastguard Worker
430*c8dee2aaSAndroid Build Coastguard Worker // Edge inset/outset distance ordered LBTR, set to 0.5 for a half pixel if the AA flag
431*c8dee2aaSAndroid Build Coastguard Worker // is turned on, or 0.0 if the edge is not anti-aliased.
432*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> edgeDistances;
433*c8dee2aaSAndroid Build Coastguard Worker if (aaFlags == GrQuadAAFlags::kAll) {
434*c8dee2aaSAndroid Build Coastguard Worker edgeDistances = 0.5f;
435*c8dee2aaSAndroid Build Coastguard Worker } else {
436*c8dee2aaSAndroid Build Coastguard Worker edgeDistances = { (aaFlags & GrQuadAAFlags::kLeft) ? 0.5f : 0.f,
437*c8dee2aaSAndroid Build Coastguard Worker (aaFlags & GrQuadAAFlags::kBottom) ? 0.5f : 0.f,
438*c8dee2aaSAndroid Build Coastguard Worker (aaFlags & GrQuadAAFlags::kTop) ? 0.5f : 0.f,
439*c8dee2aaSAndroid Build Coastguard Worker (aaFlags & GrQuadAAFlags::kRight) ? 0.5f : 0.f };
440*c8dee2aaSAndroid Build Coastguard Worker }
441*c8dee2aaSAndroid Build Coastguard Worker
442*c8dee2aaSAndroid Build Coastguard Worker // Write inner vertices first
443*c8dee2aaSAndroid Build Coastguard Worker float coverage[4];
444*c8dee2aaSAndroid Build Coastguard Worker fAAHelper.inset(edgeDistances, deviceQuad, localQuad).store(coverage);
445*c8dee2aaSAndroid Build Coastguard Worker fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, coverage, color,
446*c8dee2aaSAndroid Build Coastguard Worker geomSubset, uvSubset);
447*c8dee2aaSAndroid Build Coastguard Worker
448*c8dee2aaSAndroid Build Coastguard Worker // Then outer vertices, which use 0.f for their coverage. If the inset was degenerate
449*c8dee2aaSAndroid Build Coastguard Worker // to a line (had all coverages < 1), tweak the outset distance so the outer frame's
450*c8dee2aaSAndroid Build Coastguard Worker // narrow axis reaches out to 2px, which gives better animation under translation.
451*c8dee2aaSAndroid Build Coastguard Worker const bool hairline = aaFlags == GrQuadAAFlags::kAll &&
452*c8dee2aaSAndroid Build Coastguard Worker coverage[0] < 1.f &&
453*c8dee2aaSAndroid Build Coastguard Worker coverage[1] < 1.f &&
454*c8dee2aaSAndroid Build Coastguard Worker coverage[2] < 1.f &&
455*c8dee2aaSAndroid Build Coastguard Worker coverage[3] < 1.f;
456*c8dee2aaSAndroid Build Coastguard Worker if (hairline) {
457*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> len = fAAHelper.getEdgeLengths();
458*c8dee2aaSAndroid Build Coastguard Worker // Using max guards us against trying to scale a degenerate triangle edge of 0 len
459*c8dee2aaSAndroid Build Coastguard Worker // up to 2px. The shuffles are so that edge 0's adjustment is based on the lengths
460*c8dee2aaSAndroid Build Coastguard Worker // of its connecting edges (1 and 2), and so forth.
461*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> maxWH = max(skvx::shuffle<1, 0, 3, 2>(len),
462*c8dee2aaSAndroid Build Coastguard Worker skvx::shuffle<2, 3, 0, 1>(len));
463*c8dee2aaSAndroid Build Coastguard Worker // wh + 2e' = 2, so e' = (2 - wh) / 2 => e' = e * (2 - wh). But if w or h > 1, then
464*c8dee2aaSAndroid Build Coastguard Worker // 2 - wh < 1 and represents the non-narrow axis so clamp to 1.
465*c8dee2aaSAndroid Build Coastguard Worker edgeDistances *= max(1.f, 2.f - maxWH);
466*c8dee2aaSAndroid Build Coastguard Worker }
467*c8dee2aaSAndroid Build Coastguard Worker fAAHelper.outset(edgeDistances, deviceQuad, localQuad);
468*c8dee2aaSAndroid Build Coastguard Worker fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
469*c8dee2aaSAndroid Build Coastguard Worker geomSubset, uvSubset);
470*c8dee2aaSAndroid Build Coastguard Worker }
471*c8dee2aaSAndroid Build Coastguard Worker } else {
472*c8dee2aaSAndroid Build Coastguard Worker // No outsetting needed, just write a single quad with full coverage
473*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kNone &&
474*c8dee2aaSAndroid Build Coastguard Worker !fVertexSpec.requiresGeometrySubset());
475*c8dee2aaSAndroid Build Coastguard Worker fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
476*c8dee2aaSAndroid Build Coastguard Worker kIgnoredSubset, uvSubset);
477*c8dee2aaSAndroid Build Coastguard Worker }
478*c8dee2aaSAndroid Build Coastguard Worker }
479*c8dee2aaSAndroid Build Coastguard Worker
GetIndexBuffer(GrMeshDrawTarget * target,IndexBufferOption indexBufferOption)480*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawTarget* target,
481*c8dee2aaSAndroid Build Coastguard Worker IndexBufferOption indexBufferOption) {
482*c8dee2aaSAndroid Build Coastguard Worker auto resourceProvider = target->resourceProvider();
483*c8dee2aaSAndroid Build Coastguard Worker
484*c8dee2aaSAndroid Build Coastguard Worker switch (indexBufferOption) {
485*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kPictureFramed: return resourceProvider->refAAQuadIndexBuffer();
486*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kIndexedRects: return resourceProvider->refNonAAQuadIndexBuffer();
487*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kTriStrips: // fall through
488*c8dee2aaSAndroid Build Coastguard Worker default: return nullptr;
489*c8dee2aaSAndroid Build Coastguard Worker }
490*c8dee2aaSAndroid Build Coastguard Worker }
491*c8dee2aaSAndroid Build Coastguard Worker
QuadLimit(IndexBufferOption option)492*c8dee2aaSAndroid Build Coastguard Worker int QuadLimit(IndexBufferOption option) {
493*c8dee2aaSAndroid Build Coastguard Worker switch (option) {
494*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kPictureFramed: return GrResourceProvider::MaxNumAAQuads();
495*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kIndexedRects: return GrResourceProvider::MaxNumNonAAQuads();
496*c8dee2aaSAndroid Build Coastguard Worker case IndexBufferOption::kTriStrips: return SK_MaxS32; // not limited by an indexBuffer
497*c8dee2aaSAndroid Build Coastguard Worker }
498*c8dee2aaSAndroid Build Coastguard Worker
499*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
500*c8dee2aaSAndroid Build Coastguard Worker }
501*c8dee2aaSAndroid Build Coastguard Worker
IssueDraw(const GrCaps & caps,GrOpsRenderPass * renderPass,const VertexSpec & spec,int runningQuadCount,int quadsInDraw,int maxVerts,int absVertBufferOffset)502*c8dee2aaSAndroid Build Coastguard Worker void IssueDraw(const GrCaps& caps, GrOpsRenderPass* renderPass, const VertexSpec& spec,
503*c8dee2aaSAndroid Build Coastguard Worker int runningQuadCount, int quadsInDraw, int maxVerts, int absVertBufferOffset) {
504*c8dee2aaSAndroid Build Coastguard Worker if (spec.indexBufferOption() == IndexBufferOption::kTriStrips) {
505*c8dee2aaSAndroid Build Coastguard Worker int offset = absVertBufferOffset +
506*c8dee2aaSAndroid Build Coastguard Worker runningQuadCount * GrResourceProvider::NumVertsPerNonAAQuad();
507*c8dee2aaSAndroid Build Coastguard Worker renderPass->draw(4, offset);
508*c8dee2aaSAndroid Build Coastguard Worker return;
509*c8dee2aaSAndroid Build Coastguard Worker }
510*c8dee2aaSAndroid Build Coastguard Worker
511*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.indexBufferOption() == IndexBufferOption::kPictureFramed ||
512*c8dee2aaSAndroid Build Coastguard Worker spec.indexBufferOption() == IndexBufferOption::kIndexedRects);
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker int maxNumQuads, numIndicesPerQuad, numVertsPerQuad;
515*c8dee2aaSAndroid Build Coastguard Worker
516*c8dee2aaSAndroid Build Coastguard Worker if (spec.indexBufferOption() == IndexBufferOption::kPictureFramed) {
517*c8dee2aaSAndroid Build Coastguard Worker // AA uses 8 vertices and 30 indices per quad, basically nested rectangles
518*c8dee2aaSAndroid Build Coastguard Worker maxNumQuads = GrResourceProvider::MaxNumAAQuads();
519*c8dee2aaSAndroid Build Coastguard Worker numIndicesPerQuad = GrResourceProvider::NumIndicesPerAAQuad();
520*c8dee2aaSAndroid Build Coastguard Worker numVertsPerQuad = GrResourceProvider::NumVertsPerAAQuad();
521*c8dee2aaSAndroid Build Coastguard Worker } else {
522*c8dee2aaSAndroid Build Coastguard Worker // Non-AA uses 4 vertices and 6 indices per quad
523*c8dee2aaSAndroid Build Coastguard Worker maxNumQuads = GrResourceProvider::MaxNumNonAAQuads();
524*c8dee2aaSAndroid Build Coastguard Worker numIndicesPerQuad = GrResourceProvider::NumIndicesPerNonAAQuad();
525*c8dee2aaSAndroid Build Coastguard Worker numVertsPerQuad = GrResourceProvider::NumVertsPerNonAAQuad();
526*c8dee2aaSAndroid Build Coastguard Worker }
527*c8dee2aaSAndroid Build Coastguard Worker
528*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(runningQuadCount + quadsInDraw <= maxNumQuads);
529*c8dee2aaSAndroid Build Coastguard Worker
530*c8dee2aaSAndroid Build Coastguard Worker if (caps.avoidLargeIndexBufferDraws()) {
531*c8dee2aaSAndroid Build Coastguard Worker // When we need to avoid large index buffer draws we modify the base vertex of the draw
532*c8dee2aaSAndroid Build Coastguard Worker // which, in GL, requires rebinding all vertex attrib arrays, so a base index is generally
533*c8dee2aaSAndroid Build Coastguard Worker // preferred.
534*c8dee2aaSAndroid Build Coastguard Worker int offset = absVertBufferOffset + runningQuadCount * numVertsPerQuad;
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker renderPass->drawIndexPattern(numIndicesPerQuad, quadsInDraw, maxNumQuads, numVertsPerQuad,
537*c8dee2aaSAndroid Build Coastguard Worker offset);
538*c8dee2aaSAndroid Build Coastguard Worker } else {
539*c8dee2aaSAndroid Build Coastguard Worker int baseIndex = runningQuadCount * numIndicesPerQuad;
540*c8dee2aaSAndroid Build Coastguard Worker int numIndicesToDraw = quadsInDraw * numIndicesPerQuad;
541*c8dee2aaSAndroid Build Coastguard Worker
542*c8dee2aaSAndroid Build Coastguard Worker int minVertex = runningQuadCount * numVertsPerQuad;
543*c8dee2aaSAndroid Build Coastguard Worker int maxVertex = (runningQuadCount + quadsInDraw) * numVertsPerQuad - 1; // inclusive
544*c8dee2aaSAndroid Build Coastguard Worker
545*c8dee2aaSAndroid Build Coastguard Worker renderPass->drawIndexed(numIndicesToDraw, baseIndex, minVertex, maxVertex,
546*c8dee2aaSAndroid Build Coastguard Worker absVertBufferOffset);
547*c8dee2aaSAndroid Build Coastguard Worker }
548*c8dee2aaSAndroid Build Coastguard Worker }
549*c8dee2aaSAndroid Build Coastguard Worker
550*c8dee2aaSAndroid Build Coastguard Worker ////////////////// VertexSpec Implementation
551*c8dee2aaSAndroid Build Coastguard Worker
deviceDimensionality() const552*c8dee2aaSAndroid Build Coastguard Worker int VertexSpec::deviceDimensionality() const {
553*c8dee2aaSAndroid Build Coastguard Worker return this->deviceQuadType() == GrQuad::Type::kPerspective ? 3 : 2;
554*c8dee2aaSAndroid Build Coastguard Worker }
555*c8dee2aaSAndroid Build Coastguard Worker
localDimensionality() const556*c8dee2aaSAndroid Build Coastguard Worker int VertexSpec::localDimensionality() const {
557*c8dee2aaSAndroid Build Coastguard Worker return fHasLocalCoords ? (this->localQuadType() == GrQuad::Type::kPerspective ? 3 : 2) : 0;
558*c8dee2aaSAndroid Build Coastguard Worker }
559*c8dee2aaSAndroid Build Coastguard Worker
coverageMode() const560*c8dee2aaSAndroid Build Coastguard Worker CoverageMode VertexSpec::coverageMode() const {
561*c8dee2aaSAndroid Build Coastguard Worker if (this->usesCoverageAA()) {
562*c8dee2aaSAndroid Build Coastguard Worker if (this->compatibleWithCoverageAsAlpha() && this->hasVertexColors() &&
563*c8dee2aaSAndroid Build Coastguard Worker !this->requiresGeometrySubset()) {
564*c8dee2aaSAndroid Build Coastguard Worker // Using a geometric subset acts as a second source of coverage and folding
565*c8dee2aaSAndroid Build Coastguard Worker // the original coverage into color makes it impossible to apply the color's
566*c8dee2aaSAndroid Build Coastguard Worker // alpha to the geometric subset's coverage when the original shape is clipped.
567*c8dee2aaSAndroid Build Coastguard Worker return CoverageMode::kWithColor;
568*c8dee2aaSAndroid Build Coastguard Worker } else {
569*c8dee2aaSAndroid Build Coastguard Worker return CoverageMode::kWithPosition;
570*c8dee2aaSAndroid Build Coastguard Worker }
571*c8dee2aaSAndroid Build Coastguard Worker } else {
572*c8dee2aaSAndroid Build Coastguard Worker return CoverageMode::kNone;
573*c8dee2aaSAndroid Build Coastguard Worker }
574*c8dee2aaSAndroid Build Coastguard Worker }
575*c8dee2aaSAndroid Build Coastguard Worker
576*c8dee2aaSAndroid Build Coastguard Worker // This needs to stay in sync w/ QuadPerEdgeAAGeometryProcessor::initializeAttrs
vertexSize() const577*c8dee2aaSAndroid Build Coastguard Worker size_t VertexSpec::vertexSize() const {
578*c8dee2aaSAndroid Build Coastguard Worker bool needsPerspective = (this->deviceDimensionality() == 3);
579*c8dee2aaSAndroid Build Coastguard Worker CoverageMode coverageMode = this->coverageMode();
580*c8dee2aaSAndroid Build Coastguard Worker
581*c8dee2aaSAndroid Build Coastguard Worker size_t count = 0;
582*c8dee2aaSAndroid Build Coastguard Worker
583*c8dee2aaSAndroid Build Coastguard Worker if (coverageMode == CoverageMode::kWithPosition) {
584*c8dee2aaSAndroid Build Coastguard Worker if (needsPerspective) {
585*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
586*c8dee2aaSAndroid Build Coastguard Worker } else {
587*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType) +
588*c8dee2aaSAndroid Build Coastguard Worker GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
589*c8dee2aaSAndroid Build Coastguard Worker }
590*c8dee2aaSAndroid Build Coastguard Worker } else {
591*c8dee2aaSAndroid Build Coastguard Worker if (needsPerspective) {
592*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat3_GrVertexAttribType);
593*c8dee2aaSAndroid Build Coastguard Worker } else {
594*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType);
595*c8dee2aaSAndroid Build Coastguard Worker }
596*c8dee2aaSAndroid Build Coastguard Worker }
597*c8dee2aaSAndroid Build Coastguard Worker
598*c8dee2aaSAndroid Build Coastguard Worker if (this->requiresGeometrySubset()) {
599*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
600*c8dee2aaSAndroid Build Coastguard Worker }
601*c8dee2aaSAndroid Build Coastguard Worker
602*c8dee2aaSAndroid Build Coastguard Worker count += this->localDimensionality() * GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
603*c8dee2aaSAndroid Build Coastguard Worker
604*c8dee2aaSAndroid Build Coastguard Worker if (ColorType::kByte == this->colorType()) {
605*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kUByte4_norm_GrVertexAttribType);
606*c8dee2aaSAndroid Build Coastguard Worker } else if (ColorType::kFloat == this->colorType()) {
607*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
608*c8dee2aaSAndroid Build Coastguard Worker }
609*c8dee2aaSAndroid Build Coastguard Worker
610*c8dee2aaSAndroid Build Coastguard Worker if (this->hasSubset()) {
611*c8dee2aaSAndroid Build Coastguard Worker count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
612*c8dee2aaSAndroid Build Coastguard Worker }
613*c8dee2aaSAndroid Build Coastguard Worker
614*c8dee2aaSAndroid Build Coastguard Worker return count;
615*c8dee2aaSAndroid Build Coastguard Worker }
616*c8dee2aaSAndroid Build Coastguard Worker
617*c8dee2aaSAndroid Build Coastguard Worker ////////////////// Geometry Processor Implementation
618*c8dee2aaSAndroid Build Coastguard Worker
619*c8dee2aaSAndroid Build Coastguard Worker class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
620*c8dee2aaSAndroid Build Coastguard Worker public:
Make(SkArenaAlloc * arena,const VertexSpec & spec)621*c8dee2aaSAndroid Build Coastguard Worker static GrGeometryProcessor* Make(SkArenaAlloc* arena, const VertexSpec& spec) {
622*c8dee2aaSAndroid Build Coastguard Worker return arena->make([&](void* ptr) {
623*c8dee2aaSAndroid Build Coastguard Worker return new (ptr) QuadPerEdgeAAGeometryProcessor(spec);
624*c8dee2aaSAndroid Build Coastguard Worker });
625*c8dee2aaSAndroid Build Coastguard Worker }
626*c8dee2aaSAndroid Build Coastguard Worker
Make(SkArenaAlloc * arena,const VertexSpec & vertexSpec,const GrShaderCaps & caps,const GrBackendFormat & backendFormat,GrSamplerState samplerState,const skgpu::Swizzle & swizzle,sk_sp<GrColorSpaceXform> textureColorSpaceXform,Saturate saturate)627*c8dee2aaSAndroid Build Coastguard Worker static GrGeometryProcessor* Make(SkArenaAlloc* arena,
628*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& vertexSpec,
629*c8dee2aaSAndroid Build Coastguard Worker const GrShaderCaps& caps,
630*c8dee2aaSAndroid Build Coastguard Worker const GrBackendFormat& backendFormat,
631*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState samplerState,
632*c8dee2aaSAndroid Build Coastguard Worker const skgpu::Swizzle& swizzle,
633*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrColorSpaceXform> textureColorSpaceXform,
634*c8dee2aaSAndroid Build Coastguard Worker Saturate saturate) {
635*c8dee2aaSAndroid Build Coastguard Worker return arena->make([&](void* ptr) {
636*c8dee2aaSAndroid Build Coastguard Worker return new (ptr) QuadPerEdgeAAGeometryProcessor(
637*c8dee2aaSAndroid Build Coastguard Worker vertexSpec, caps, backendFormat, samplerState, swizzle,
638*c8dee2aaSAndroid Build Coastguard Worker std::move(textureColorSpaceXform), saturate);
639*c8dee2aaSAndroid Build Coastguard Worker });
640*c8dee2aaSAndroid Build Coastguard Worker }
641*c8dee2aaSAndroid Build Coastguard Worker
name() const642*c8dee2aaSAndroid Build Coastguard Worker const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; }
643*c8dee2aaSAndroid Build Coastguard Worker
addToKey(const GrShaderCaps &,KeyBuilder * b) const644*c8dee2aaSAndroid Build Coastguard Worker void addToKey(const GrShaderCaps&, KeyBuilder* b) const override {
645*c8dee2aaSAndroid Build Coastguard Worker // texturing, device-dimensions are single bit flags
646*c8dee2aaSAndroid Build Coastguard Worker b->addBool(fTexSubset.isInitialized(), "subset");
647*c8dee2aaSAndroid Build Coastguard Worker b->addBool(fSampler.isInitialized(), "textured");
648*c8dee2aaSAndroid Build Coastguard Worker b->addBool(fNeedsPerspective, "perspective");
649*c8dee2aaSAndroid Build Coastguard Worker b->addBool((fSaturate == Saturate::kYes), "saturate");
650*c8dee2aaSAndroid Build Coastguard Worker
651*c8dee2aaSAndroid Build Coastguard Worker b->addBool(fLocalCoord.isInitialized(), "hasLocalCoords");
652*c8dee2aaSAndroid Build Coastguard Worker if (fLocalCoord.isInitialized()) {
653*c8dee2aaSAndroid Build Coastguard Worker // 2D (0) or 3D (1)
654*c8dee2aaSAndroid Build Coastguard Worker b->addBits(1, (kFloat3_GrVertexAttribType == fLocalCoord.cpuType()), "localCoordsType");
655*c8dee2aaSAndroid Build Coastguard Worker }
656*c8dee2aaSAndroid Build Coastguard Worker b->addBool(fColor.isInitialized(), "hasColor");
657*c8dee2aaSAndroid Build Coastguard Worker if (fColor.isInitialized()) {
658*c8dee2aaSAndroid Build Coastguard Worker // bytes (0) or floats (1)
659*c8dee2aaSAndroid Build Coastguard Worker b->addBits(1, (kFloat4_GrVertexAttribType == fColor.cpuType()), "colorType");
660*c8dee2aaSAndroid Build Coastguard Worker }
661*c8dee2aaSAndroid Build Coastguard Worker // and coverage mode, 00 for none, 01 for withposition, 10 for withcolor, 11 for
662*c8dee2aaSAndroid Build Coastguard Worker // position+geomsubset
663*c8dee2aaSAndroid Build Coastguard Worker uint32_t coverageKey = 0;
664*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fGeomSubset.isInitialized() || fCoverageMode == CoverageMode::kWithPosition);
665*c8dee2aaSAndroid Build Coastguard Worker if (fCoverageMode != CoverageMode::kNone) {
666*c8dee2aaSAndroid Build Coastguard Worker coverageKey = fGeomSubset.isInitialized()
667*c8dee2aaSAndroid Build Coastguard Worker ? 0x3
668*c8dee2aaSAndroid Build Coastguard Worker : (CoverageMode::kWithPosition == fCoverageMode ? 0x1 : 0x2);
669*c8dee2aaSAndroid Build Coastguard Worker }
670*c8dee2aaSAndroid Build Coastguard Worker b->addBits(2, coverageKey, "coverageMode");
671*c8dee2aaSAndroid Build Coastguard Worker
672*c8dee2aaSAndroid Build Coastguard Worker b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()), "colorSpaceXform");
673*c8dee2aaSAndroid Build Coastguard Worker }
674*c8dee2aaSAndroid Build Coastguard Worker
makeProgramImpl(const GrShaderCaps &) const675*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
676*c8dee2aaSAndroid Build Coastguard Worker class Impl : public ProgramImpl {
677*c8dee2aaSAndroid Build Coastguard Worker public:
678*c8dee2aaSAndroid Build Coastguard Worker void setData(const GrGLSLProgramDataManager& pdman,
679*c8dee2aaSAndroid Build Coastguard Worker const GrShaderCaps&,
680*c8dee2aaSAndroid Build Coastguard Worker const GrGeometryProcessor& geomProc) override {
681*c8dee2aaSAndroid Build Coastguard Worker const auto& gp = geomProc.cast<QuadPerEdgeAAGeometryProcessor>();
682*c8dee2aaSAndroid Build Coastguard Worker fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get());
683*c8dee2aaSAndroid Build Coastguard Worker }
684*c8dee2aaSAndroid Build Coastguard Worker
685*c8dee2aaSAndroid Build Coastguard Worker private:
686*c8dee2aaSAndroid Build Coastguard Worker void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
687*c8dee2aaSAndroid Build Coastguard Worker using Interpolation = GrGLSLVaryingHandler::Interpolation;
688*c8dee2aaSAndroid Build Coastguard Worker
689*c8dee2aaSAndroid Build Coastguard Worker const auto& gp = args.fGeomProc.cast<QuadPerEdgeAAGeometryProcessor>();
690*c8dee2aaSAndroid Build Coastguard Worker fTextureColorSpaceXformHelper.emitCode(args.fUniformHandler,
691*c8dee2aaSAndroid Build Coastguard Worker gp.fTextureColorSpaceXform.get());
692*c8dee2aaSAndroid Build Coastguard Worker
693*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->emitAttributes(gp);
694*c8dee2aaSAndroid Build Coastguard Worker
695*c8dee2aaSAndroid Build Coastguard Worker if (gp.fCoverageMode == CoverageMode::kWithPosition) {
696*c8dee2aaSAndroid Build Coastguard Worker // Strip last channel from the vertex attribute to remove coverage and get the
697*c8dee2aaSAndroid Build Coastguard Worker // actual position
698*c8dee2aaSAndroid Build Coastguard Worker if (gp.fNeedsPerspective) {
699*c8dee2aaSAndroid Build Coastguard Worker args.fVertBuilder->codeAppendf("float3 position = %s.xyz;",
700*c8dee2aaSAndroid Build Coastguard Worker gp.fPosition.name());
701*c8dee2aaSAndroid Build Coastguard Worker } else {
702*c8dee2aaSAndroid Build Coastguard Worker args.fVertBuilder->codeAppendf("float2 position = %s.xy;",
703*c8dee2aaSAndroid Build Coastguard Worker gp.fPosition.name());
704*c8dee2aaSAndroid Build Coastguard Worker }
705*c8dee2aaSAndroid Build Coastguard Worker gpArgs->fPositionVar = {"position",
706*c8dee2aaSAndroid Build Coastguard Worker gp.fNeedsPerspective ? SkSLType::kFloat3
707*c8dee2aaSAndroid Build Coastguard Worker : SkSLType::kFloat2,
708*c8dee2aaSAndroid Build Coastguard Worker GrShaderVar::TypeModifier::None};
709*c8dee2aaSAndroid Build Coastguard Worker } else {
710*c8dee2aaSAndroid Build Coastguard Worker // No coverage to eliminate
711*c8dee2aaSAndroid Build Coastguard Worker gpArgs->fPositionVar = gp.fPosition.asShaderVar();
712*c8dee2aaSAndroid Build Coastguard Worker }
713*c8dee2aaSAndroid Build Coastguard Worker
714*c8dee2aaSAndroid Build Coastguard Worker // This attribute will be uninitialized if earlier FP analysis determined no
715*c8dee2aaSAndroid Build Coastguard Worker // local coordinates are needed (and this will not include the inline texture
716*c8dee2aaSAndroid Build Coastguard Worker // fetch this GP does before invoking FPs).
717*c8dee2aaSAndroid Build Coastguard Worker gpArgs->fLocalCoordVar = gp.fLocalCoord.asShaderVar();
718*c8dee2aaSAndroid Build Coastguard Worker
719*c8dee2aaSAndroid Build Coastguard Worker // Solid color before any texturing gets modulated in
720*c8dee2aaSAndroid Build Coastguard Worker const char* blendDst;
721*c8dee2aaSAndroid Build Coastguard Worker if (gp.fColor.isInitialized()) {
722*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(gp.fCoverageMode != CoverageMode::kWithColor || !gp.fNeedsPerspective);
723*c8dee2aaSAndroid Build Coastguard Worker // The color cannot be flat if the varying coverage has been modulated into it
724*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
725*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addPassThroughAttribute(
726*c8dee2aaSAndroid Build Coastguard Worker gp.fColor.asShaderVar(),
727*c8dee2aaSAndroid Build Coastguard Worker args.fOutputColor,
728*c8dee2aaSAndroid Build Coastguard Worker gp.fCoverageMode == CoverageMode::kWithColor
729*c8dee2aaSAndroid Build Coastguard Worker ? Interpolation::kInterpolated
730*c8dee2aaSAndroid Build Coastguard Worker : Interpolation::kCanBeFlat);
731*c8dee2aaSAndroid Build Coastguard Worker blendDst = args.fOutputColor;
732*c8dee2aaSAndroid Build Coastguard Worker } else {
733*c8dee2aaSAndroid Build Coastguard Worker // Output color must be initialized to something
734*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("half4 %s = half4(1);", args.fOutputColor);
735*c8dee2aaSAndroid Build Coastguard Worker blendDst = nullptr;
736*c8dee2aaSAndroid Build Coastguard Worker }
737*c8dee2aaSAndroid Build Coastguard Worker
738*c8dee2aaSAndroid Build Coastguard Worker // If there is a texture, must also handle texture coordinates and reading from
739*c8dee2aaSAndroid Build Coastguard Worker // the texture in the fragment shader before continuing to fragment processors.
740*c8dee2aaSAndroid Build Coastguard Worker if (gp.fSampler.isInitialized()) {
741*c8dee2aaSAndroid Build Coastguard Worker // Texture coordinates clamped by the subset on the fragment shader; if the GP
742*c8dee2aaSAndroid Build Coastguard Worker // has a texture, it's guaranteed to have local coordinates
743*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend("float2 texCoord;");
744*c8dee2aaSAndroid Build Coastguard Worker if (gp.fLocalCoord.cpuType() == kFloat3_GrVertexAttribType) {
745*c8dee2aaSAndroid Build Coastguard Worker // Can't do a pass through since we need to perform perspective division
746*c8dee2aaSAndroid Build Coastguard Worker GrGLSLVarying v(gp.fLocalCoord.gpuType());
747*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addVarying(gp.fLocalCoord.name(), &v);
748*c8dee2aaSAndroid Build Coastguard Worker args.fVertBuilder->codeAppendf("%s = %s;",
749*c8dee2aaSAndroid Build Coastguard Worker v.vsOut(), gp.fLocalCoord.name());
750*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("texCoord = %s.xy / %s.z;",
751*c8dee2aaSAndroid Build Coastguard Worker v.fsIn(), v.fsIn());
752*c8dee2aaSAndroid Build Coastguard Worker } else {
753*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord.asShaderVar(),
754*c8dee2aaSAndroid Build Coastguard Worker "texCoord");
755*c8dee2aaSAndroid Build Coastguard Worker }
756*c8dee2aaSAndroid Build Coastguard Worker
757*c8dee2aaSAndroid Build Coastguard Worker // Clamp the now 2D localCoordName variable by the subset if it is provided
758*c8dee2aaSAndroid Build Coastguard Worker if (gp.fTexSubset.isInitialized()) {
759*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend("float4 subset;");
760*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addPassThroughAttribute(gp.fTexSubset.asShaderVar(),
761*c8dee2aaSAndroid Build Coastguard Worker "subset",
762*c8dee2aaSAndroid Build Coastguard Worker Interpolation::kCanBeFlat);
763*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend(
764*c8dee2aaSAndroid Build Coastguard Worker "texCoord = clamp(texCoord, subset.LT, subset.RB);");
765*c8dee2aaSAndroid Build Coastguard Worker }
766*c8dee2aaSAndroid Build Coastguard Worker
767*c8dee2aaSAndroid Build Coastguard Worker // Now modulate the starting output color by the texture lookup
768*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf(
769*c8dee2aaSAndroid Build Coastguard Worker "%s = %s(",
770*c8dee2aaSAndroid Build Coastguard Worker args.fOutputColor,
771*c8dee2aaSAndroid Build Coastguard Worker (gp.fSaturate == Saturate::kYes) ? "saturate" : "");
772*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->appendTextureLookupAndBlend(
773*c8dee2aaSAndroid Build Coastguard Worker blendDst, SkBlendMode::kModulate, args.fTexSamplers[0],
774*c8dee2aaSAndroid Build Coastguard Worker "texCoord", &fTextureColorSpaceXformHelper);
775*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend(");");
776*c8dee2aaSAndroid Build Coastguard Worker } else {
777*c8dee2aaSAndroid Build Coastguard Worker // Saturate is only intended for use with a proxy to account for the fact
778*c8dee2aaSAndroid Build Coastguard Worker // that TextureOp skips SkPaint conversion, which normally handles this.
779*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(gp.fSaturate == Saturate::kNo);
780*c8dee2aaSAndroid Build Coastguard Worker }
781*c8dee2aaSAndroid Build Coastguard Worker
782*c8dee2aaSAndroid Build Coastguard Worker // And lastly, output the coverage calculation code
783*c8dee2aaSAndroid Build Coastguard Worker if (gp.fCoverageMode == CoverageMode::kWithPosition) {
784*c8dee2aaSAndroid Build Coastguard Worker GrGLSLVarying coverage(SkSLType::kFloat);
785*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addVarying("coverage", &coverage);
786*c8dee2aaSAndroid Build Coastguard Worker if (gp.fNeedsPerspective) {
787*c8dee2aaSAndroid Build Coastguard Worker // Multiply by "W" in the vertex shader, then by 1/w (sk_FragCoord.w) in
788*c8dee2aaSAndroid Build Coastguard Worker // the fragment shader to get screen-space linear coverage.
789*c8dee2aaSAndroid Build Coastguard Worker args.fVertBuilder->codeAppendf("%s = %s.w * %s.z;",
790*c8dee2aaSAndroid Build Coastguard Worker coverage.vsOut(), gp.fPosition.name(),
791*c8dee2aaSAndroid Build Coastguard Worker gp.fPosition.name());
792*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("float coverage = %s * sk_FragCoord.w;",
793*c8dee2aaSAndroid Build Coastguard Worker coverage.fsIn());
794*c8dee2aaSAndroid Build Coastguard Worker } else {
795*c8dee2aaSAndroid Build Coastguard Worker args.fVertBuilder->codeAppendf("%s = %s;",
796*c8dee2aaSAndroid Build Coastguard Worker coverage.vsOut(), gp.fCoverage.name());
797*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("float coverage = %s;", coverage.fsIn());
798*c8dee2aaSAndroid Build Coastguard Worker }
799*c8dee2aaSAndroid Build Coastguard Worker
800*c8dee2aaSAndroid Build Coastguard Worker if (gp.fGeomSubset.isInitialized()) {
801*c8dee2aaSAndroid Build Coastguard Worker // Calculate distance from sk_FragCoord to the 4 edges of the subset
802*c8dee2aaSAndroid Build Coastguard Worker // and clamp them to (0, 1). Use the minimum of these and the original
803*c8dee2aaSAndroid Build Coastguard Worker // coverage. This only has to be done in the exterior triangles, the
804*c8dee2aaSAndroid Build Coastguard Worker // interior of the quad geometry can never be clipped by the subset box.
805*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend("float4 geoSubset;");
806*c8dee2aaSAndroid Build Coastguard Worker args.fVaryingHandler->addPassThroughAttribute(gp.fGeomSubset.asShaderVar(),
807*c8dee2aaSAndroid Build Coastguard Worker "geoSubset",
808*c8dee2aaSAndroid Build Coastguard Worker Interpolation::kCanBeFlat);
809*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppend(
810*c8dee2aaSAndroid Build Coastguard Worker // This is lifted from GrFragmentProcessor::Rect.
811*c8dee2aaSAndroid Build Coastguard Worker "float4 dists4 = saturate(float4(1, 1, -1, -1) * "
812*c8dee2aaSAndroid Build Coastguard Worker "(sk_FragCoord.xyxy - geoSubset));"
813*c8dee2aaSAndroid Build Coastguard Worker "float2 dists2 = dists4.xy + dists4.zw - 1;"
814*c8dee2aaSAndroid Build Coastguard Worker "coverage = min(coverage, dists2.x * dists2.y);");
815*c8dee2aaSAndroid Build Coastguard Worker }
816*c8dee2aaSAndroid Build Coastguard Worker
817*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("half4 %s = half4(coverage);",
818*c8dee2aaSAndroid Build Coastguard Worker args.fOutputCoverage);
819*c8dee2aaSAndroid Build Coastguard Worker } else {
820*c8dee2aaSAndroid Build Coastguard Worker // Set coverage to 1, since it's either non-AA or the coverage was already
821*c8dee2aaSAndroid Build Coastguard Worker // folded into the output color
822*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!gp.fGeomSubset.isInitialized());
823*c8dee2aaSAndroid Build Coastguard Worker args.fFragBuilder->codeAppendf("const half4 %s = half4(1);",
824*c8dee2aaSAndroid Build Coastguard Worker args.fOutputCoverage);
825*c8dee2aaSAndroid Build Coastguard Worker }
826*c8dee2aaSAndroid Build Coastguard Worker }
827*c8dee2aaSAndroid Build Coastguard Worker
828*c8dee2aaSAndroid Build Coastguard Worker GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper;
829*c8dee2aaSAndroid Build Coastguard Worker };
830*c8dee2aaSAndroid Build Coastguard Worker
831*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<Impl>();
832*c8dee2aaSAndroid Build Coastguard Worker }
833*c8dee2aaSAndroid Build Coastguard Worker
834*c8dee2aaSAndroid Build Coastguard Worker private:
835*c8dee2aaSAndroid Build Coastguard Worker using Saturate = skgpu::ganesh::TextureOp::Saturate;
836*c8dee2aaSAndroid Build Coastguard Worker
QuadPerEdgeAAGeometryProcessor(const VertexSpec & spec)837*c8dee2aaSAndroid Build Coastguard Worker QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec)
838*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
839*c8dee2aaSAndroid Build Coastguard Worker , fTextureColorSpaceXform(nullptr) {
840*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!spec.hasSubset());
841*c8dee2aaSAndroid Build Coastguard Worker this->initializeAttrs(spec);
842*c8dee2aaSAndroid Build Coastguard Worker this->setTextureSamplerCnt(0);
843*c8dee2aaSAndroid Build Coastguard Worker }
844*c8dee2aaSAndroid Build Coastguard Worker
QuadPerEdgeAAGeometryProcessor(const VertexSpec & spec,const GrShaderCaps & caps,const GrBackendFormat & backendFormat,GrSamplerState samplerState,const skgpu::Swizzle & swizzle,sk_sp<GrColorSpaceXform> textureColorSpaceXform,Saturate saturate)845*c8dee2aaSAndroid Build Coastguard Worker QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec,
846*c8dee2aaSAndroid Build Coastguard Worker const GrShaderCaps& caps,
847*c8dee2aaSAndroid Build Coastguard Worker const GrBackendFormat& backendFormat,
848*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState samplerState,
849*c8dee2aaSAndroid Build Coastguard Worker const skgpu::Swizzle& swizzle,
850*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrColorSpaceXform> textureColorSpaceXform,
851*c8dee2aaSAndroid Build Coastguard Worker Saturate saturate)
852*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
853*c8dee2aaSAndroid Build Coastguard Worker , fSaturate(saturate)
854*c8dee2aaSAndroid Build Coastguard Worker , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
855*c8dee2aaSAndroid Build Coastguard Worker , fSampler(samplerState, backendFormat, swizzle) {
856*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(spec.hasLocalCoords());
857*c8dee2aaSAndroid Build Coastguard Worker this->initializeAttrs(spec);
858*c8dee2aaSAndroid Build Coastguard Worker this->setTextureSamplerCnt(1);
859*c8dee2aaSAndroid Build Coastguard Worker }
860*c8dee2aaSAndroid Build Coastguard Worker
861*c8dee2aaSAndroid Build Coastguard Worker // This needs to stay in sync w/ VertexSpec::vertexSize
initializeAttrs(const VertexSpec & spec)862*c8dee2aaSAndroid Build Coastguard Worker void initializeAttrs(const VertexSpec& spec) {
863*c8dee2aaSAndroid Build Coastguard Worker fNeedsPerspective = spec.deviceDimensionality() == 3;
864*c8dee2aaSAndroid Build Coastguard Worker fCoverageMode = spec.coverageMode();
865*c8dee2aaSAndroid Build Coastguard Worker
866*c8dee2aaSAndroid Build Coastguard Worker if (fCoverageMode == CoverageMode::kWithPosition) {
867*c8dee2aaSAndroid Build Coastguard Worker if (fNeedsPerspective) {
868*c8dee2aaSAndroid Build Coastguard Worker fPosition = {"positionWithCoverage", kFloat4_GrVertexAttribType, SkSLType::kFloat4};
869*c8dee2aaSAndroid Build Coastguard Worker } else {
870*c8dee2aaSAndroid Build Coastguard Worker fPosition = {"position", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
871*c8dee2aaSAndroid Build Coastguard Worker fCoverage = {"coverage", kFloat_GrVertexAttribType, SkSLType::kFloat};
872*c8dee2aaSAndroid Build Coastguard Worker }
873*c8dee2aaSAndroid Build Coastguard Worker } else {
874*c8dee2aaSAndroid Build Coastguard Worker if (fNeedsPerspective) {
875*c8dee2aaSAndroid Build Coastguard Worker fPosition = {"position", kFloat3_GrVertexAttribType, SkSLType::kFloat3};
876*c8dee2aaSAndroid Build Coastguard Worker } else {
877*c8dee2aaSAndroid Build Coastguard Worker fPosition = {"position", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
878*c8dee2aaSAndroid Build Coastguard Worker }
879*c8dee2aaSAndroid Build Coastguard Worker }
880*c8dee2aaSAndroid Build Coastguard Worker
881*c8dee2aaSAndroid Build Coastguard Worker // Need a geometry subset when the quads are AA and not rectilinear, since their AA
882*c8dee2aaSAndroid Build Coastguard Worker // outsetting can go beyond a half pixel.
883*c8dee2aaSAndroid Build Coastguard Worker if (spec.requiresGeometrySubset()) {
884*c8dee2aaSAndroid Build Coastguard Worker fGeomSubset = {"geomSubset", kFloat4_GrVertexAttribType, SkSLType::kFloat4};
885*c8dee2aaSAndroid Build Coastguard Worker }
886*c8dee2aaSAndroid Build Coastguard Worker
887*c8dee2aaSAndroid Build Coastguard Worker int localDim = spec.localDimensionality();
888*c8dee2aaSAndroid Build Coastguard Worker if (localDim == 3) {
889*c8dee2aaSAndroid Build Coastguard Worker fLocalCoord = {"localCoord", kFloat3_GrVertexAttribType, SkSLType::kFloat3};
890*c8dee2aaSAndroid Build Coastguard Worker } else if (localDim == 2) {
891*c8dee2aaSAndroid Build Coastguard Worker fLocalCoord = {"localCoord", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
892*c8dee2aaSAndroid Build Coastguard Worker } // else localDim == 0 and attribute remains uninitialized
893*c8dee2aaSAndroid Build Coastguard Worker
894*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasVertexColors()) {
895*c8dee2aaSAndroid Build Coastguard Worker fColor = MakeColorAttribute("color", ColorType::kFloat == spec.colorType());
896*c8dee2aaSAndroid Build Coastguard Worker }
897*c8dee2aaSAndroid Build Coastguard Worker
898*c8dee2aaSAndroid Build Coastguard Worker if (spec.hasSubset()) {
899*c8dee2aaSAndroid Build Coastguard Worker fTexSubset = {"texSubset", kFloat4_GrVertexAttribType, SkSLType::kFloat4};
900*c8dee2aaSAndroid Build Coastguard Worker }
901*c8dee2aaSAndroid Build Coastguard Worker
902*c8dee2aaSAndroid Build Coastguard Worker this->setVertexAttributesWithImplicitOffsets(&fPosition, 6);
903*c8dee2aaSAndroid Build Coastguard Worker }
904*c8dee2aaSAndroid Build Coastguard Worker
onTextureSampler(int) const905*c8dee2aaSAndroid Build Coastguard Worker const TextureSampler& onTextureSampler(int) const override { return fSampler; }
906*c8dee2aaSAndroid Build Coastguard Worker
907*c8dee2aaSAndroid Build Coastguard Worker Attribute fPosition; // May contain coverage as last channel
908*c8dee2aaSAndroid Build Coastguard Worker Attribute fCoverage; // Used for non-perspective position to avoid Intel Metal issues
909*c8dee2aaSAndroid Build Coastguard Worker Attribute fColor; // May have coverage modulated in if the FPs support it
910*c8dee2aaSAndroid Build Coastguard Worker Attribute fLocalCoord;
911*c8dee2aaSAndroid Build Coastguard Worker Attribute fGeomSubset; // Screen-space bounding box on geometry+aa outset
912*c8dee2aaSAndroid Build Coastguard Worker Attribute fTexSubset; // Texture-space bounding box on local coords
913*c8dee2aaSAndroid Build Coastguard Worker
914*c8dee2aaSAndroid Build Coastguard Worker // The positions attribute may have coverage built into it, so float3 is an ambiguous type
915*c8dee2aaSAndroid Build Coastguard Worker // and may mean 2d with coverage, or 3d with no coverage
916*c8dee2aaSAndroid Build Coastguard Worker bool fNeedsPerspective;
917*c8dee2aaSAndroid Build Coastguard Worker // Should saturate() be called on the color? Only relevant when created with a texture.
918*c8dee2aaSAndroid Build Coastguard Worker Saturate fSaturate = Saturate::kNo;
919*c8dee2aaSAndroid Build Coastguard Worker CoverageMode fCoverageMode;
920*c8dee2aaSAndroid Build Coastguard Worker
921*c8dee2aaSAndroid Build Coastguard Worker // Color space will be null and fSampler.isInitialized() returns false when the GP is configured
922*c8dee2aaSAndroid Build Coastguard Worker // to skip texturing.
923*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
924*c8dee2aaSAndroid Build Coastguard Worker TextureSampler fSampler;
925*c8dee2aaSAndroid Build Coastguard Worker
926*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GrGeometryProcessor;
927*c8dee2aaSAndroid Build Coastguard Worker };
928*c8dee2aaSAndroid Build Coastguard Worker
MakeProcessor(SkArenaAlloc * arena,const VertexSpec & spec)929*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* MakeProcessor(SkArenaAlloc* arena, const VertexSpec& spec) {
930*c8dee2aaSAndroid Build Coastguard Worker return QuadPerEdgeAAGeometryProcessor::Make(arena, spec);
931*c8dee2aaSAndroid Build Coastguard Worker }
932*c8dee2aaSAndroid Build Coastguard Worker
MakeTexturedProcessor(SkArenaAlloc * arena,const VertexSpec & spec,const GrShaderCaps & caps,const GrBackendFormat & backendFormat,GrSamplerState samplerState,const skgpu::Swizzle & swizzle,sk_sp<GrColorSpaceXform> textureColorSpaceXform,Saturate saturate)933*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* MakeTexturedProcessor(SkArenaAlloc* arena,
934*c8dee2aaSAndroid Build Coastguard Worker const VertexSpec& spec,
935*c8dee2aaSAndroid Build Coastguard Worker const GrShaderCaps& caps,
936*c8dee2aaSAndroid Build Coastguard Worker const GrBackendFormat& backendFormat,
937*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState samplerState,
938*c8dee2aaSAndroid Build Coastguard Worker const skgpu::Swizzle& swizzle,
939*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrColorSpaceXform> textureColorSpaceXform,
940*c8dee2aaSAndroid Build Coastguard Worker Saturate saturate) {
941*c8dee2aaSAndroid Build Coastguard Worker return QuadPerEdgeAAGeometryProcessor::Make(arena, spec, caps, backendFormat, samplerState,
942*c8dee2aaSAndroid Build Coastguard Worker swizzle, std::move(textureColorSpaceXform),
943*c8dee2aaSAndroid Build Coastguard Worker saturate);
944*c8dee2aaSAndroid Build Coastguard Worker }
945*c8dee2aaSAndroid Build Coastguard Worker
946*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh::QuadPerEdgeAA
947