blob: da70bf661c5399a3313c8d7c975b8b50159aa657 [file] [log] [blame]
Michael Ludwig460eb5e2018-10-29 11:09:29 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Michael Ludwigfd4f4df2019-05-29 09:51:09 -04008#include "src/gpu/ops/GrQuadPerEdgeAA.h"
9
Michael Ludwigfb7ba522019-10-29 15:33:34 -040010#include "include/private/SkVx.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/SkGr.h"
Michael Ludwigfb7ba522019-10-29 15:33:34 -040012#include "src/gpu/geometry/GrQuadUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
14#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
15#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
16#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
17#include "src/gpu/glsl/GrGLSLVarying.h"
18#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Michael Ludwig460eb5e2018-10-29 11:09:29 -040019
Michael Ludwigf995c052018-11-26 15:24:29 -050020
Michael Ludwig460eb5e2018-10-29 11:09:29 -040021namespace {
22
Michael Ludwig73dbea62019-11-19 14:55:36 -050023// Generic WriteQuadProc that can handle any VertexSpec. It writes the 4 vertices in triangle strip
24// order, although the data per-vertex is dependent on the VertexSpec.
25static void write_quad_generic(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -050026 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -050027 const float coverage[4], const SkPMColor4f& color,
28 const SkRect& geomDomain, const SkRect& texDomain) {
Michael Ludwig93aeba02018-12-21 09:50:31 -050029 static constexpr auto If = GrVertexWriter::If<float>;
Michael Ludwig704d5402019-11-25 09:43:37 -050030
31 SkASSERT(!spec.hasLocalCoords() || localQuad);
32
Michael Ludwig73dbea62019-11-19 14:55:36 -050033 GrQuadPerEdgeAA::CoverageMode mode = spec.coverageMode();
Michael Ludwig553e9a92018-11-29 12:38:35 -050034 for (int i = 0; i < 4; ++i) {
Michael Ludwig93aeba02018-12-21 09:50:31 -050035 // save position, this is a float2 or float3 or float4 depending on the combination of
36 // perspective and coverage mode.
Michael Ludwig704d5402019-11-25 09:43:37 -050037 vb->write(deviceQuad->x(i), deviceQuad->y(i),
38 If(spec.deviceQuadType() == GrQuad::Type::kPerspective, deviceQuad->w(i)),
Robert Phillips29f38542019-10-16 09:20:25 -040039 If(mode == GrQuadPerEdgeAA::CoverageMode::kWithPosition, coverage[i]));
Michael Ludwig4921dc32018-12-03 14:57:29 +000040
Michael Ludwig93aeba02018-12-21 09:50:31 -050041 // save color
42 if (spec.hasVertexColors()) {
Brian Salomon1d835422019-03-13 16:11:44 -040043 bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
Michael Ludwige6266a22019-03-07 11:24:32 -050044 vb->write(GrVertexColor(
Michael Ludwig73dbea62019-11-19 14:55:36 -050045 color * (mode == GrQuadPerEdgeAA::CoverageMode::kWithColor ? coverage[i] : 1.f),
Robert Phillips29f38542019-10-16 09:20:25 -040046 wide));
Michael Ludwig93aeba02018-12-21 09:50:31 -050047 }
48
49 // save local position
50 if (spec.hasLocalCoords()) {
Michael Ludwig704d5402019-11-25 09:43:37 -050051 vb->write(localQuad->x(i), localQuad->y(i),
52 If(spec.localQuadType() == GrQuad::Type::kPerspective, localQuad->w(i)));
Michael Ludwig93aeba02018-12-21 09:50:31 -050053 }
54
Michael Ludwigdcfbe322019-04-01 14:55:54 -040055 // save the geometry domain
56 if (spec.requiresGeometryDomain()) {
57 vb->write(geomDomain);
58 }
59
60 // save the texture domain
Michael Ludwig93aeba02018-12-21 09:50:31 -050061 if (spec.hasDomain()) {
Michael Ludwigdcfbe322019-04-01 14:55:54 -040062 vb->write(texDomain);
Michael Ludwig93aeba02018-12-21 09:50:31 -050063 }
64 }
65}
66
Michael Ludwig73dbea62019-11-19 14:55:36 -050067// Specialized WriteQuadProcs for particular VertexSpecs that show up frequently (determined
68// experimentally through recorded GMs, SKPs, and SVGs, as well as SkiaRenderer's usage patterns):
69
70// 2D (XY), no explicit coverage, vertex color, no locals, no geometry domain, no texture domain
71// This represents simple, solid color or shader, non-AA (or AA with cov. as alpha) rects.
72static void write_2d_color(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -050073 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -050074 const float coverage[4], const SkPMColor4f& color,
75 const SkRect& geomDomain, const SkRect& texDomain) {
76 // Assert assumptions about VertexSpec
77 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
78 SkASSERT(!spec.hasLocalCoords());
79 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kNone ||
80 spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor);
81 SkASSERT(spec.hasVertexColors());
82 SkASSERT(!spec.requiresGeometryDomain());
83 SkASSERT(!spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -050084 // We don't assert that localQuad == nullptr, since it is possible for GrFillRectOp to
85 // accumulate local coords conservatively (paint not trivial), and then after analysis realize
86 // the processors don't need local coordinates.
Michael Ludwig73dbea62019-11-19 14:55:36 -050087
88 bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
89 for (int i = 0; i < 4; ++i) {
90 // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
91 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
92 coverage[i] == 1.f);
Michael Ludwig704d5402019-11-25 09:43:37 -050093 vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide));
Michael Ludwig73dbea62019-11-19 14:55:36 -050094 }
95}
96
97// 2D (XY), no explicit coverage, UV locals, no color, no geometry domain, no texture domain
98// This represents opaque, non AA, textured rects
99static void write_2d_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500100 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500101 const float coverage[4], const SkPMColor4f& color,
102 const SkRect& geomDomain, const SkRect& texDomain) {
103 // Assert assumptions about VertexSpec
104 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
105 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
106 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kNone);
107 SkASSERT(!spec.hasVertexColors());
108 SkASSERT(!spec.requiresGeometryDomain());
109 SkASSERT(!spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500110 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500111
112 for (int i = 0; i < 4; ++i) {
Michael Ludwig704d5402019-11-25 09:43:37 -0500113 vb->write(deviceQuad->x(i), deviceQuad->y(i), localQuad->x(i), localQuad->y(i));
Michael Ludwig73dbea62019-11-19 14:55:36 -0500114 }
115}
116
117// 2D (XY), no explicit coverage, UV locals, vertex color, no geometry or texture domains
118// This represents transparent, non AA (or AA with cov. as alpha), textured rects
119static void write_2d_color_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500120 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500121 const float coverage[4], const SkPMColor4f& color,
122 const SkRect& geomDomain, const SkRect& texDomain) {
123 // Assert assumptions about VertexSpec
124 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
125 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
126 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kNone ||
127 spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor);
128 SkASSERT(spec.hasVertexColors());
129 SkASSERT(!spec.requiresGeometryDomain());
130 SkASSERT(!spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500131 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500132
133 bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
134 for (int i = 0; i < 4; ++i) {
135 // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
136 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
137 coverage[i] == 1.f);
Michael Ludwig704d5402019-11-25 09:43:37 -0500138 vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide),
139 localQuad->x(i), localQuad->y(i));
Michael Ludwig73dbea62019-11-19 14:55:36 -0500140 }
141}
142
143// 2D (XY), explicit coverage, UV locals, no color, no geometry domain, no texture domain
144// This represents opaque, AA, textured rects
145static void write_2d_cov_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500146 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500147 const float coverage[4], const SkPMColor4f& color,
148 const SkRect& geomDomain, const SkRect& texDomain) {
149 // Assert assumptions about VertexSpec
150 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
151 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
152 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithPosition);
153 SkASSERT(!spec.hasVertexColors());
154 SkASSERT(!spec.requiresGeometryDomain());
155 SkASSERT(!spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500156 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500157
158 for (int i = 0; i < 4; ++i) {
Michael Ludwig704d5402019-11-25 09:43:37 -0500159 vb->write(deviceQuad->x(i), deviceQuad->y(i), coverage[i],
160 localQuad->x(i), localQuad->y(i));
Michael Ludwig73dbea62019-11-19 14:55:36 -0500161 }
162}
163
164// NOTE: The three _strict specializations below match the non-strict uv functions above, except
165// that they also write the UV domain. These are included to benefit SkiaRenderer, which must make
166// use of both fast and strict constrained domains. When testing _strict was not that common across
167// GMS, SKPs, and SVGs but we have little visibility into actual SkiaRenderer statistics. If
168// SkiaRenderer can avoid domains more, these 3 functions should probably be removed for simplicity.
169
170// 2D (XY), no explicit coverage, UV locals, no color, tex domain but no geometry domain
171// This represents opaque, non AA, textured rects with strict uv sampling
172static void write_2d_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500173 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500174 const float coverage[4], const SkPMColor4f& color,
175 const SkRect& geomDomain, const SkRect& texDomain) {
176 // Assert assumptions about VertexSpec
177 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
178 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
179 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kNone);
180 SkASSERT(!spec.hasVertexColors());
181 SkASSERT(!spec.requiresGeometryDomain());
182 SkASSERT(spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500183 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500184
185 for (int i = 0; i < 4; ++i) {
Michael Ludwig704d5402019-11-25 09:43:37 -0500186 vb->write(deviceQuad->x(i), deviceQuad->y(i), localQuad->x(i), localQuad->y(i), texDomain);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500187 }
188}
189
190// 2D (XY), no explicit coverage, UV locals, vertex color, tex domain but no geometry domain
191// This represents transparent, non AA (or AA with cov. as alpha), textured rects with strict sample
192static void write_2d_color_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500193 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500194 const float coverage[4], const SkPMColor4f& color,
195 const SkRect& geomDomain, const SkRect& texDomain) {
196 // Assert assumptions about VertexSpec
197 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
198 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
199 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kNone ||
200 spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor);
201 SkASSERT(spec.hasVertexColors());
202 SkASSERT(!spec.requiresGeometryDomain());
203 SkASSERT(spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500204 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500205
206 bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
207 for (int i = 0; i < 4; ++i) {
208 // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
209 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
210 coverage[i] == 1.f);
Michael Ludwig704d5402019-11-25 09:43:37 -0500211 vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide),
212 localQuad->x(i), localQuad->y(i), texDomain);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500213 }
214}
215
216// 2D (XY), explicit coverage, UV locals, no color, tex domain but no geometry domain
217// This represents opaque, AA, textured rects with strict uv sampling
218static void write_2d_cov_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
Michael Ludwig704d5402019-11-25 09:43:37 -0500219 const GrQuad* deviceQuad, const GrQuad* localQuad,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500220 const float coverage[4], const SkPMColor4f& color,
221 const SkRect& geomDomain, const SkRect& texDomain) {
222 // Assert assumptions about VertexSpec
223 SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective);
224 SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective);
225 SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithPosition);
226 SkASSERT(!spec.hasVertexColors());
227 SkASSERT(!spec.requiresGeometryDomain());
228 SkASSERT(spec.hasDomain());
Michael Ludwig704d5402019-11-25 09:43:37 -0500229 SkASSERT(localQuad);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500230
231 for (int i = 0; i < 4; ++i) {
Michael Ludwig704d5402019-11-25 09:43:37 -0500232 vb->write(deviceQuad->x(i), deviceQuad->y(i), coverage[i],
233 localQuad->x(i), localQuad->y(i), texDomain);
Michael Ludwig73dbea62019-11-19 14:55:36 -0500234 }
235}
236
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400237} // anonymous namespace
238
Michael Ludwigc182b942018-11-16 10:27:51 -0500239namespace GrQuadPerEdgeAA {
240
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400241IndexBufferOption CalcIndexBufferOption(GrAAType aa, int numQuads) {
242 if (aa == GrAAType::kCoverage) {
243 return IndexBufferOption::kPictureFramed;
244 } else if (numQuads > 1) {
245 return IndexBufferOption::kIndexedRects;
246 } else {
247 return IndexBufferOption::kTriStrips;
248 }
249}
250
Brian Osman8fa7ab42019-03-18 10:22:42 -0400251// This is a more elaborate version of SkPMColor4fNeedsWideColor that allows "no color" for white
252ColorType MinColorType(SkPMColor4f color, GrClampType clampType, const GrCaps& caps) {
Brian Salomon1d835422019-03-13 16:11:44 -0400253 if (color == SK_PMColor4fWHITE) {
254 return ColorType::kNone;
Brian Salomon1d835422019-03-13 16:11:44 -0400255 } else {
Brian Osman8fa7ab42019-03-18 10:22:42 -0400256 return SkPMColor4fNeedsWideColor(color, clampType, caps) ? ColorType::kHalf
257 : ColorType::kByte;
Brian Salomon1d835422019-03-13 16:11:44 -0400258 }
259}
260
Michael Ludwig73dbea62019-11-19 14:55:36 -0500261////////////////// Tessellator Implementation
Michael Ludwigc182b942018-11-16 10:27:51 -0500262
Michael Ludwig73dbea62019-11-19 14:55:36 -0500263Tessellator::WriteQuadProc Tessellator::GetWriteQuadProc(const VertexSpec& spec) {
264 // All specialized writing functions requires 2D geometry and no geometry domain. This is not
265 // the same as just checking device type vs. kRectilinear since non-AA general 2D quads do not
266 // require a geometry domain and could then go through a fast path.
267 if (spec.deviceQuadType() != GrQuad::Type::kPerspective && !spec.requiresGeometryDomain()) {
268 CoverageMode mode = spec.coverageMode();
269 if (spec.hasVertexColors()) {
270 if (mode != CoverageMode::kWithPosition) {
271 // Vertex colors, but no explicit coverage
272 if (!spec.hasLocalCoords()) {
273 // Non-UV with vertex colors (possibly with coverage folded into alpha)
274 return write_2d_color;
275 } else if (spec.localQuadType() != GrQuad::Type::kPerspective) {
276 // UV locals with vertex colors (possibly with coverage-as-alpha)
277 return spec.hasDomain() ? write_2d_color_uv_strict : write_2d_color_uv;
278 }
279 }
280 // Else fall through; this is a spec that requires vertex colors and explicit coverage,
281 // which means it's anti-aliased and the FPs don't support coverage as alpha, or
282 // it uses 3D local coordinates.
283 } else if (spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective) {
284 if (mode == CoverageMode::kWithPosition) {
285 // UV locals with explicit coverage
286 return spec.hasDomain() ? write_2d_cov_uv_strict : write_2d_cov_uv;
287 } else {
288 SkASSERT(mode == CoverageMode::kNone);
289 return spec.hasDomain() ? write_2d_uv_strict : write_2d_uv;
290 }
291 }
292 // Else fall through to generic vertex function; this is a spec that has no vertex colors
293 // and [no|uvr] local coords, which doesn't happen often enough to warrant specialization.
294 }
Michael Ludwig41f395d2019-05-23 13:59:45 -0400295
Michael Ludwig73dbea62019-11-19 14:55:36 -0500296 // Arbitrary spec hits the slow path
297 return write_quad_generic;
298}
299
Michael Ludwig189c9802019-11-21 11:21:12 -0500300Tessellator::Tessellator(const VertexSpec& spec, char* vertices)
Michael Ludwig73dbea62019-11-19 14:55:36 -0500301 : fVertexSpec(spec)
Michael Ludwig189c9802019-11-21 11:21:12 -0500302 , fVertexWriter{vertices}
Michael Ludwig73dbea62019-11-19 14:55:36 -0500303 , fWriteProc(Tessellator::GetWriteQuadProc(spec)) {}
304
Michael Ludwig704d5402019-11-25 09:43:37 -0500305void Tessellator::append(GrQuad* deviceQuad, GrQuad* localQuad,
Michael Ludwig189c9802019-11-21 11:21:12 -0500306 const SkPMColor4f& color, const SkRect& uvDomain, GrQuadAAFlags aaFlags) {
307 // We allow Tessellator to be created with a null vertices pointer for convenience, but it is
308 // assumed it will never actually be used in those cases.
309 SkASSERT(fVertexWriter.fPtr);
Michael Ludwig704d5402019-11-25 09:43:37 -0500310 SkASSERT(deviceQuad->quadType() <= fVertexSpec.deviceQuadType());
311 SkASSERT(localQuad || !fVertexSpec.hasLocalCoords());
312 SkASSERT(!fVertexSpec.hasLocalCoords() || localQuad->quadType() <= fVertexSpec.localQuadType());
Michael Ludwig73dbea62019-11-19 14:55:36 -0500313
314 static const float kFullCoverage[4] = {1.f, 1.f, 1.f, 1.f};
315 static const float kZeroCoverage[4] = {0.f, 0.f, 0.f, 0.f};
316 static const SkRect kIgnoredDomain = SkRect::MakeEmpty();
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400317
Michael Ludwig73dbea62019-11-19 14:55:36 -0500318 if (fVertexSpec.usesCoverageAA()) {
319 SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kWithColor ||
320 fVertexSpec.coverageMode() == CoverageMode::kWithPosition);
Michael Ludwigfb7ba522019-10-29 15:33:34 -0400321 // Must calculate inner and outer quadrilaterals for the vertex coverage ramps, and possibly
Michael Ludwig73dbea62019-11-19 14:55:36 -0500322 // a geometry domain if corners are not right angles
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400323 SkRect geomDomain;
Michael Ludwig73dbea62019-11-19 14:55:36 -0500324 if (fVertexSpec.requiresGeometryDomain()) {
Michael Ludwig704d5402019-11-25 09:43:37 -0500325 geomDomain = deviceQuad->bounds();
Michael Ludwigfb7ba522019-10-29 15:33:34 -0400326 geomDomain.outset(0.5f, 0.5f); // account for AA expansion
Michael Ludwige6266a22019-03-07 11:24:32 -0500327 }
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400328
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500329 if (aaFlags == GrQuadAAFlags::kNone) {
330 // Have to write the coverage AA vertex structure, but there's no math to be done for a
331 // non-aa quad batched into a coverage AA op.
Michael Ludwig189c9802019-11-21 11:21:12 -0500332 fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500333 geomDomain, uvDomain);
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500334 // Since we pass the same corners in, the outer vertex structure will have 0 area and
335 // the coverage interpolation from 1 to 0 will not be visible.
Michael Ludwig189c9802019-11-21 11:21:12 -0500336 fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500337 geomDomain, uvDomain);
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500338 } else {
Michael Ludwig73dbea62019-11-19 14:55:36 -0500339 // Reset the tessellation helper to match the current geometry
Michael Ludwig704d5402019-11-25 09:43:37 -0500340 fAAHelper.reset(*deviceQuad, localQuad);
Michael Ludwigfb7ba522019-10-29 15:33:34 -0400341
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500342 // Edge inset/outset distance ordered LBTR, set to 0.5 for a half pixel if the AA flag
343 // is turned on, or 0.0 if the edge is not anti-aliased.
344 skvx::Vec<4, float> edgeDistances;
345 if (aaFlags == GrQuadAAFlags::kAll) {
346 edgeDistances = 0.5f;
347 } else {
348 edgeDistances = { (aaFlags & GrQuadAAFlags::kLeft) ? 0.5f : 0.f,
349 (aaFlags & GrQuadAAFlags::kBottom) ? 0.5f : 0.f,
350 (aaFlags & GrQuadAAFlags::kTop) ? 0.5f : 0.f,
351 (aaFlags & GrQuadAAFlags::kRight) ? 0.5f : 0.f };
352 }
Michael Ludwigfb7ba522019-10-29 15:33:34 -0400353
Michael Ludwig73dbea62019-11-19 14:55:36 -0500354 // Write inner vertices first
355 float coverage[4];
Michael Ludwig704d5402019-11-25 09:43:37 -0500356 fAAHelper.inset(edgeDistances, deviceQuad, localQuad).store(coverage);
357 fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, coverage, color,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500358 geomDomain, uvDomain);
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500359
360 // Then outer vertices, which use 0.f for their coverage
Michael Ludwig704d5402019-11-25 09:43:37 -0500361 fAAHelper.outset(edgeDistances, deviceQuad, localQuad);
362 fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500363 geomDomain, uvDomain);
Michael Ludwigd84dd4b2019-11-05 12:03:12 -0500364 }
Michael Ludwig93aeba02018-12-21 09:50:31 -0500365 } else {
366 // No outsetting needed, just write a single quad with full coverage
Michael Ludwig73dbea62019-11-19 14:55:36 -0500367 SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kNone &&
368 !fVertexSpec.requiresGeometryDomain());
Michael Ludwig189c9802019-11-21 11:21:12 -0500369 fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
Michael Ludwig73dbea62019-11-19 14:55:36 -0500370 kIgnoredDomain, uvDomain);
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400371 }
372}
Michael Ludwig20e909e2018-10-30 10:43:57 -0400373
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400374sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawOp::Target* target,
375 IndexBufferOption indexBufferOption) {
Robert Phillipsee08d522019-10-28 16:34:44 -0400376 auto resourceProvider = target->resourceProvider();
377
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400378 switch (indexBufferOption) {
379 case IndexBufferOption::kPictureFramed: return resourceProvider->refAAQuadIndexBuffer();
380 case IndexBufferOption::kIndexedRects: return resourceProvider->refNonAAQuadIndexBuffer();
381 case IndexBufferOption::kTriStrips: // fall through
382 default: return nullptr;
383 }
384}
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400385
Robert Phillips438d9862019-11-14 12:46:05 -0500386int QuadLimit(IndexBufferOption option) {
387 switch (option) {
388 case IndexBufferOption::kPictureFramed: return GrResourceProvider::MaxNumAAQuads();
389 case IndexBufferOption::kIndexedRects: return GrResourceProvider::MaxNumNonAAQuads();
390 case IndexBufferOption::kTriStrips: return SK_MaxS32; // not limited by an indexBuffer
391 }
392
393 SkUNREACHABLE;
394}
Michael Ludwig93aeba02018-12-21 09:50:31 -0500395
Robert Phillips2f05a482019-11-25 09:54:43 -0500396void ConfigureMesh(const GrCaps& caps, GrMesh* mesh, const VertexSpec& spec,
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400397 int runningQuadCount, int quadsInDraw, int maxVerts,
398 sk_sp<const GrBuffer> vertexBuffer,
399 sk_sp<const GrBuffer> indexBuffer, int absVertBufferOffset) {
400 SkASSERT(vertexBuffer);
Robert Phillipsc554dcf2019-10-28 11:43:55 -0400401
Robert Phillipscea290f2019-11-06 11:21:03 -0500402 mesh->setPrimitiveType(spec.primitiveType());
403
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400404 if (spec.indexBufferOption() == IndexBufferOption::kTriStrips) {
405 SkASSERT(!indexBuffer);
Michael Ludwig93aeba02018-12-21 09:50:31 -0500406
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400407 mesh->setNonIndexedNonInstanced(4);
408 int offset = absVertBufferOffset +
409 runningQuadCount * GrResourceProvider::NumVertsPerNonAAQuad();
410 mesh->setVertexData(std::move(vertexBuffer), offset);
411 return;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500412 }
413
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400414 SkASSERT(spec.indexBufferOption() == IndexBufferOption::kPictureFramed ||
415 spec.indexBufferOption() == IndexBufferOption::kIndexedRects);
416 SkASSERT(indexBuffer);
417
Robert Phillips2f05a482019-11-25 09:54:43 -0500418 int maxNumQuads, numIndicesPerQuad, numVertsPerQuad;
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400419
420 if (spec.indexBufferOption() == IndexBufferOption::kPictureFramed) {
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400421 // AA uses 8 vertices and 30 indices per quad, basically nested rectangles
Robert Phillips2f05a482019-11-25 09:54:43 -0500422 maxNumQuads = GrResourceProvider::MaxNumAAQuads();
423 numIndicesPerQuad = GrResourceProvider::NumIndicesPerAAQuad();
424 numVertsPerQuad = GrResourceProvider::NumVertsPerAAQuad();
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400425 } else {
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400426 // Non-AA uses 4 vertices and 6 indices per quad
Robert Phillips2f05a482019-11-25 09:54:43 -0500427 maxNumQuads = GrResourceProvider::MaxNumNonAAQuads();
428 numIndicesPerQuad = GrResourceProvider::NumIndicesPerNonAAQuad();
429 numVertsPerQuad = GrResourceProvider::NumVertsPerNonAAQuad();
Robert Phillipsfd0c3b52019-11-01 08:44:42 -0400430 }
431
Robert Phillips2f05a482019-11-25 09:54:43 -0500432 SkASSERT(runningQuadCount + quadsInDraw <= maxNumQuads);
433
434 if (caps.avoidLargeIndexBufferDraws()) {
435 // When we need to avoid large index buffer draws we modify the base vertex of the draw
436 // which, in GL, requires rebinding all vertex attrib arrays, so a base index is generally
437 // preferred.
438 int offset = absVertBufferOffset + runningQuadCount * numVertsPerQuad;
439
440 mesh->setIndexedPatterned(std::move(indexBuffer), numIndicesPerQuad,
441 numVertsPerQuad, quadsInDraw, maxNumQuads);
442 mesh->setVertexData(std::move(vertexBuffer), offset);
443 } else {
444 int baseIndex = runningQuadCount * numIndicesPerQuad;
445 int numIndicesToDraw = quadsInDraw * numIndicesPerQuad;
446
447 int minVertex = runningQuadCount * numVertsPerQuad;
448 int maxVertex = (runningQuadCount + quadsInDraw) * numVertsPerQuad;
449
450 mesh->setIndexed(std::move(indexBuffer), numIndicesToDraw,
451 baseIndex, minVertex, maxVertex, GrPrimitiveRestart::kNo);
452 mesh->setVertexData(std::move(vertexBuffer), absVertBufferOffset);
453 }
Michael Ludwig93aeba02018-12-21 09:50:31 -0500454}
455
Michael Ludwigc182b942018-11-16 10:27:51 -0500456////////////////// VertexSpec Implementation
Michael Ludwig20e909e2018-10-30 10:43:57 -0400457
Michael Ludwigc182b942018-11-16 10:27:51 -0500458int VertexSpec::deviceDimensionality() const {
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400459 return this->deviceQuadType() == GrQuad::Type::kPerspective ? 3 : 2;
Michael Ludwigc182b942018-11-16 10:27:51 -0500460}
461
462int VertexSpec::localDimensionality() const {
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400463 return fHasLocalCoords ? (this->localQuadType() == GrQuad::Type::kPerspective ? 3 : 2) : 0;
Michael Ludwigc182b942018-11-16 10:27:51 -0500464}
465
Robert Phillips29f38542019-10-16 09:20:25 -0400466CoverageMode VertexSpec::coverageMode() const {
467 if (this->usesCoverageAA()) {
468 if (this->compatibleWithCoverageAsAlpha() && this->hasVertexColors() &&
469 !this->requiresGeometryDomain()) {
470 // Using a geometric domain acts as a second source of coverage and folding
471 // the original coverage into color makes it impossible to apply the color's
472 // alpha to the geometric domain's coverage when the original shape is clipped.
473 return CoverageMode::kWithColor;
474 } else {
475 return CoverageMode::kWithPosition;
476 }
477 } else {
478 return CoverageMode::kNone;
479 }
480}
481
482// This needs to stay in sync w/ QuadPerEdgeAAGeometryProcessor::initializeAttrs
483size_t VertexSpec::vertexSize() const {
484 bool needsPerspective = (this->deviceDimensionality() == 3);
485 CoverageMode coverageMode = this->coverageMode();
486
487 size_t count = 0;
488
489 if (coverageMode == CoverageMode::kWithPosition) {
490 if (needsPerspective) {
491 count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
492 } else {
493 count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType) +
494 GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
495 }
496 } else {
497 if (needsPerspective) {
498 count += GrVertexAttribTypeSize(kFloat3_GrVertexAttribType);
499 } else {
500 count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType);
501 }
502 }
503
504 if (this->requiresGeometryDomain()) {
505 count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
506 }
507
508 count += this->localDimensionality() * GrVertexAttribTypeSize(kFloat_GrVertexAttribType);
509
510 if (ColorType::kByte == this->colorType()) {
511 count += GrVertexAttribTypeSize(kUByte4_norm_GrVertexAttribType);
512 } else if (ColorType::kHalf == this->colorType()) {
513 count += GrVertexAttribTypeSize(kHalf4_GrVertexAttribType);
514 }
515
516 if (this->hasDomain()) {
517 count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType);
518 }
519
520 return count;
521}
522
Michael Ludwig467994d2018-12-03 14:58:31 +0000523////////////////// Geometry Processor Implementation
Michael Ludwigc182b942018-11-16 10:27:51 -0500524
Michael Ludwig467994d2018-12-03 14:58:31 +0000525class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
526public:
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400527 using Saturate = GrTextureOp::Saturate;
Michael Ludwig20e909e2018-10-30 10:43:57 -0400528
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500529 static GrGeometryProcessor* Make(SkArenaAlloc* arena, const VertexSpec& spec) {
530 return arena->make<QuadPerEdgeAAGeometryProcessor>(spec);
Michael Ludwig20e909e2018-10-30 10:43:57 -0400531 }
532
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500533 static GrGeometryProcessor* Make(SkArenaAlloc* arena, const VertexSpec& vertexSpec,
534 const GrShaderCaps& caps,
535 const GrBackendFormat& backendFormat,
536 const GrSamplerState& samplerState,
537 const GrSwizzle& swizzle,
538 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
539 Saturate saturate) {
540 return arena->make<QuadPerEdgeAAGeometryProcessor>(
Robert Phillips323471e2019-11-11 11:33:37 -0500541 vertexSpec, caps, backendFormat, samplerState, swizzle,
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500542 std::move(textureColorSpaceXform), saturate);
Michael Ludwig20e909e2018-10-30 10:43:57 -0400543 }
544
Michael Ludwig467994d2018-12-03 14:58:31 +0000545 const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; }
Michael Ludwig024e2622018-11-30 13:25:55 -0500546
Michael Ludwig467994d2018-12-03 14:58:31 +0000547 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400548 // texturing, device-dimensions are single bit flags
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400549 uint32_t x = (fTexDomain.isInitialized() ? 0 : 0x1)
550 | (fSampler.isInitialized() ? 0 : 0x2)
551 | (fNeedsPerspective ? 0 : 0x4)
552 | (fSaturate == Saturate::kNo ? 0 : 0x8);
Michael Ludwig467994d2018-12-03 14:58:31 +0000553 // local coords require 2 bits (3 choices), 00 for none, 01 for 2d, 10 for 3d
554 if (fLocalCoord.isInitialized()) {
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400555 x |= kFloat3_GrVertexAttribType == fLocalCoord.cpuType() ? 0x10 : 0x20;
Brian Osman78dc72c2018-12-03 13:20:43 +0000556 }
Michael Ludwig467994d2018-12-03 14:58:31 +0000557 // similar for colors, 00 for none, 01 for bytes, 10 for half-floats
Michael Ludwig93aeba02018-12-21 09:50:31 -0500558 if (fColor.isInitialized()) {
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400559 x |= kUByte4_norm_GrVertexAttribType == fColor.cpuType() ? 0x40 : 0x80;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500560 }
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400561 // and coverage mode, 00 for none, 01 for withposition, 10 for withcolor, 11 for
562 // position+geomdomain
563 SkASSERT(!fGeomDomain.isInitialized() || fCoverageMode == CoverageMode::kWithPosition);
Michael Ludwig93aeba02018-12-21 09:50:31 -0500564 if (fCoverageMode != CoverageMode::kNone) {
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400565 x |= fGeomDomain.isInitialized()
566 ? 0x300
567 : (CoverageMode::kWithPosition == fCoverageMode ? 0x100 : 0x200);
Michael Ludwig467994d2018-12-03 14:58:31 +0000568 }
569
570 b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()));
571 b->add32(x);
Brian Osman78dc72c2018-12-03 13:20:43 +0000572 }
Michael Ludwig467994d2018-12-03 14:58:31 +0000573
574 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
575 class GLSLProcessor : public GrGLSLGeometryProcessor {
576 public:
577 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
Brian Salomonc241b582019-11-27 08:57:17 -0500578 const CoordTransformRange& transformRange) override {
Michael Ludwig467994d2018-12-03 14:58:31 +0000579 const auto& gp = proc.cast<QuadPerEdgeAAGeometryProcessor>();
580 if (gp.fLocalCoord.isInitialized()) {
Brian Salomonc241b582019-11-27 08:57:17 -0500581 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Michael Ludwig467994d2018-12-03 14:58:31 +0000582 }
583 fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get());
584 }
585
586 private:
587 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
588 using Interpolation = GrGLSLVaryingHandler::Interpolation;
589
590 const auto& gp = args.fGP.cast<QuadPerEdgeAAGeometryProcessor>();
591 fTextureColorSpaceXformHelper.emitCode(args.fUniformHandler,
592 gp.fTextureColorSpaceXform.get());
593
594 args.fVaryingHandler->emitAttributes(gp);
595
Michael Ludwig93aeba02018-12-21 09:50:31 -0500596 if (gp.fCoverageMode == CoverageMode::kWithPosition) {
597 // Strip last channel from the vertex attribute to remove coverage and get the
598 // actual position
599 if (gp.fNeedsPerspective) {
600 args.fVertBuilder->codeAppendf("float3 position = %s.xyz;",
601 gp.fPosition.name());
602 } else {
603 args.fVertBuilder->codeAppendf("float2 position = %s.xy;",
604 gp.fPosition.name());
605 }
606 gpArgs->fPositionVar = {"position",
607 gp.fNeedsPerspective ? kFloat3_GrSLType
608 : kFloat2_GrSLType,
609 GrShaderVar::kNone_TypeModifier};
Michael Ludwig467994d2018-12-03 14:58:31 +0000610 } else {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500611 // No coverage to eliminate
612 gpArgs->fPositionVar = gp.fPosition.asShaderVar();
Michael Ludwig467994d2018-12-03 14:58:31 +0000613 }
Michael Ludwig467994d2018-12-03 14:58:31 +0000614
615 // Handle local coordinates if they exist
616 if (gp.fLocalCoord.isInitialized()) {
617 // NOTE: If the only usage of local coordinates is for the inline texture fetch
618 // before FPs, then there are no registered FPCoordTransforms and this ends up
619 // emitting nothing, so there isn't a duplication of local coordinates
620 this->emitTransforms(args.fVertBuilder,
621 args.fVaryingHandler,
622 args.fUniformHandler,
623 gp.fLocalCoord.asShaderVar(),
624 args.fFPCoordTransformHandler);
625 }
626
627 // Solid color before any texturing gets modulated in
628 if (gp.fColor.isInitialized()) {
Michael Ludwig3d2753e2019-03-29 14:36:32 -0400629 SkASSERT(gp.fCoverageMode != CoverageMode::kWithColor || !gp.fNeedsPerspective);
Michael Ludwig93aeba02018-12-21 09:50:31 -0500630 // The color cannot be flat if the varying coverage has been modulated into it
Michael Ludwig467994d2018-12-03 14:58:31 +0000631 args.fVaryingHandler->addPassThroughAttribute(gp.fColor, args.fOutputColor,
Michael Ludwig93aeba02018-12-21 09:50:31 -0500632 gp.fCoverageMode == CoverageMode::kWithColor ?
633 Interpolation::kInterpolated : Interpolation::kCanBeFlat);
634 } else {
635 // Output color must be initialized to something
636 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputColor);
Michael Ludwig467994d2018-12-03 14:58:31 +0000637 }
638
639 // If there is a texture, must also handle texture coordinates and reading from
640 // the texture in the fragment shader before continuing to fragment processors.
641 if (gp.fSampler.isInitialized()) {
642 // Texture coordinates clamped by the domain on the fragment shader; if the GP
643 // has a texture, it's guaranteed to have local coordinates
644 args.fFragBuilder->codeAppend("float2 texCoord;");
645 if (gp.fLocalCoord.cpuType() == kFloat3_GrVertexAttribType) {
646 // Can't do a pass through since we need to perform perspective division
647 GrGLSLVarying v(gp.fLocalCoord.gpuType());
648 args.fVaryingHandler->addVarying(gp.fLocalCoord.name(), &v);
649 args.fVertBuilder->codeAppendf("%s = %s;",
650 v.vsOut(), gp.fLocalCoord.name());
651 args.fFragBuilder->codeAppendf("texCoord = %s.xy / %s.z;",
652 v.fsIn(), v.fsIn());
653 } else {
654 args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord, "texCoord");
655 }
656
657 // Clamp the now 2D localCoordName variable by the domain if it is provided
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400658 if (gp.fTexDomain.isInitialized()) {
Michael Ludwig467994d2018-12-03 14:58:31 +0000659 args.fFragBuilder->codeAppend("float4 domain;");
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400660 args.fVaryingHandler->addPassThroughAttribute(gp.fTexDomain, "domain",
Michael Ludwig467994d2018-12-03 14:58:31 +0000661 Interpolation::kCanBeFlat);
662 args.fFragBuilder->codeAppend(
663 "texCoord = clamp(texCoord, domain.xy, domain.zw);");
664 }
665
666 // Now modulate the starting output color by the texture lookup
667 args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
668 args.fFragBuilder->appendTextureLookupAndModulate(
669 args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
670 &fTextureColorSpaceXformHelper);
671 args.fFragBuilder->codeAppend(";");
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400672 if (gp.fSaturate == Saturate::kYes) {
673 args.fFragBuilder->codeAppendf("%s = saturate(%s);",
674 args.fOutputColor, args.fOutputColor);
675 }
676 } else {
677 // Saturate is only intended for use with a proxy to account for the fact
678 // that GrTextureOp skips SkPaint conversion, which normally handles this.
679 SkASSERT(gp.fSaturate == Saturate::kNo);
Michael Ludwig467994d2018-12-03 14:58:31 +0000680 }
681
682 // And lastly, output the coverage calculation code
Michael Ludwig93aeba02018-12-21 09:50:31 -0500683 if (gp.fCoverageMode == CoverageMode::kWithPosition) {
684 GrGLSLVarying coverage(kFloat_GrSLType);
685 args.fVaryingHandler->addVarying("coverage", &coverage);
Michael Ludwig467994d2018-12-03 14:58:31 +0000686 if (gp.fNeedsPerspective) {
Michael Ludwig3d2753e2019-03-29 14:36:32 -0400687 // Multiply by "W" in the vertex shader, then by 1/w (sk_FragCoord.w) in
688 // the fragment shader to get screen-space linear coverage.
689 args.fVertBuilder->codeAppendf("%s = %s.w * %s.z;",
690 coverage.vsOut(), gp.fPosition.name(),
691 gp.fPosition.name());
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400692 args.fFragBuilder->codeAppendf("float coverage = %s * sk_FragCoord.w;",
693 coverage.fsIn());
Michael Ludwig93aeba02018-12-21 09:50:31 -0500694 } else {
Jim Van Verthd5d9c212019-05-02 10:22:10 -0400695 args.fVertBuilder->codeAppendf("%s = %s;",
696 coverage.vsOut(), gp.fCoverage.name());
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400697 args.fFragBuilder->codeAppendf("float coverage = %s;", coverage.fsIn());
Michael Ludwig467994d2018-12-03 14:58:31 +0000698 }
Michael Ludwig93aeba02018-12-21 09:50:31 -0500699
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400700 if (gp.fGeomDomain.isInitialized()) {
701 // Calculate distance from sk_FragCoord to the 4 edges of the domain
702 // and clamp them to (0, 1). Use the minimum of these and the original
703 // coverage. This only has to be done in the exterior triangles, the
704 // interior of the quad geometry can never be clipped by the domain box.
705 args.fFragBuilder->codeAppend("float4 geoDomain;");
706 args.fVaryingHandler->addPassThroughAttribute(gp.fGeomDomain, "geoDomain",
707 Interpolation::kCanBeFlat);
708 args.fFragBuilder->codeAppend(
709 "if (coverage < 0.5) {"
710 " float4 dists4 = clamp(float4(1, 1, -1, -1) * "
711 "(sk_FragCoord.xyxy - geoDomain), 0, 1);"
712 " float2 dists2 = dists4.xy * dists4.zw;"
713 " coverage = min(coverage, dists2.x * dists2.y);"
714 "}");
715 }
716
717 args.fFragBuilder->codeAppendf("%s = half4(half(coverage));",
718 args.fOutputCoverage);
Michael Ludwig467994d2018-12-03 14:58:31 +0000719 } else {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500720 // Set coverage to 1, since it's either non-AA or the coverage was already
721 // folded into the output color
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400722 SkASSERT(!gp.fGeomDomain.isInitialized());
Ethan Nicholase1f55022019-02-05 17:17:40 -0500723 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
Michael Ludwig467994d2018-12-03 14:58:31 +0000724 }
725 }
726 GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper;
727 };
728 return new GLSLProcessor;
729 }
730
731private:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500732 friend class ::SkArenaAlloc; // for access to ctor
733
Michael Ludwig467994d2018-12-03 14:58:31 +0000734 QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec)
735 : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
736 , fTextureColorSpaceXform(nullptr) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500737 SkASSERT(!spec.hasDomain());
Michael Ludwig467994d2018-12-03 14:58:31 +0000738 this->initializeAttrs(spec);
739 this->setTextureSamplerCnt(0);
740 }
741
Brian Salomon67529b22019-08-13 15:31:04 -0400742 QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec,
743 const GrShaderCaps& caps,
Robert Phillipsf272bea2019-10-17 08:56:16 -0400744 const GrBackendFormat& backendFormat,
Greg Daniel7a82edf2018-12-04 10:54:34 -0500745 const GrSamplerState& samplerState,
Greg Daniel2c3398d2019-06-19 11:58:01 -0400746 const GrSwizzle& swizzle,
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400747 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
748 Saturate saturate)
Michael Ludwig467994d2018-12-03 14:58:31 +0000749 : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400750 , fSaturate(saturate)
Michael Ludwig467994d2018-12-03 14:58:31 +0000751 , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
Robert Phillips323471e2019-11-11 11:33:37 -0500752 , fSampler(samplerState, backendFormat, swizzle) {
Michael Ludwig93aeba02018-12-21 09:50:31 -0500753 SkASSERT(spec.hasLocalCoords());
Michael Ludwig467994d2018-12-03 14:58:31 +0000754 this->initializeAttrs(spec);
755 this->setTextureSamplerCnt(1);
756 }
757
Robert Phillips29f38542019-10-16 09:20:25 -0400758 // This needs to stay in sync w/ VertexSpec::vertexSize
Michael Ludwig467994d2018-12-03 14:58:31 +0000759 void initializeAttrs(const VertexSpec& spec) {
760 fNeedsPerspective = spec.deviceDimensionality() == 3;
Robert Phillips29f38542019-10-16 09:20:25 -0400761 fCoverageMode = spec.coverageMode();
Michael Ludwig93aeba02018-12-21 09:50:31 -0500762
763 if (fCoverageMode == CoverageMode::kWithPosition) {
764 if (fNeedsPerspective) {
765 fPosition = {"positionWithCoverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
766 } else {
Jim Van Verthd5d9c212019-05-02 10:22:10 -0400767 fPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
768 fCoverage = {"coverage", kFloat_GrVertexAttribType, kFloat_GrSLType};
Michael Ludwig93aeba02018-12-21 09:50:31 -0500769 }
770 } else {
771 if (fNeedsPerspective) {
772 fPosition = {"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
773 } else {
774 fPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
775 }
776 }
Michael Ludwig467994d2018-12-03 14:58:31 +0000777
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400778 // Need a geometry domain when the quads are AA and not rectilinear, since their AA
779 // outsetting can go beyond a half pixel.
780 if (spec.requiresGeometryDomain()) {
781 fGeomDomain = {"geomDomain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
782 }
783
Michael Ludwig467994d2018-12-03 14:58:31 +0000784 int localDim = spec.localDimensionality();
785 if (localDim == 3) {
786 fLocalCoord = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
787 } else if (localDim == 2) {
788 fLocalCoord = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
789 } // else localDim == 0 and attribute remains uninitialized
790
791 if (ColorType::kByte == spec.colorType()) {
792 fColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
793 } else if (ColorType::kHalf == spec.colorType()) {
794 fColor = {"color", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
795 }
796
797 if (spec.hasDomain()) {
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400798 fTexDomain = {"texDomain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
Michael Ludwig467994d2018-12-03 14:58:31 +0000799 }
800
Jim Van Verthd5d9c212019-05-02 10:22:10 -0400801 this->setVertexAttributes(&fPosition, 6);
Michael Ludwig467994d2018-12-03 14:58:31 +0000802 }
803
804 const TextureSampler& onTextureSampler(int) const override { return fSampler; }
805
Michael Ludwig93aeba02018-12-21 09:50:31 -0500806 Attribute fPosition; // May contain coverage as last channel
Jim Van Verthd5d9c212019-05-02 10:22:10 -0400807 Attribute fCoverage; // Used for non-perspective position to avoid Intel Metal issues
Michael Ludwig93aeba02018-12-21 09:50:31 -0500808 Attribute fColor; // May have coverage modulated in if the FPs support it
Michael Ludwig467994d2018-12-03 14:58:31 +0000809 Attribute fLocalCoord;
Michael Ludwigdcfbe322019-04-01 14:55:54 -0400810 Attribute fGeomDomain; // Screen-space bounding box on geometry+aa outset
811 Attribute fTexDomain; // Texture-space bounding box on local coords
Michael Ludwig467994d2018-12-03 14:58:31 +0000812
Michael Ludwig93aeba02018-12-21 09:50:31 -0500813 // The positions attribute may have coverage built into it, so float3 is an ambiguous type
814 // and may mean 2d with coverage, or 3d with no coverage
Michael Ludwig467994d2018-12-03 14:58:31 +0000815 bool fNeedsPerspective;
Brian Salomonf19f9ca2019-09-18 15:54:26 -0400816 // Should saturate() be called on the color? Only relevant when created with a texture.
817 Saturate fSaturate = Saturate::kNo;
Michael Ludwig93aeba02018-12-21 09:50:31 -0500818 CoverageMode fCoverageMode;
Michael Ludwig467994d2018-12-03 14:58:31 +0000819
820 // Color space will be null and fSampler.isInitialized() returns false when the GP is configured
821 // to skip texturing.
822 sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
823 TextureSampler fSampler;
824
825 typedef GrGeometryProcessor INHERITED;
826};
827
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500828GrGeometryProcessor* MakeProcessor(SkArenaAlloc* arena, const VertexSpec& spec) {
829 return QuadPerEdgeAAGeometryProcessor::Make(arena, spec);
Michael Ludwig467994d2018-12-03 14:58:31 +0000830}
831
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500832GrGeometryProcessor* MakeTexturedProcessor(SkArenaAlloc* arena, const VertexSpec& spec,
833 const GrShaderCaps& caps,
834 const GrBackendFormat& backendFormat,
835 const GrSamplerState& samplerState,
836 const GrSwizzle& swizzle,
837 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
838 Saturate saturate) {
839 return QuadPerEdgeAAGeometryProcessor::Make(arena, spec, caps, backendFormat, samplerState,
840 swizzle, std::move(textureColorSpaceXform),
841 saturate);
Michael Ludwig20e909e2018-10-30 10:43:57 -0400842}
Michael Ludwigc182b942018-11-16 10:27:51 -0500843
844} // namespace GrQuadPerEdgeAA