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