blob: 026ea8931c633ece470c7ec1308ff9d5d0d3b5bd [file] [log] [blame]
Chris Dalton133944a2018-11-16 23:30:29 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/ops/GrFillRRectOp.h"
Chris Dalton133944a2018-11-16 23:30:29 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/private/GrRecordingContext.h"
11#include "src/core/SkRRectPriv.h"
12#include "src/gpu/GrCaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrMemoryPool.h"
14#include "src/gpu/GrOpFlushState.h"
Greg Daniel2d41d0d2019-08-26 11:08:51 -040015#include "src/gpu/GrOpsRenderPass.h"
Robert Phillips901aff02019-10-08 12:32:56 -040016#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#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"
Chris Dalton133944a2018-11-16 23:30:29 -050022
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.
Chris Dalton0dffbab2019-03-27 13:08:50 -060025static bool can_use_hw_derivatives_with_coverage(
26 const GrShaderCaps&, const SkMatrix&, const SkRRect&);
Chris Dalton133944a2018-11-16 23:30:29 -050027
Chris Dalton82eb9e72019-03-21 14:26:39 -060028std::unique_ptr<GrFillRRectOp> GrFillRRectOp::Make(
Chris Dalton0dffbab2019-03-27 13:08:50 -060029 GrRecordingContext* ctx, GrAAType aaType, const SkMatrix& viewMatrix, const SkRRect& rrect,
Robert Phillipsb97da532019-02-12 15:24:12 -050030 const GrCaps& caps, GrPaint&& paint) {
Chris Dalton133944a2018-11-16 23:30:29 -050031 if (!caps.instanceAttribSupport()) {
32 return nullptr;
33 }
34
Chris Dalton0dffbab2019-03-27 13:08:50 -060035 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) {
Chris Dalton8a64a442019-10-29 18:54:58 -060050 if (!caps.sampleLocationsSupport() || !caps.shaderCaps()->sampleMaskSupport() ||
51 caps.shaderCaps()->canOnlyUseSampleMaskWithStencil()) {
Chris Dalton0dffbab2019-03-27 13:08:50 -060052 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 }
Chris Dalton133944a2018-11-16 23:30:29 -050061 }
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
Chris Dalton0dffbab2019-03-27 13:08:50 -060072 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
97GrFillRRectOp::GrFillRRectOp(
98 GrAAType aaType, const SkRRect& rrect, Flags flags,
99 const SkMatrix& totalShapeMatrix, GrPaint&& paint, 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());
Greg Daniel5faf4742019-10-01 15:14:44 -0400107 this->setBounds(devBounds, GrOp::HasAABloat::kYes, GrOp::IsHairline::kNo);
Chris Dalton133944a2018-11-16 23:30:29 -0500108
109 // Write the matrix attribs.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600110 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 }
Chris Dalton133944a2018-11-16 23:30:29 -0500121
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);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600125 (radiiX * (2/rrect.width())).store(this->appendInstanceData<float>(4));
126 (radiiY * (2/rrect.height())).store(this->appendInstanceData<float>(4));
Chris Dalton133944a2018-11-16 23:30:29 -0500127
128 // We will write the color and local rect attribs during finalize().
129}
130
Chris Dalton6ce447a2019-06-23 18:07:38 -0600131GrProcessorSet::Analysis GrFillRRectOp::finalize(
132 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
133 GrClampType clampType) {
Chris Dalton133944a2018-11-16 23:30:29 -0500134 SkASSERT(1 == fInstanceCount);
135
136 SkPMColor4f overrideColor;
137 const GrProcessorSet::Analysis& analysis = fProcessors.finalize(
Chris Daltonb8fff0d2019-03-05 10:11:58 -0700138
139 fOriginalColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
Chris Dalton6ce447a2019-06-23 18:07:38 -0600140 &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType,
141 &overrideColor);
Chris Dalton133944a2018-11-16 23:30:29 -0500142
143 // Finish writing the instance attribs.
Brian Osman5105d682019-02-13 16:06:14 -0500144 SkPMColor4f finalColor = analysis.inputColorIsOverridden() ? overrideColor : fOriginalColor;
145 if (!SkPMColor4fFitsInBytes(finalColor)) {
146 fFlags |= Flags::kWideColor;
147 uint32_t halfColor[2];
148 SkFloatToHalf_finite_ftz(Sk4f::Load(finalColor.vec())).store(&halfColor);
149 this->writeInstanceData(halfColor[0], halfColor[1]);
150 } else {
151 this->writeInstanceData(finalColor.toBytes_RGBA());
152 }
153
Chris Dalton133944a2018-11-16 23:30:29 -0500154 if (analysis.usesLocalCoords()) {
155 this->writeInstanceData(fLocalRect);
156 fFlags |= Flags::kHasLocalCoords;
157 }
158 fInstanceStride = fInstanceData.count();
159
Chris Dalton4b62aed2019-01-15 11:53:00 -0700160 return analysis;
Chris Dalton133944a2018-11-16 23:30:29 -0500161}
162
Chris Dalton82eb9e72019-03-21 14:26:39 -0600163GrDrawOp::CombineResult GrFillRRectOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
164 const auto& that = *op->cast<GrFillRRectOp>();
Chris Dalton133944a2018-11-16 23:30:29 -0500165 if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
166 fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
167 return CombineResult::kCannotCombine;
168 }
169
170 fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
171 fInstanceCount += that.fInstanceCount;
172 SkASSERT(fInstanceStride == that.fInstanceStride);
173 return CombineResult::kMerged;
174}
175
Chris Dalton0dffbab2019-03-27 13:08:50 -0600176class GrFillRRectOp::Processor : public GrGeometryProcessor {
177public:
178 Processor(GrAAType aaType, Flags flags)
179 : GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID)
180 , fAAType(aaType)
181 , fFlags(flags) {
182 int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
183 this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
Chris Dalton133944a2018-11-16 23:30:29 -0500184
Chris Dalton0dffbab2019-03-27 13:08:50 -0600185 if (!(flags & Flags::kHasPerspective)) {
186 // Affine 2D transformation (float2x2 plus float2 translate).
187 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
188 fInstanceAttribs.emplace_back(
189 "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
190 } else {
191 // Perspective float3x3 transformation matrix.
192 fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
193 fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
194 fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
195 }
196 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
197 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
198 fColorAttrib = &fInstanceAttribs.push_back(
199 MakeColorAttribute("color", (flags & Flags::kWideColor)));
200 if (fFlags & Flags::kHasLocalCoords) {
201 fInstanceAttribs.emplace_back(
202 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
203 }
204 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
205
206 if (GrAAType::kMSAA == fAAType) {
207 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
208 }
209 }
210
211 const char* name() const override { return "GrFillRRectOp::Processor"; }
212
213 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
214 b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
215 }
216
217 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
218
219private:
220 static constexpr Attribute kVertexAttribs[] = {
221 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
222 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
223 // Coverage only.
224 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
225
226 const GrAAType fAAType;
227 const Flags fFlags;
228
229 SkSTArray<6, Attribute> fInstanceAttribs;
230 const Attribute* fColorAttrib;
231
232 class CoverageImpl;
233 class MSAAImpl;
234};
235
236constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
237
238// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500239// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
240// edges. The Vertex struct tells the shader where to place its vertex within a normalized
241// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600242struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500243 std::array<float, 4> fRadiiSelector;
244 std::array<float, 2> fCorner;
245 std::array<float, 2> fRadiusOutset;
246 std::array<float, 2> fAABloatDirection;
247 float fCoverage;
248 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500249};
250
251// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
252// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
253// rectangles.
254static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
255
Chris Dalton0dffbab2019-03-27 13:08:50 -0600256static constexpr CoverageVertex kCoverageVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500257 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700258 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
259 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500260
261 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700262 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
263 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500264
265 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700266 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
267 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500268
269 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700270 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
271 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500272
273
274 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700275 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
276 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500277
278 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700279 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
280 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500281
282 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700283 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
284 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500285
286 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700287 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
288 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500289
290
291 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700292 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
293 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
294 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
295 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
296 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
297 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500298
299 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700300 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
301 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
302 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
303 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
304 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
305 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500306
307 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700308 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
309 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
310 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
311 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
312 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
313 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500314
315 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700316 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
317 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
318 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
319 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700320 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700321 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500322
Chris Dalton0dffbab2019-03-27 13:08:50 -0600323GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500324
Chris Dalton0dffbab2019-03-27 13:08:50 -0600325static constexpr uint16_t kCoverageIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500326 // Inset octagon (solid coverage).
327 0, 1, 7,
328 1, 2, 7,
329 7, 2, 6,
330 2, 3, 6,
331 6, 3, 5,
332 3, 4, 5,
333
334 // AA borders (linear coverage).
335 0, 1, 8, 1, 9, 8,
336 2, 3, 10, 3, 11, 10,
337 4, 5, 12, 5, 13, 12,
338 6, 7, 14, 7, 15, 14,
339
340 // Top-left arc.
341 16, 17, 21,
342 17, 21, 18,
343 21, 18, 20,
344 18, 20, 19,
345
346 // Top-right arc.
347 22, 23, 27,
348 23, 27, 24,
349 27, 24, 26,
350 24, 26, 25,
351
352 // Bottom-right arc.
353 28, 29, 33,
354 29, 33, 30,
355 33, 30, 32,
356 30, 32, 31,
357
358 // Bottom-left arc.
359 34, 35, 39,
360 35, 39, 36,
361 39, 36, 38,
362 36, 38, 37};
363
Chris Dalton0dffbab2019-03-27 13:08:50 -0600364GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500365
Greg Danielf793de12019-09-05 13:23:23 -0400366
367// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
368// by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
369struct MSAAVertex {
370 std::array<float, 4> fRadiiSelector;
371 std::array<float, 2> fCorner;
372 std::array<float, 2> fRadiusOutset;
373};
374
375static constexpr MSAAVertex kMSAAVertexData[] = {
376 // Left edge. (Negative radii selector indicates this is not an arc section.)
377 {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}},
378 {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
379
380 // Top edge.
381 {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
382 {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}},
383
384 // Right edge.
385 {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}},
386 {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}},
387
388 // Bottom edge.
389 {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}},
390 {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}},
391
392 // Top-left corner.
393 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
394 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}},
395 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
396 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}},
397
398 // Top-right corner.
399 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}},
400 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}},
401 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}},
402 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}},
403
404 // Bottom-right corner.
405 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}},
406 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}},
407 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}},
408 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}},
409
410 // Bottom-left corner.
411 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}},
412 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}},
413 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}},
414 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}};
415
416GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
417
418static constexpr uint16_t kMSAAIndexData[] = {
419 // Inset octagon. (Full sample mask.)
420 0, 1, 2,
421 0, 2, 3,
422 0, 3, 6,
423 3, 4, 5,
424 3, 5, 6,
425 6, 7, 0,
426
427 // Top-left arc. (Sample mask is set to the arc.)
428 8, 9, 10,
429 9, 11, 10,
430
431 // Top-right arc.
432 12, 13, 14,
433 13, 15, 14,
434
435 // Bottom-right arc.
436 16, 17, 18,
437 17, 19, 18,
438
439 // Bottom-left arc.
440 20, 21, 22,
441 21, 23, 22};
442
443GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
444
445void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
446 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
447 &fInstanceBuffer, &fBaseInstance)) {
448 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
449 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
450 }
451
452 if (GrAAType::kCoverage == fAAType) {
453 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
454
455 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
456 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
457 gCoverageIndexBufferKey);
458
459 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
460
461 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
462 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
463 gCoverageVertexBufferKey);
464
465 fIndexCount = SK_ARRAY_COUNT(kCoverageIndexData);
466 } else {
467 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
468
469 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
470 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
471 gMSAAIndexBufferKey);
472
473 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
474
475 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
476 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
477 gMSAAVertexBufferKey);
478
479 fIndexCount = SK_ARRAY_COUNT(kMSAAIndexData);
480 }
481}
482
Chris Dalton0dffbab2019-03-27 13:08:50 -0600483class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500484 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
485 const auto& proc = args.fGP.cast<Processor>();
486 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
487
Chris Dalton0dffbab2019-03-27 13:08:50 -0600488 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
489
Chris Dalton133944a2018-11-16 23:30:29 -0500490 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
491 varyings->emitAttributes(proc);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600492 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500493 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
494
495 // Emit the vertex shader.
496 GrGLSLVertexBuilder* v = args.fVertBuilder;
497
498 // Unpack vertex attribs.
499 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
500 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
501 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
502 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
503 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
504
505 // Find the amount to bloat each edge for AA (in source space).
506 v->codeAppend("float2 pixellength = inversesqrt("
507 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
508 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
509 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
510 "abs(normalized_axis_dirs.zw));");
511 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
512
513 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000514 v->codeAppend("float4 radii_and_neighbors = radii_selector"
515 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
516 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
517 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500518
519 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
520 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
521 // or else opposite AA borders will overlap. Instead, fudge the size up to
522 // the width of a coverage ramp, and then reduce total coverage to make
523 // the rect appear more thin.
524 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
525 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
526 // Set radii to zero to ensure we take the "linear coverage" codepath.
527 // (The "coverage" variable only has effect in the linear codepath.)
528 v->codeAppend( "radii = float2(0);");
529 v->codeAppend("}");
530
531 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
532 // The radii are very small. Demote this arc to a sharp 90 degree corner.
533 v->codeAppend( "radii = aa_bloatradius;");
534 // Snap octagon vertices to the corner of the bounding box.
535 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
536 v->codeAppend( "is_linear_coverage = 1;");
537 v->codeAppend("} else {");
Mike Reedd3efa992018-11-28 13:13:15 +0000538 // Don't let radii get smaller than a pixel.
Chris Dalton133944a2018-11-16 23:30:29 -0500539 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
Mike Reedd3efa992018-11-28 13:13:15 +0000540 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
541 // Don't let neighboring radii get closer together than 1/16 pixel.
542 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
543 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
544 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500545 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500546
547 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
548 // normalized [-1,-1,+1,+1] space.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700549 v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
550 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500551
552 // Emit transforms.
553 GrShaderVar localCoord("", kFloat2_GrSLType);
554 if (proc.fFlags & Flags::kHasLocalCoords) {
555 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
556 "local_rect.zw * (1 + vertexpos)) * .5;");
557 localCoord.set(kFloat2_GrSLType, "localcoord");
558 }
559 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
560 args.fFPCoordTransformHandler);
561
562 // Transform to device space.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600563 SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
Chris Dalton133944a2018-11-16 23:30:29 -0500564 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
565 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
566 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
567
568 // Setup interpolants for coverage.
569 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
570 varyings->addVarying("arccoord", &arcCoord);
571 v->codeAppend("if (0 != is_linear_coverage) {");
572 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
573 // interpolate linear coverage across y.
574 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
575 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700576 // Find the normalized arc coordinates for our corner ellipse.
577 // (i.e., the coordinate system where x^2 + y^2 == 1).
578 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500579 // We are a corner piece: Interpolate the arc coordinates for coverage.
580 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
581 // instructs the fragment shader to use linear coverage).
582 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
583 if (!useHWDerivatives) {
584 // The gradient is order-1: Interpolate it across arccoord.zw.
585 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
586 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
587 }
588 v->codeAppend("}");
589
590 // Emit the fragment shader.
591 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
592
593 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
594 f->codeAppendf("half coverage;");
595 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600596 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500597 f->codeAppendf("} else {");
598 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
599 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
600 if (useHWDerivatives) {
601 f->codeAppendf("float fnwidth = fwidth(fn);");
602 } else {
603 // The gradient is interpolated across arccoord.zw.
604 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
605 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
606 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500607 f->codeAppendf( "half d = half(fn/fnwidth);");
Chris Dalton133944a2018-11-16 23:30:29 -0500608 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
609 f->codeAppendf("}");
610 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
611 }
612
613 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
614 FPCoordTransformIter&& transformIter) override {
615 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
616 }
617};
618
Chris Dalton0dffbab2019-03-27 13:08:50 -0600619
620class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
621 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
622 const auto& proc = args.fGP.cast<Processor>();
623 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
624 bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
625 bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
626 SkASSERT(useHWDerivatives == hasPerspective);
627
628 SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
629
630 // Emit the vertex shader.
631 GrGLSLVertexBuilder* v = args.fVertBuilder;
632
633 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
634 varyings->emitAttributes(proc);
635 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
636 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
637
638 // Unpack vertex attribs.
639 v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
640 v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
641
642 // Identify our radii.
643 v->codeAppend("float2 radii;");
644 v->codeAppend("radii.x = dot(radii_selector, radii_x);");
645 v->codeAppend("radii.y = dot(radii_selector, radii_y);");
646 v->codeAppendf("bool is_arc_section = (radii.x > 0);");
647 v->codeAppendf("radii = abs(radii);");
648
649 // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
650 // [-1,-1,+1,+1] space.
651 v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
652
653 // Emit transforms.
654 GrShaderVar localCoord("", kFloat2_GrSLType);
655 if (hasLocalCoords) {
656 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
657 "local_rect.zw * (1 + vertexpos)) * .5;");
658 localCoord.set(kFloat2_GrSLType, "localcoord");
659 }
660 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
661 args.fFPCoordTransformHandler);
662
663 // Transform to device space.
664 if (!hasPerspective) {
665 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
666 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
667 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
668 } else {
669 v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
670 v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
671 gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
672 }
673
674 // Determine normalized arc coordinates for the implicit function.
675 GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
676 varyings->addVarying("arccoord", &arcCoord);
677 v->codeAppendf("if (is_arc_section) {");
678 v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
679 if (!useHWDerivatives) {
680 // The gradient is order-1: Interpolate it across arccoord.zw.
681 // This doesn't work with perspective.
682 SkASSERT(!hasPerspective);
683 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
684 v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
685 arcCoord.vsOut(), arcCoord.vsOut());
686 }
687 v->codeAppendf("} else {");
688 if (useHWDerivatives) {
689 v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
690 } else {
691 v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
692 }
693 v->codeAppendf("}");
694
695 // Emit the fragment shader.
696 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
697
698 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
699
700 // If x,y == 0, then we are drawing a triangle that does not track an arc.
701 f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
702 f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
703 if (GrAAType::kMSAA == proc.fAAType) {
704 using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
705 if (!useHWDerivatives) {
706 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
707 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
708 } else {
709 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
710 }
711 } else {
712 f->codeAppendf("if (fn > 0) {");
713 f->codeAppendf( "%s = half4(0);", args.fOutputCoverage);
714 f->codeAppendf("}");
715 }
716 f->codeAppendf("}");
717 }
718
719 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
720 FPCoordTransformIter&& transformIter) override {
721 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
722 }
723};
724
Chris Dalton82eb9e72019-03-21 14:26:39 -0600725GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
Chris Dalton133944a2018-11-16 23:30:29 -0500726 const GrShaderCaps&) const {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600727 if (GrAAType::kCoverage != fAAType) {
728 return new MSAAImpl();
729 }
730 return new CoverageImpl();
Chris Dalton133944a2018-11-16 23:30:29 -0500731}
732
Chris Dalton82eb9e72019-03-21 14:26:39 -0600733void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Greg Danielf793de12019-09-05 13:23:23 -0400734 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
Chris Dalton133944a2018-11-16 23:30:29 -0500735 return; // Setup failed.
736 }
737
Greg Daniel0b002e22019-08-12 13:25:36 -0400738 Processor* proc = flushState->allocator()->make<Processor>(fAAType, fFlags);
739 SkASSERT(proc->instanceStride() == (size_t)fInstanceStride);
Chris Dalton133944a2018-11-16 23:30:29 -0500740
741 GrPipeline::InitArgs initArgs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600742 if (GrAAType::kMSAA == fAAType) {
Chris Daltonbaa1b352019-04-03 12:03:00 -0600743 initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600744 }
Chris Dalton133944a2018-11-16 23:30:29 -0500745 initArgs.fCaps = &flushState->caps();
Robert Phillips405413f2019-10-04 10:39:28 -0400746 initArgs.fDstProxy = flushState->drawOpArgs().dstProxy();
747 initArgs.fOutputSwizzle = flushState->drawOpArgs().outputSwizzle();
Chris Dalton8fa16252018-11-19 13:37:31 -0700748 auto clip = flushState->detachAppliedClip();
Greg Daniel0b002e22019-08-12 13:25:36 -0400749 GrPipeline::FixedDynamicState* fixedDynamicState =
750 flushState->allocator()->make<GrPipeline::FixedDynamicState>(clip.scissorState().rect());
751 GrPipeline* pipeline = flushState->allocator()->make<GrPipeline>(initArgs,
752 std::move(fProcessors),
753 std::move(clip));
Chris Dalton133944a2018-11-16 23:30:29 -0500754
Robert Phillips901aff02019-10-08 12:32:56 -0400755 GrProgramInfo programInfo(flushState->drawOpArgs().numSamples(),
756 flushState->drawOpArgs().origin(),
757 *pipeline,
758 *proc,
759 fixedDynamicState,
Robert Phillips2d8a95e2019-10-10 12:50:22 -0400760 nullptr, 0);
Robert Phillips901aff02019-10-08 12:32:56 -0400761
Greg Daniel0b002e22019-08-12 13:25:36 -0400762 GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
763 mesh->setIndexedInstanced(
Greg Danielf793de12019-09-05 13:23:23 -0400764 std::move(fIndexBuffer), fIndexCount, std::move(fInstanceBuffer), fInstanceCount,
765 fBaseInstance, GrPrimitiveRestart::kNo);
766 mesh->setVertexData(std::move(fVertexBuffer));
Robert Phillips901aff02019-10-08 12:32:56 -0400767 flushState->opsRenderPass()->draw(programInfo, mesh, 1, this->bounds());
Greg Danielf793de12019-09-05 13:23:23 -0400768 fIndexCount = 0;
Chris Dalton133944a2018-11-16 23:30:29 -0500769}
770
771// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600772static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500773 Sk2f devRadii = devScale * cornerRadii;
774 if (devRadii[1] < devRadii[0]) {
775 devRadii = SkNx_shuffle<1,0>(devRadii);
776 }
777 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
778 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
779 // This threshold was arrived at subjevtively on an NVIDIA chip.
780 return minDevRadius * minDevRadius * 5 > devRadii[1];
781}
782
Chris Dalton0dffbab2019-03-27 13:08:50 -0600783static bool can_use_hw_derivatives_with_coverage(
784 const Sk2f& devScale, const SkVector& cornerRadii) {
785 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500786}
787
788// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600789static bool can_use_hw_derivatives_with_coverage(
790 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500791 if (!shaderCaps.shaderDerivativeSupport()) {
792 return false;
793 }
794
795 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
796 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
797 Sk2f devScale = (x*x + y*y).sqrt();
798 switch (rrect.getType()) {
799 case SkRRect::kEmpty_Type:
800 case SkRRect::kRect_Type:
801 return true;
802
803 case SkRRect::kOval_Type:
804 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600805 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500806
807 case SkRRect::kNinePatch_Type: {
808 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
809 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
810 Sk2f minRadii = Sk2f::Min(r0, r1);
811 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600812 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
813 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500814 }
815
816 case SkRRect::kComplex_Type: {
817 for (int i = 0; i < 4; ++i) {
818 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600819 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500820 return false;
821 }
822 }
823 return true;
824 }
825 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600826 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500827}