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