• 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 "src/gpu/ops/GrFillRRectOp.h"
9 
10 #include "include/private/GrRecordingContext.h"
11 #include "src/core/SkRRectPriv.h"
12 #include "src/gpu/GrCaps.h"
13 #include "src/gpu/GrGpuCommandBuffer.h"
14 #include "src/gpu/GrMemoryPool.h"
15 #include "src/gpu/GrOpFlushState.h"
16 #include "src/gpu/GrRecordingContextPriv.h"
17 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
19 #include "src/gpu/glsl/GrGLSLVarying.h"
20 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
21 
22 // Hardware derivatives are not always accurate enough for highly elliptical corners. This method
23 // checks to make sure the corners will still all look good if we use HW derivatives.
24 static bool can_use_hw_derivatives_with_coverage(
25         const GrShaderCaps&, const SkMatrix&, const SkRRect&);
26 
Make(GrRecordingContext * ctx,GrAAType aaType,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrCaps & caps,GrPaint && paint)27 std::unique_ptr<GrFillRRectOp> GrFillRRectOp::Make(
28         GrRecordingContext* ctx, GrAAType aaType, const SkMatrix& viewMatrix, const SkRRect& rrect,
29         const GrCaps& caps, GrPaint&& paint) {
30     if (!caps.instanceAttribSupport()) {
31         return nullptr;
32     }
33 
34     Flags flags = Flags::kNone;
35     if (GrAAType::kCoverage == aaType) {
36         // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we
37         // already use HW derivatives. The only trick will be adjusting the AA outset to account for
38         // perspective. (i.e., outset = 0.5 * z.)
39         if (viewMatrix.hasPerspective()) {
40             return nullptr;
41         }
42         if (can_use_hw_derivatives_with_coverage(*caps.shaderCaps(), viewMatrix, rrect)) {
43             // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms
44             // in coverage mode. We use them as long as the approximation will be accurate enough.
45             flags |= Flags::kUseHWDerivatives;
46         }
47     } else {
48         if (GrAAType::kMSAA == aaType) {
49             if (!caps.sampleLocationsSupport() || !caps.shaderCaps()->sampleVariablesSupport()) {
50                 return nullptr;
51             }
52         }
53         if (viewMatrix.hasPerspective()) {
54             // HW derivatives are consistently slower on all platforms in sample mask mode. We
55             // therefore only use them when there is perspective, since then we can't interpolate
56             // the symbolic screen-space gradient.
57             flags |= Flags::kUseHWDerivatives | Flags::kHasPerspective;
58         }
59     }
60 
61     // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space.
62     float l = rrect.rect().left(), r = rrect.rect().right(),
63           t = rrect.rect().top(), b = rrect.rect().bottom();
64     SkMatrix m;
65     // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b].
66     m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2);
67     // Map to device space.
68     m.postConcat(viewMatrix);
69 
70     SkRect devBounds;
71     if (!(flags & Flags::kHasPerspective)) {
72         // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's
73         // device-space quad, it's quite simple to find the bounding rectangle:
74         devBounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0);
75         devBounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()),
76                          SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY()));
77     } else {
78         viewMatrix.mapRect(&devBounds, rrect.rect());
79     }
80 
81     if (GrAAType::kMSAA == aaType && caps.preferTrianglesOverSampleMask()) {
82         // We are on a platform that prefers fine triangles instead of using the sample mask. See if
83         // the round rect is large enough that it will be faster for us to send it off to the
84         // default path renderer instead. The 200x200 threshold was arrived at using the
85         // "shapes_rrect" benchmark on an ARM Galaxy S9.
86         if (devBounds.height() * devBounds.width() > 200 * 200) {
87             return nullptr;
88         }
89     }
90 
91     GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
92     return pool->allocate<GrFillRRectOp>(aaType, rrect, flags, m, std::move(paint), devBounds);
93 }
94 
GrFillRRectOp(GrAAType aaType,const SkRRect & rrect,Flags flags,const SkMatrix & totalShapeMatrix,GrPaint && paint,const SkRect & devBounds)95 GrFillRRectOp::GrFillRRectOp(
96         GrAAType aaType, const SkRRect& rrect, Flags flags,
97         const SkMatrix& totalShapeMatrix, GrPaint&& paint, const SkRect& devBounds)
98         : GrDrawOp(ClassID())
99         , fAAType(aaType)
100         , fOriginalColor(paint.getColor4f())
101         , fLocalRect(rrect.rect())
102         , fFlags(flags)
103         , fProcessors(std::move(paint)) {
104     SkASSERT((fFlags & Flags::kHasPerspective) == totalShapeMatrix.hasPerspective());
105     this->setBounds(devBounds, GrOp::HasAABloat::kYes, GrOp::IsZeroArea::kNo);
106 
107     // Write the matrix attribs.
108     const SkMatrix& m = totalShapeMatrix;
109     if (!(fFlags & Flags::kHasPerspective)) {
110         // Affine 2D transformation (float2x2 plus float2 translate).
111         SkASSERT(!m.hasPerspective());
112         this->writeInstanceData(m.getScaleX(), m.getSkewX(), m.getSkewY(), m.getScaleY());
113         this->writeInstanceData(m.getTranslateX(), m.getTranslateY());
114     } else {
115         // Perspective float3x3 transformation matrix.
116         SkASSERT(m.hasPerspective());
117         m.get9(this->appendInstanceData<float>(9));
118     }
119 
120     // Convert the radii to [-1, -1, +1, +1] space and write their attribs.
121     Sk4f radiiX, radiiY;
122     Sk4f::Load2(SkRRectPriv::GetRadiiArray(rrect), &radiiX, &radiiY);
123     (radiiX * (2/rrect.width())).store(this->appendInstanceData<float>(4));
124     (radiiY * (2/rrect.height())).store(this->appendInstanceData<float>(4));
125 
126     // We will write the color and local rect attribs during finalize().
127 }
128 
finalize(const GrCaps & caps,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType clampType)129 GrProcessorSet::Analysis GrFillRRectOp::finalize(
130         const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
131         GrClampType clampType) {
132     SkASSERT(1 == fInstanceCount);
133 
134     SkPMColor4f overrideColor;
135     const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
136 
137             fOriginalColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
138             &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType,
139             &overrideColor);
140 
141     // Finish writing the instance attribs.
142     SkPMColor4f finalColor = analysis.inputColorIsOverridden() ? overrideColor : fOriginalColor;
143     if (!SkPMColor4fFitsInBytes(finalColor)) {
144         fFlags |= Flags::kWideColor;
145         uint32_t halfColor[2];
146         SkFloatToHalf_finite_ftz(Sk4f::Load(finalColor.vec())).store(&halfColor);
147         this->writeInstanceData(halfColor[0], halfColor[1]);
148     } else {
149         this->writeInstanceData(finalColor.toBytes_RGBA());
150     }
151 
152     if (analysis.usesLocalCoords()) {
153         this->writeInstanceData(fLocalRect);
154         fFlags |= Flags::kHasLocalCoords;
155     }
156     fInstanceStride = fInstanceData.count();
157 
158     return analysis;
159 }
160 
onCombineIfPossible(GrOp * op,const GrCaps &)161 GrDrawOp::CombineResult GrFillRRectOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
162     const auto& that = *op->cast<GrFillRRectOp>();
163     if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
164         fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
165         return CombineResult::kCannotCombine;
166     }
167 
168     fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
169     fInstanceCount += that.fInstanceCount;
170     SkASSERT(fInstanceStride == that.fInstanceStride);
171     return CombineResult::kMerged;
172 }
173 
onPrepare(GrOpFlushState * flushState)174 void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
175     if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
176                                                          &fInstanceBuffer, &fBaseInstance)) {
177         SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
178         memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
179     }
180 }
181 
182 class GrFillRRectOp::Processor : public GrGeometryProcessor {
183 public:
Processor(GrAAType aaType,Flags flags)184     Processor(GrAAType aaType, Flags flags)
185             : GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID)
186             , fAAType(aaType)
187             , fFlags(flags) {
188         int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
189         this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
190 
191         if (!(flags & Flags::kHasPerspective)) {
192             // Affine 2D transformation (float2x2 plus float2 translate).
193             fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
194             fInstanceAttribs.emplace_back(
195                     "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
196         } else {
197             // Perspective float3x3 transformation matrix.
198             fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
199             fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
200             fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
201         }
202         fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
203         fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
204         fColorAttrib = &fInstanceAttribs.push_back(
205                 MakeColorAttribute("color", (flags & Flags::kWideColor)));
206         if (fFlags & Flags::kHasLocalCoords) {
207             fInstanceAttribs.emplace_back(
208                     "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
209         }
210         this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
211 
212         if (GrAAType::kMSAA == fAAType) {
213             this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
214         }
215     }
216 
name() const217     const char* name() const override { return "GrFillRRectOp::Processor"; }
218 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const219     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
220         b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
221     }
222 
223     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
224 
225 private:
226     static constexpr Attribute kVertexAttribs[] = {
227             {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
228             {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
229             // Coverage only.
230             {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
231 
232     const GrAAType fAAType;
233     const Flags fFlags;
234 
235     SkSTArray<6, Attribute> fInstanceAttribs;
236     const Attribute* fColorAttrib;
237 
238     class CoverageImpl;
239     class MSAAImpl;
240 };
241 
242 constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
243 
244 // Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
245 // coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
246 // edges. The Vertex struct tells the shader where to place its vertex within a normalized
247 // ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
248 struct CoverageVertex {
249     std::array<float, 4> fRadiiSelector;
250     std::array<float, 2> fCorner;
251     std::array<float, 2> fRadiusOutset;
252     std::array<float, 2> fAABloatDirection;
253     float fCoverage;
254     float fIsLinearCoverage;
255 };
256 
257 // This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
258 // of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
259 // rectangles.
260 static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
261 
262 static constexpr CoverageVertex kCoverageVertexData[] = {
263         // Left inset edge.
264         {{{0,0,0,1}},  {{-1,+1}},  {{0,-1}},  {{+1,0}},  1,  1},
265         {{{1,0,0,0}},  {{-1,-1}},  {{0,+1}},  {{+1,0}},  1,  1},
266 
267         // Top inset edge.
268         {{{1,0,0,0}},  {{-1,-1}},  {{+1,0}},  {{0,+1}},  1,  1},
269         {{{0,1,0,0}},  {{+1,-1}},  {{-1,0}},  {{0,+1}},  1,  1},
270 
271         // Right inset edge.
272         {{{0,1,0,0}},  {{+1,-1}},  {{0,+1}},  {{-1,0}},  1,  1},
273         {{{0,0,1,0}},  {{+1,+1}},  {{0,-1}},  {{-1,0}},  1,  1},
274 
275         // Bottom inset edge.
276         {{{0,0,1,0}},  {{+1,+1}},  {{-1,0}},  {{0,-1}},  1,  1},
277         {{{0,0,0,1}},  {{-1,+1}},  {{+1,0}},  {{0,-1}},  1,  1},
278 
279 
280         // Left outset edge.
281         {{{0,0,0,1}},  {{-1,+1}},  {{0,-1}},  {{-1,0}},  0,  1},
282         {{{1,0,0,0}},  {{-1,-1}},  {{0,+1}},  {{-1,0}},  0,  1},
283 
284         // Top outset edge.
285         {{{1,0,0,0}},  {{-1,-1}},  {{+1,0}},  {{0,-1}},  0,  1},
286         {{{0,1,0,0}},  {{+1,-1}},  {{-1,0}},  {{0,-1}},  0,  1},
287 
288         // Right outset edge.
289         {{{0,1,0,0}},  {{+1,-1}},  {{0,+1}},  {{+1,0}},  0,  1},
290         {{{0,0,1,0}},  {{+1,+1}},  {{0,-1}},  {{+1,0}},  0,  1},
291 
292         // Bottom outset edge.
293         {{{0,0,1,0}},  {{+1,+1}},  {{-1,0}},  {{0,+1}},  0,  1},
294         {{{0,0,0,1}},  {{-1,+1}},  {{+1,0}},  {{0,+1}},  0,  1},
295 
296 
297         // Top-left corner.
298         {{{1,0,0,0}},  {{-1,-1}},  {{ 0,+1}},  {{-1, 0}},  0,  0},
299         {{{1,0,0,0}},  {{-1,-1}},  {{ 0,+1}},  {{+1, 0}},  1,  0},
300         {{{1,0,0,0}},  {{-1,-1}},  {{+1, 0}},  {{ 0,+1}},  1,  0},
301         {{{1,0,0,0}},  {{-1,-1}},  {{+1, 0}},  {{ 0,-1}},  0,  0},
302         {{{1,0,0,0}},  {{-1,-1}},  {{+kOctoOffset,0}},  {{-1,-1}},  0,  0},
303         {{{1,0,0,0}},  {{-1,-1}},  {{0,+kOctoOffset}},  {{-1,-1}},  0,  0},
304 
305         // Top-right corner.
306         {{{0,1,0,0}},  {{+1,-1}},  {{-1, 0}},  {{ 0,-1}},  0,  0},
307         {{{0,1,0,0}},  {{+1,-1}},  {{-1, 0}},  {{ 0,+1}},  1,  0},
308         {{{0,1,0,0}},  {{+1,-1}},  {{ 0,+1}},  {{-1, 0}},  1,  0},
309         {{{0,1,0,0}},  {{+1,-1}},  {{ 0,+1}},  {{+1, 0}},  0,  0},
310         {{{0,1,0,0}},  {{+1,-1}},  {{0,+kOctoOffset}},  {{+1,-1}},  0,  0},
311         {{{0,1,0,0}},  {{+1,-1}},  {{-kOctoOffset,0}},  {{+1,-1}},  0,  0},
312 
313         // Bottom-right corner.
314         {{{0,0,1,0}},  {{+1,+1}},  {{ 0,-1}},  {{+1, 0}},  0,  0},
315         {{{0,0,1,0}},  {{+1,+1}},  {{ 0,-1}},  {{-1, 0}},  1,  0},
316         {{{0,0,1,0}},  {{+1,+1}},  {{-1, 0}},  {{ 0,-1}},  1,  0},
317         {{{0,0,1,0}},  {{+1,+1}},  {{-1, 0}},  {{ 0,+1}},  0,  0},
318         {{{0,0,1,0}},  {{+1,+1}},  {{-kOctoOffset,0}},  {{+1,+1}},  0,  0},
319         {{{0,0,1,0}},  {{+1,+1}},  {{0,-kOctoOffset}},  {{+1,+1}},  0,  0},
320 
321         // Bottom-left corner.
322         {{{0,0,0,1}},  {{-1,+1}},  {{+1, 0}},  {{ 0,+1}},  0,  0},
323         {{{0,0,0,1}},  {{-1,+1}},  {{+1, 0}},  {{ 0,-1}},  1,  0},
324         {{{0,0,0,1}},  {{-1,+1}},  {{ 0,-1}},  {{+1, 0}},  1,  0},
325         {{{0,0,0,1}},  {{-1,+1}},  {{ 0,-1}},  {{-1, 0}},  0,  0},
326         {{{0,0,0,1}},  {{-1,+1}},  {{0,-kOctoOffset}},  {{-1,+1}},  0,  0},
327         {{{0,0,0,1}},  {{-1,+1}},  {{+kOctoOffset,0}},  {{-1,+1}},  0,  0}};
328 
329 GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
330 
331 static constexpr uint16_t kCoverageIndexData[] = {
332         // Inset octagon (solid coverage).
333         0, 1, 7,
334         1, 2, 7,
335         7, 2, 6,
336         2, 3, 6,
337         6, 3, 5,
338         3, 4, 5,
339 
340         // AA borders (linear coverage).
341         0, 1, 8, 1, 9, 8,
342         2, 3, 10, 3, 11, 10,
343         4, 5, 12, 5, 13, 12,
344         6, 7, 14, 7, 15, 14,
345 
346         // Top-left arc.
347         16, 17, 21,
348         17, 21, 18,
349         21, 18, 20,
350         18, 20, 19,
351 
352         // Top-right arc.
353         22, 23, 27,
354         23, 27, 24,
355         27, 24, 26,
356         24, 26, 25,
357 
358         // Bottom-right arc.
359         28, 29, 33,
360         29, 33, 30,
361         33, 30, 32,
362         30, 32, 31,
363 
364         // Bottom-left arc.
365         34, 35, 39,
366         35, 39, 36,
367         39, 36, 38,
368         36, 38, 37};
369 
370 GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
371 
372 class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)373     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
374         const auto& proc = args.fGP.cast<Processor>();
375         bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
376 
377         SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
378 
379         GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
380         varyings->emitAttributes(proc);
381         varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
382                                           GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
383 
384         // Emit the vertex shader.
385         GrGLSLVertexBuilder* v = args.fVertBuilder;
386 
387         // Unpack vertex attribs.
388         v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
389         v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
390         v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
391         v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
392         v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
393 
394         // Find the amount to bloat each edge for AA (in source space).
395         v->codeAppend("float2 pixellength = inversesqrt("
396                               "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
397         v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
398         v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
399                                            "abs(normalized_axis_dirs.zw));");
400         v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
401 
402         // Identify our radii.
403         v->codeAppend("float4 radii_and_neighbors = radii_selector"
404                               "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
405         v->codeAppend("float2 radii = radii_and_neighbors.xy;");
406         v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
407 
408         v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
409                           // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
410                           // or else opposite AA borders will overlap. Instead, fudge the size up to
411                           // the width of a coverage ramp, and then reduce total coverage to make
412                           // the rect appear more thin.
413         v->codeAppend(    "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
414         v->codeAppend(    "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
415                           // Set radii to zero to ensure we take the "linear coverage" codepath.
416                           // (The "coverage" variable only has effect in the linear codepath.)
417         v->codeAppend(    "radii = float2(0);");
418         v->codeAppend("}");
419 
420         v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
421                           // The radii are very small. Demote this arc to a sharp 90 degree corner.
422         v->codeAppend(    "radii = aa_bloatradius;");
423                           // Snap octagon vertices to the corner of the bounding box.
424         v->codeAppend(    "radius_outset = floor(abs(radius_outset)) * radius_outset;");
425         v->codeAppend(    "is_linear_coverage = 1;");
426         v->codeAppend("} else {");
427                           // Don't let radii get smaller than a pixel.
428         v->codeAppend(    "radii = clamp(radii, pixellength, 2 - pixellength);");
429         v->codeAppend(    "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
430                           // Don't let neighboring radii get closer together than 1/16 pixel.
431         v->codeAppend(    "float2 spacing = 2 - radii - neighbor_radii;");
432         v->codeAppend(    "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
433         v->codeAppend(    "radii -= extra_pad * .5;");
434         v->codeAppend("}");
435 
436         // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
437         // normalized [-1,-1,+1,+1] space.
438         v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
439         v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
440 
441         // Emit transforms.
442         GrShaderVar localCoord("", kFloat2_GrSLType);
443         if (proc.fFlags & Flags::kHasLocalCoords) {
444             v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
445                                                "local_rect.zw * (1 + vertexpos)) * .5;");
446             localCoord.set(kFloat2_GrSLType, "localcoord");
447         }
448         this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
449                              args.fFPCoordTransformHandler);
450 
451         // Transform to device space.
452         SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
453         v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
454         v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
455         gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
456 
457         // Setup interpolants for coverage.
458         GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
459         varyings->addVarying("arccoord", &arcCoord);
460         v->codeAppend("if (0 != is_linear_coverage) {");
461                            // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
462                            // interpolate linear coverage across y.
463         v->codeAppendf(    "%s.xy = float2(0, coverage);", arcCoord.vsOut());
464         v->codeAppend("} else {");
465                            // Find the normalized arc coordinates for our corner ellipse.
466                            // (i.e., the coordinate system where x^2 + y^2 == 1).
467         v->codeAppend(    "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
468                            // We are a corner piece: Interpolate the arc coordinates for coverage.
469                            // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
470                            // instructs the fragment shader to use linear coverage).
471         v->codeAppendf(    "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
472         if (!useHWDerivatives) {
473             // The gradient is order-1: Interpolate it across arccoord.zw.
474             v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
475             v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
476         }
477         v->codeAppend("}");
478 
479         // Emit the fragment shader.
480         GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
481 
482         f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
483         f->codeAppendf("half coverage;");
484         f->codeAppendf("if (0 == x_plus_1) {");
485         f->codeAppendf(    "coverage = half(y);");  // We are a non-arc pixel (linear coverage).
486         f->codeAppendf("} else {");
487         f->codeAppendf(    "float fn = x_plus_1 * (x_plus_1 - 2);");  // fn = (x+1)*(x-1) = x^2-1
488         f->codeAppendf(    "fn = fma(y,y, fn);");  // fn = x^2 + y^2 - 1
489         if (useHWDerivatives) {
490             f->codeAppendf("float fnwidth = fwidth(fn);");
491         } else {
492             // The gradient is interpolated across arccoord.zw.
493             f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
494             f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
495         }
496         f->codeAppendf(    "half d = half(fn/fnwidth);");
497         f->codeAppendf(    "coverage = clamp(.5 - d, 0, 1);");
498         f->codeAppendf("}");
499         f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
500     }
501 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor &,FPCoordTransformIter && transformIter)502     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
503                  FPCoordTransformIter&& transformIter) override {
504         this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
505     }
506 };
507 
508 // Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
509 // by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
510 struct MSAAVertex {
511     std::array<float, 4> fRadiiSelector;
512     std::array<float, 2> fCorner;
513     std::array<float, 2> fRadiusOutset;
514 };
515 
516 static constexpr MSAAVertex kMSAAVertexData[] = {
517         // Left edge. (Negative radii selector indicates this is not an arc section.)
518         {{{0,0,0,-1}},  {{-1,+1}},  {{0,-1}}},
519         {{{-1,0,0,0}},  {{-1,-1}},  {{0,+1}}},
520 
521         // Top edge.
522         {{{-1,0,0,0}},  {{-1,-1}},  {{+1,0}}},
523         {{{0,-1,0,0}},  {{+1,-1}},  {{-1,0}}},
524 
525         // Right edge.
526         {{{0,-1,0,0}},  {{+1,-1}},  {{0,+1}}},
527         {{{0,0,-1,0}},  {{+1,+1}},  {{0,-1}}},
528 
529         // Bottom edge.
530         {{{0,0,-1,0}},  {{+1,+1}},  {{-1,0}}},
531         {{{0,0,0,-1}},  {{-1,+1}},  {{+1,0}}},
532 
533         // Top-left corner.
534         {{{1,0,0,0}},  {{-1,-1}},  {{0,+1}}},
535         {{{1,0,0,0}},  {{-1,-1}},  {{0,+kOctoOffset}}},
536         {{{1,0,0,0}},  {{-1,-1}},  {{+1,0}}},
537         {{{1,0,0,0}},  {{-1,-1}},  {{+kOctoOffset,0}}},
538 
539         // Top-right corner.
540         {{{0,1,0,0}},  {{+1,-1}},  {{-1,0}}},
541         {{{0,1,0,0}},  {{+1,-1}},  {{-kOctoOffset,0}}},
542         {{{0,1,0,0}},  {{+1,-1}},  {{0,+1}}},
543         {{{0,1,0,0}},  {{+1,-1}},  {{0,+kOctoOffset}}},
544 
545         // Bottom-right corner.
546         {{{0,0,1,0}},  {{+1,+1}},  {{0,-1}}},
547         {{{0,0,1,0}},  {{+1,+1}},  {{0,-kOctoOffset}}},
548         {{{0,0,1,0}},  {{+1,+1}},  {{-1,0}}},
549         {{{0,0,1,0}},  {{+1,+1}},  {{-kOctoOffset,0}}},
550 
551         // Bottom-left corner.
552         {{{0,0,0,1}},  {{-1,+1}},  {{+1,0}}},
553         {{{0,0,0,1}},  {{-1,+1}},  {{+kOctoOffset,0}}},
554         {{{0,0,0,1}},  {{-1,+1}},  {{0,-1}}},
555         {{{0,0,0,1}},  {{-1,+1}},  {{0,-kOctoOffset}}}};
556 
557 GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
558 
559 static constexpr uint16_t kMSAAIndexData[] = {
560         // Inset octagon. (Full sample mask.)
561         0, 1, 2,
562         0, 2, 3,
563         0, 3, 6,
564         3, 4, 5,
565         3, 5, 6,
566         6, 7, 0,
567 
568         // Top-left arc. (Sample mask is set to the arc.)
569          8,  9, 10,
570          9, 11, 10,
571 
572         // Top-right arc.
573         12, 13, 14,
574         13, 15, 14,
575 
576         // Bottom-right arc.
577         16, 17, 18,
578         17, 19, 18,
579 
580         // Bottom-left arc.
581         20, 21, 22,
582         21, 23, 22};
583 
584 GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
585 
586 class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)587     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
588         const auto& proc = args.fGP.cast<Processor>();
589         bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
590         bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
591         bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
592         SkASSERT(useHWDerivatives == hasPerspective);
593 
594         SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
595 
596         // Emit the vertex shader.
597         GrGLSLVertexBuilder* v = args.fVertBuilder;
598 
599         GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
600         varyings->emitAttributes(proc);
601         varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
602                                           GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
603 
604         // Unpack vertex attribs.
605         v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
606         v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
607 
608         // Identify our radii.
609         v->codeAppend("float2 radii;");
610         v->codeAppend("radii.x = dot(radii_selector, radii_x);");
611         v->codeAppend("radii.y = dot(radii_selector, radii_y);");
612         v->codeAppendf("bool is_arc_section = (radii.x > 0);");
613         v->codeAppendf("radii = abs(radii);");
614 
615         // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
616         // [-1,-1,+1,+1] space.
617         v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
618 
619         // Emit transforms.
620         GrShaderVar localCoord("", kFloat2_GrSLType);
621         if (hasLocalCoords) {
622             v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
623                                                "local_rect.zw * (1 + vertexpos)) * .5;");
624             localCoord.set(kFloat2_GrSLType, "localcoord");
625         }
626         this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
627                              args.fFPCoordTransformHandler);
628 
629         // Transform to device space.
630         if (!hasPerspective) {
631             v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
632             v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
633             gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
634         } else {
635             v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
636             v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
637             gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
638         }
639 
640         // Determine normalized arc coordinates for the implicit function.
641         GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
642         varyings->addVarying("arccoord", &arcCoord);
643         v->codeAppendf("if (is_arc_section) {");
644         v->codeAppendf(    "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
645         if (!useHWDerivatives) {
646             // The gradient is order-1: Interpolate it across arccoord.zw.
647             // This doesn't work with perspective.
648             SkASSERT(!hasPerspective);
649             v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
650             v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
651                            arcCoord.vsOut(), arcCoord.vsOut());
652         }
653         v->codeAppendf("} else {");
654         if (useHWDerivatives) {
655             v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
656         } else {
657             v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
658         }
659         v->codeAppendf("}");
660 
661         // Emit the fragment shader.
662         GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
663 
664         f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
665 
666         // If x,y == 0, then we are drawing a triangle that does not track an arc.
667         f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
668         f->codeAppendf(    "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
669         if (GrAAType::kMSAA == proc.fAAType) {
670             using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
671             if (!useHWDerivatives) {
672                 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
673                 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
674             } else {
675                 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
676             }
677         } else {
678             f->codeAppendf("if (fn > 0) {");
679             f->codeAppendf(    "%s = half4(0);", args.fOutputCoverage);
680             f->codeAppendf("}");
681         }
682         f->codeAppendf("}");
683     }
684 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor &,FPCoordTransformIter && transformIter)685     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
686                  FPCoordTransformIter&& transformIter) override {
687         this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
688     }
689 };
690 
createGLSLInstance(const GrShaderCaps &) const691 GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
692         const GrShaderCaps&) const {
693     if (GrAAType::kCoverage != fAAType) {
694         return new MSAAImpl();
695     }
696     return new CoverageImpl();
697 }
698 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)699 void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
700     if (!fInstanceBuffer) {
701         return;  // Setup failed.
702     }
703 
704     sk_sp<const GrBuffer> indexBuffer, vertexBuffer;
705     int indexCount;
706 
707     if (GrAAType::kCoverage == fAAType) {
708         GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
709 
710         indexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
711                 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
712                 gCoverageIndexBufferKey);
713 
714         GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
715 
716         vertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
717                 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
718                 gCoverageVertexBufferKey);
719 
720         indexCount = SK_ARRAY_COUNT(kCoverageIndexData);
721     } else {
722         GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
723 
724         indexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
725                 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
726                 gMSAAIndexBufferKey);
727 
728         GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
729 
730         vertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
731                 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
732                 gMSAAVertexBufferKey);
733 
734         indexCount = SK_ARRAY_COUNT(kMSAAIndexData);
735     }
736 
737     if (!indexBuffer || !vertexBuffer) {
738         return;
739     }
740 
741     Processor* proc = flushState->allocator()->make<Processor>(fAAType, fFlags);
742     SkASSERT(proc->instanceStride() == (size_t)fInstanceStride);
743 
744     GrPipeline::InitArgs initArgs;
745     if (GrAAType::kMSAA == fAAType) {
746         initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
747     }
748     initArgs.fCaps = &flushState->caps();
749     initArgs.fDstProxy = flushState->drawOpArgs().fDstProxy;
750     initArgs.fOutputSwizzle = flushState->drawOpArgs().fOutputSwizzle;
751     auto clip = flushState->detachAppliedClip();
752     GrPipeline::FixedDynamicState* fixedDynamicState =
753         flushState->allocator()->make<GrPipeline::FixedDynamicState>(clip.scissorState().rect());
754     GrPipeline* pipeline = flushState->allocator()->make<GrPipeline>(initArgs,
755                                                                      std::move(fProcessors),
756                                                                      std::move(clip));
757 
758     GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
759     mesh->setIndexedInstanced(
760             std::move(indexBuffer), indexCount, fInstanceBuffer, fInstanceCount, fBaseInstance,
761             GrPrimitiveRestart::kNo);
762     mesh->setVertexData(std::move(vertexBuffer));
763     flushState->rtCommandBuffer()->draw(
764             *proc, *pipeline, fixedDynamicState, nullptr, mesh, 1, this->bounds());
765 }
766 
767 // Will the given corner look good if we use HW derivatives?
can_use_hw_derivatives_with_coverage(const Sk2f & devScale,const Sk2f & cornerRadii)768 static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
769     Sk2f devRadii = devScale * cornerRadii;
770     if (devRadii[1] < devRadii[0]) {
771         devRadii = SkNx_shuffle<1,0>(devRadii);
772     }
773     float minDevRadius = SkTMax(devRadii[0], 1.f);  // Shader clamps radius at a minimum of 1.
774     // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
775     // This threshold was arrived at subjevtively on an NVIDIA chip.
776     return minDevRadius * minDevRadius * 5 > devRadii[1];
777 }
778 
can_use_hw_derivatives_with_coverage(const Sk2f & devScale,const SkVector & cornerRadii)779 static bool can_use_hw_derivatives_with_coverage(
780         const Sk2f& devScale, const SkVector& cornerRadii) {
781     return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
782 }
783 
784 // Will the given round rect look good if we use HW derivatives?
can_use_hw_derivatives_with_coverage(const GrShaderCaps & shaderCaps,const SkMatrix & viewMatrix,const SkRRect & rrect)785 static bool can_use_hw_derivatives_with_coverage(
786         const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
787     if (!shaderCaps.shaderDerivativeSupport()) {
788         return false;
789     }
790 
791     Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
792     Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
793     Sk2f devScale = (x*x + y*y).sqrt();
794     switch (rrect.getType()) {
795         case SkRRect::kEmpty_Type:
796         case SkRRect::kRect_Type:
797             return true;
798 
799         case SkRRect::kOval_Type:
800         case SkRRect::kSimple_Type:
801             return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
802 
803         case SkRRect::kNinePatch_Type: {
804             Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
805             Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
806             Sk2f minRadii = Sk2f::Min(r0, r1);
807             Sk2f maxRadii = Sk2f::Max(r0, r1);
808             return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
809                    can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
810         }
811 
812         case SkRRect::kComplex_Type: {
813             for (int i = 0; i < 4; ++i) {
814                 auto corner = static_cast<SkRRect::Corner>(i);
815                 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
816                     return false;
817                 }
818             }
819             return true;
820         }
821     }
822     SK_ABORT("Invalid round rect type.");
823 }
824