blob: 3c98570a4f50c887766eacf971a623f427467d95 [file] [log] [blame]
Chris Dalton133944a2018-11-16 23:30:29 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAAFillRRectOp.h"
9
10#include "GrCaps.h"
11#include "GrContextPriv.h"
12#include "GrGpuCommandBuffer.h"
13#include "GrMemoryPool.h"
14#include "SkRRectPriv.h"
15#include "glsl/GrGLSLFragmentShaderBuilder.h"
16#include "glsl/GrGLSLGeometryProcessor.h"
17#include "glsl/GrGLSLVarying.h"
18#include "glsl/GrGLSLVertexGeoBuilder.h"
19
20// Hardware derivatives are not always accurate enough for highly elliptical corners. This method
21// checks to make sure the corners will still all look good if we use HW derivatives.
22static bool can_use_hw_derivatives(const GrShaderCaps&, const SkMatrix&, const SkRRect&);
23
24std::unique_ptr<GrAAFillRRectOp> GrAAFillRRectOp::Make(
25 GrContext* ctx, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrCaps& caps,
26 GrPaint&& paint) {
27 if (!caps.instanceAttribSupport()) {
28 return nullptr;
29 }
30
31 // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we already
32 // use HW derivatives. The only trick will be adjusting the AA outset to account for
33 // perspective. (i.e., outset = 0.5 * z.)
34 if (viewMatrix.hasPerspective()) {
35 return nullptr;
36 }
37
38 GrOpMemoryPool* pool = ctx->contextPriv().opMemoryPool();
39 return pool->allocate<GrAAFillRRectOp>(*caps.shaderCaps(), viewMatrix, rrect, std::move(paint));
40}
41
42GrAAFillRRectOp::GrAAFillRRectOp(const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
43 const SkRRect& rrect, GrPaint&& paint)
44 : GrDrawOp(ClassID())
45 , fOriginalColor(paint.getColor4f())
46 , fLocalRect(rrect.rect())
47 , fProcessors(std::move(paint)) {
48 if (can_use_hw_derivatives(shaderCaps, viewMatrix, rrect)) {
49 fFlags |= Flags::kUseHWDerivatives;
50 }
51
52 // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space.
53 float l = rrect.rect().left(), r = rrect.rect().right(),
54 t = rrect.rect().top(), b = rrect.rect().bottom();
55 SkMatrix m;
56 // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b].
57 m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2);
58 // Map to device space.
59 m.postConcat(viewMatrix);
60
61 // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's
62 // device-space quad, it's quite simple to find the bounding rectangle:
63 SkASSERT(!m.hasPerspective());
64 SkRect bounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0);
65 bounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()),
66 SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY()));
67 this->setBounds(bounds, GrOp::HasAABloat::kYes, GrOp::IsZeroArea::kNo);
68
69 // Write the matrix attribs.
70 this->writeInstanceData(m.getScaleX(), m.getSkewX(), m.getSkewY(), m.getScaleY());
71 this->writeInstanceData(m.getTranslateX(), m.getTranslateY());
72
73 // Convert the radii to [-1, -1, +1, +1] space and write their attribs.
74 Sk4f radiiX, radiiY;
75 Sk4f::Load2(SkRRectPriv::GetRadiiArray(rrect), &radiiX, &radiiY);
76 (radiiX * (2/(r - l))).store(this->appendInstanceData<float>(4));
77 (radiiY * (2/(b - t))).store(this->appendInstanceData<float>(4));
78
79 // We will write the color and local rect attribs during finalize().
80}
81
82GrDrawOp::RequiresDstTexture GrAAFillRRectOp::finalize(const GrCaps& caps,
83 const GrAppliedClip* clip) {
84 SkASSERT(1 == fInstanceCount);
85
86 SkPMColor4f overrideColor;
87 const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
88 fOriginalColor, GrProcessorAnalysisCoverage::kSingleChannel, clip, false, caps,
89 &overrideColor);
90
91 // Finish writing the instance attribs.
92 this->writeInstanceData(
93 (analysis.inputColorIsOverridden() ? overrideColor : fOriginalColor).toBytes_RGBA());
94 if (analysis.usesLocalCoords()) {
95 this->writeInstanceData(fLocalRect);
96 fFlags |= Flags::kHasLocalCoords;
97 }
98 fInstanceStride = fInstanceData.count();
99
100 return RequiresDstTexture(analysis.requiresDstTexture());
101}
102
103GrDrawOp::CombineResult GrAAFillRRectOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
104 const auto& that = *op->cast<GrAAFillRRectOp>();
105 if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
106 fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
107 return CombineResult::kCannotCombine;
108 }
109
110 fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
111 fInstanceCount += that.fInstanceCount;
112 SkASSERT(fInstanceStride == that.fInstanceStride);
113 return CombineResult::kMerged;
114}
115
116void GrAAFillRRectOp::onPrepare(GrOpFlushState* flushState) {
117 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
118 &fInstanceBuffer, &fBaseInstance)) {
119 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
120 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
121 }
122}
123
124namespace {
125
126// Our round rect geometry consists of an inset octagon with solid coverage, surrounded by linear
127// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
128// edges. The Vertex struct tells the shader where to place its vertex within a normalized
129// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
130struct Vertex {
131 std::array<float, 4> fRadiiSelector;
132 std::array<float, 2> fCorner;
133 std::array<float, 2> fRadiusOutset;
134 std::array<float, 2> fAABloatDirection;
135 float fCoverage;
136 float fIsLinearCoverage;
137 std::array<float, 4> fArcCoordMatrix;
138};
139
140// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
141// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
142// rectangles.
143static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
144
145// This matrix is used to calculate normalized arc coordinates.
146// (i.e., arccoord.x^2 + arccoord.y^2 == 1). The formula to find the arc coord is:
147//
148// arccoord = arc_coord_matrix.xz * aa_bloatradius/radii + arc_coord_matrix.yw;
149//
150// See kVertexData and onEmitCode.
151static constexpr std::array<float, 4> kArcMatrices[] = {
152 {{+1, 1, 0, 0}},
153 {{-1, 1, 0, 0}},
154 {{ 0, 0, -1, 1}},
155 {{ 0, 0, +1, 1}},
156 {{+1, 1-kOctoOffset, +1, 1}},
157 {{+1, 1, +1, 1-kOctoOffset}}};
158
159static constexpr Vertex kVertexData[] = {
160 // Left inset edge.
161 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1, {{0,0,0,0}}},
162 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1, {{0,0,0,0}}},
163
164 // Top inset edge.
165 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1, {{0,0,0,0}}},
166 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1, {{0,0,0,0}}},
167
168 // Right inset edge.
169 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1, {{0,0,0,0}}},
170 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1, {{0,0,0,0}}},
171
172 // Bottom inset edge.
173 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1, {{0,0,0,0}}},
174 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1, {{0,0,0,0}}},
175
176
177 // Left outset edge.
178 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1, {{0,0,0,0}}},
179 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1, {{0,0,0,0}}},
180
181 // Top outset edge.
182 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1, {{0,0,0,0}}},
183 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1, {{0,0,0,0}}},
184
185 // Right outset edge.
186 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1, {{0,0,0,0}}},
187 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1, {{0,0,0,0}}},
188
189 // Bottom outset edge.
190 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1, {{0,0,0,0}}},
191 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1, {{0,0,0,0}}},
192
193
194 // Top-left corner.
195 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0, kArcMatrices[0]},
196 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0, kArcMatrices[1]},
197 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0, kArcMatrices[2]},
198 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0, kArcMatrices[3]},
199 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0, kArcMatrices[4]},
200 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0, kArcMatrices[5]},
201
202 // Top-right corner.
203 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0, kArcMatrices[3]},
204 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0, kArcMatrices[2]},
205 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0, kArcMatrices[1]},
206 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0, kArcMatrices[0]},
207 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0, kArcMatrices[5]},
208 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0, kArcMatrices[4]},
209
210 // Bottom-right corner.
211 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0, kArcMatrices[0]},
212 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0, kArcMatrices[1]},
213 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0, kArcMatrices[2]},
214 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0, kArcMatrices[3]},
215 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0, kArcMatrices[4]},
216 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0, kArcMatrices[5]},
217
218 // Bottom-left corner.
219 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0, kArcMatrices[3]},
220 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0, kArcMatrices[2]},
221 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0, kArcMatrices[1]},
222 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0, kArcMatrices[0]},
223 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1, 0}}, 0, 0, kArcMatrices[5]},
224 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0, kArcMatrices[4]}};
225
226GR_DECLARE_STATIC_UNIQUE_KEY(gVertexBufferKey);
227
228static constexpr uint16_t kIndexData[] = {
229 // Inset octagon (solid coverage).
230 0, 1, 7,
231 1, 2, 7,
232 7, 2, 6,
233 2, 3, 6,
234 6, 3, 5,
235 3, 4, 5,
236
237 // AA borders (linear coverage).
238 0, 1, 8, 1, 9, 8,
239 2, 3, 10, 3, 11, 10,
240 4, 5, 12, 5, 13, 12,
241 6, 7, 14, 7, 15, 14,
242
243 // Top-left arc.
244 16, 17, 21,
245 17, 21, 18,
246 21, 18, 20,
247 18, 20, 19,
248
249 // Top-right arc.
250 22, 23, 27,
251 23, 27, 24,
252 27, 24, 26,
253 24, 26, 25,
254
255 // Bottom-right arc.
256 28, 29, 33,
257 29, 33, 30,
258 33, 30, 32,
259 30, 32, 31,
260
261 // Bottom-left arc.
262 34, 35, 39,
263 35, 39, 36,
264 39, 36, 38,
265 36, 38, 37};
266
267GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
268
269}
270
271class GrAAFillRRectOp::Processor : public GrGeometryProcessor {
272public:
273 Processor(Flags flags)
274 : GrGeometryProcessor(kGrAAFillRRectOp_Processor_ClassID)
275 , fFlags(flags) {
276 this->setVertexAttributes(kVertexAttribs, 4);
277 this->setInstanceAttributes(kInstanceAttribs, (flags & Flags::kHasLocalCoords) ? 6 : 5);
278 SkASSERT(this->vertexStride() == sizeof(Vertex));
279 }
280
281 const char* name() const override { return "GrAAFillRRectOp::Processor"; }
282
283 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
284 b->add32(static_cast<uint32_t>(fFlags));
285 }
286
287 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
288
289private:
290 static constexpr Attribute kVertexAttribs[] = {
291 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
292 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
293 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
294 {"arc_coord_matrix", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
295
296 static constexpr Attribute kInstanceAttribs[] = {
297 {"skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
298 {"translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType},
299 {"radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
300 {"radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
301 {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType},
302 {"local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; // Conditional.
303
304 static constexpr int kColorAttribIdx = 4;
305
306 const Flags fFlags;
307
308 class Impl;
309};
310
311constexpr GrPrimitiveProcessor::Attribute GrAAFillRRectOp::Processor::kVertexAttribs[];
312constexpr GrPrimitiveProcessor::Attribute GrAAFillRRectOp::Processor::kInstanceAttribs[];
313
314class GrAAFillRRectOp::Processor::Impl : public GrGLSLGeometryProcessor {
315public:
316 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
317 const auto& proc = args.fGP.cast<Processor>();
318 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
319
320 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
321 varyings->emitAttributes(proc);
322 varyings->addPassThroughAttribute(proc.kInstanceAttribs[kColorAttribIdx], args.fOutputColor,
323 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
324
325 // Emit the vertex shader.
326 GrGLSLVertexBuilder* v = args.fVertBuilder;
327
328 // Unpack vertex attribs.
329 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
330 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
331 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
332 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
333 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
334
335 // Find the amount to bloat each edge for AA (in source space).
336 v->codeAppend("float2 pixellength = inversesqrt("
337 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
338 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
339 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
340 "abs(normalized_axis_dirs.zw));");
341 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
342
343 // Identify our radii.
344 v->codeAppend("float2 radii = float2(dot(radii_selector, radii_x), "
345 "dot(radii_selector, radii_y));");
346
347 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
348 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
349 // or else opposite AA borders will overlap. Instead, fudge the size up to
350 // the width of a coverage ramp, and then reduce total coverage to make
351 // the rect appear more thin.
352 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
353 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
354 // Set radii to zero to ensure we take the "linear coverage" codepath.
355 // (The "coverage" variable only has effect in the linear codepath.)
356 v->codeAppend( "radii = float2(0);");
357 v->codeAppend("}");
358
359 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
360 // The radii are very small. Demote this arc to a sharp 90 degree corner.
361 v->codeAppend( "radii = aa_bloatradius;");
362 // Snap octagon vertices to the corner of the bounding box.
363 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
364 v->codeAppend( "is_linear_coverage = 1;");
365 v->codeAppend("} else {");
366 // Don't let actual arc radii get smaller than a pixel.
367 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
368 v->codeAppend("}");
369 // Bias radii slightly inward to avoid accidental overlap of geometries from fp rounding.
370 v->codeAppend("radii -= aa_bloatradius * 1e-3;");
371
372 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
373 // normalized [-1,-1,+1,+1] space.
374 v->codeAppend("float2 vertexpos = corner"
375 "+ radius_outset * radii"
376 "+ aa_bloat_direction.xy * aa_bloatradius;");
377
378 // Emit transforms.
379 GrShaderVar localCoord("", kFloat2_GrSLType);
380 if (proc.fFlags & Flags::kHasLocalCoords) {
381 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
382 "local_rect.zw * (1 + vertexpos)) * .5;");
383 localCoord.set(kFloat2_GrSLType, "localcoord");
384 }
385 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
386 args.fFPCoordTransformHandler);
387
388 // Transform to device space.
389 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
390 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
391 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
392
393 // Setup interpolants for coverage.
394 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
395 varyings->addVarying("arccoord", &arcCoord);
396 v->codeAppend("if (0 != is_linear_coverage) {");
397 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
398 // interpolate linear coverage across y.
399 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
400 v->codeAppend("} else {");
401 v->codeAppend( "float2 arccoord = "
402 "arc_coord_matrix.xz * aa_bloatradius/radii + arc_coord_matrix.yw;");
403 // We are a corner piece: Interpolate the arc coordinates for coverage.
404 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
405 // instructs the fragment shader to use linear coverage).
406 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
407 if (!useHWDerivatives) {
408 // The gradient is order-1: Interpolate it across arccoord.zw.
409 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
410 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
411 }
412 v->codeAppend("}");
413
414 // Emit the fragment shader.
415 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
416
417 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
418 f->codeAppendf("half coverage;");
419 f->codeAppendf("if (0 == x_plus_1) {");
420 f->codeAppendf( "coverage = y;"); // We are a non-arc pixel (i.e., linear coverage).
421 f->codeAppendf("} else {");
422 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
423 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
424 if (useHWDerivatives) {
425 f->codeAppendf("float fnwidth = fwidth(fn);");
426 } else {
427 // The gradient is interpolated across arccoord.zw.
428 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
429 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
430 }
431 f->codeAppendf( "half d = fn/fnwidth;");
432 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
433 f->codeAppendf("}");
434 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
435 }
436
437 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
438 FPCoordTransformIter&& transformIter) override {
439 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
440 }
441};
442
443GrGLSLPrimitiveProcessor* GrAAFillRRectOp::Processor::createGLSLInstance(
444 const GrShaderCaps&) const {
445 return new Impl();
446}
447
448void GrAAFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
449 if (!fInstanceBuffer) {
450 return; // Setup failed.
451 }
452
453 GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
454
455 sk_sp<const GrBuffer> indexBuffer =
456 flushState->resourceProvider()->findOrMakeStaticBuffer(
457 kIndex_GrBufferType, sizeof(kIndexData), kIndexData, gIndexBufferKey);
458 if (!indexBuffer) {
459 return;
460 }
461
462 GR_DEFINE_STATIC_UNIQUE_KEY(gVertexBufferKey);
463
464 sk_sp<const GrBuffer> vertexBuffer =
465 flushState->resourceProvider()->findOrMakeStaticBuffer(
466 kVertex_GrBufferType, sizeof(kVertexData), kVertexData, gVertexBufferKey);
467 if (!vertexBuffer) {
468 return;
469 }
470
471 Processor proc(fFlags);
472 SkASSERT(proc.instanceStride() == (size_t)fInstanceStride);
473
474 GrPipeline::InitArgs initArgs;
475 initArgs.fProxy = flushState->drawOpArgs().fProxy;
476 initArgs.fCaps = &flushState->caps();
477 initArgs.fResourceProvider = flushState->resourceProvider();
478 initArgs.fDstProxy = flushState->drawOpArgs().fDstProxy;
479 GrPipeline pipeline(initArgs, std::move(fProcessors), flushState->detachAppliedClip());
480
481 GrMesh mesh(GrPrimitiveType::kTriangles);
482 mesh.setIndexedInstanced(indexBuffer.get(), SK_ARRAY_COUNT(kIndexData), fInstanceBuffer,
483 fInstanceCount, fBaseInstance, GrPrimitiveRestart::kNo);
484 mesh.setVertexData(vertexBuffer.get());
485 flushState->rtCommandBuffer()->draw(proc, pipeline, nullptr, nullptr, &mesh, 1, this->bounds());
486}
487
488// Will the given corner look good if we use HW derivatives?
489static bool can_use_hw_derivatives(const Sk2f& devScale, const Sk2f& cornerRadii) {
490 Sk2f devRadii = devScale * cornerRadii;
491 if (devRadii[1] < devRadii[0]) {
492 devRadii = SkNx_shuffle<1,0>(devRadii);
493 }
494 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
495 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
496 // This threshold was arrived at subjevtively on an NVIDIA chip.
497 return minDevRadius * minDevRadius * 5 > devRadii[1];
498}
499
500static bool can_use_hw_derivatives(const Sk2f& devScale, const SkVector& cornerRadii) {
501 return can_use_hw_derivatives(devScale, Sk2f::Load(&cornerRadii));
502}
503
504// Will the given round rect look good if we use HW derivatives?
505static bool can_use_hw_derivatives(const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
506 const SkRRect& rrect) {
507 if (!shaderCaps.shaderDerivativeSupport()) {
508 return false;
509 }
510
511 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
512 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
513 Sk2f devScale = (x*x + y*y).sqrt();
514 switch (rrect.getType()) {
515 case SkRRect::kEmpty_Type:
516 case SkRRect::kRect_Type:
517 return true;
518
519 case SkRRect::kOval_Type:
520 case SkRRect::kSimple_Type:
521 return can_use_hw_derivatives(devScale, rrect.getSimpleRadii());
522
523 case SkRRect::kNinePatch_Type: {
524 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
525 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
526 Sk2f minRadii = Sk2f::Min(r0, r1);
527 Sk2f maxRadii = Sk2f::Max(r0, r1);
528 return can_use_hw_derivatives(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
529 can_use_hw_derivatives(devScale, Sk2f(maxRadii[0], minRadii[1]));
530 }
531
532 case SkRRect::kComplex_Type: {
533 for (int i = 0; i < 4; ++i) {
534 auto corner = static_cast<SkRRect::Corner>(i);
535 if (!can_use_hw_derivatives(devScale, rrect.radii(corner))) {
536 return false;
537 }
538 }
539 return true;
540 }
541 }
542 SK_ABORT("Unreachable code.");
543 return false; // Add this return to keep GCC happy.
544}