blob: 27b8f54bc0e5edfd760d3da2ceca33ea96196a27 [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:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500178 static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, Flags flags) {
179 return arena->make<Processor>(aaType, flags);
180 }
181
182 const char* name() const override { return "GrFillRRectOp::Processor"; }
183
184 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
185 b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
186 }
187
188 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
189
190private:
191 friend class ::SkArenaAlloc; // for access to ctor
192
Chris Dalton0dffbab2019-03-27 13:08:50 -0600193 Processor(GrAAType aaType, Flags flags)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500194 : INHERITED(kGrFillRRectOp_Processor_ClassID)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600195 , fAAType(aaType)
196 , fFlags(flags) {
197 int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
198 this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
Chris Dalton133944a2018-11-16 23:30:29 -0500199
Chris Dalton0dffbab2019-03-27 13:08:50 -0600200 if (!(flags & Flags::kHasPerspective)) {
201 // Affine 2D transformation (float2x2 plus float2 translate).
202 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
203 fInstanceAttribs.emplace_back(
204 "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
205 } else {
206 // Perspective float3x3 transformation matrix.
207 fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
208 fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
209 fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
210 }
211 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
212 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
213 fColorAttrib = &fInstanceAttribs.push_back(
214 MakeColorAttribute("color", (flags & Flags::kWideColor)));
215 if (fFlags & Flags::kHasLocalCoords) {
216 fInstanceAttribs.emplace_back(
217 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
218 }
219 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
220
221 if (GrAAType::kMSAA == fAAType) {
222 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
223 }
224 }
225
Chris Dalton0dffbab2019-03-27 13:08:50 -0600226 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;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500240
241 typedef GrGeometryProcessor INHERITED;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600242};
243
244constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
245
246// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500247// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
248// edges. The Vertex struct tells the shader where to place its vertex within a normalized
249// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600250struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500251 std::array<float, 4> fRadiiSelector;
252 std::array<float, 2> fCorner;
253 std::array<float, 2> fRadiusOutset;
254 std::array<float, 2> fAABloatDirection;
255 float fCoverage;
256 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500257};
258
259// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
260// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
261// rectangles.
262static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
263
Chris Dalton0dffbab2019-03-27 13:08:50 -0600264static constexpr CoverageVertex kCoverageVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500265 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700266 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
267 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500268
269 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700270 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
271 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500272
273 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700274 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
275 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500276
277 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700278 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
279 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500280
281
282 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700283 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
284 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500285
286 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700287 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
288 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500289
290 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700291 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
292 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500293
294 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700295 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
296 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500297
298
299 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700300 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
301 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
302 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
303 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
304 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
305 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500306
307 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700308 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
309 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
310 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
311 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
312 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
313 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500314
315 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700316 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
317 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
318 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
319 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
320 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
321 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500322
323 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700324 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
325 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
326 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
327 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700328 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700329 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500330
Chris Dalton0dffbab2019-03-27 13:08:50 -0600331GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500332
Chris Dalton0dffbab2019-03-27 13:08:50 -0600333static constexpr uint16_t kCoverageIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500334 // Inset octagon (solid coverage).
335 0, 1, 7,
336 1, 2, 7,
337 7, 2, 6,
338 2, 3, 6,
339 6, 3, 5,
340 3, 4, 5,
341
342 // AA borders (linear coverage).
343 0, 1, 8, 1, 9, 8,
344 2, 3, 10, 3, 11, 10,
345 4, 5, 12, 5, 13, 12,
346 6, 7, 14, 7, 15, 14,
347
348 // Top-left arc.
349 16, 17, 21,
350 17, 21, 18,
351 21, 18, 20,
352 18, 20, 19,
353
354 // Top-right arc.
355 22, 23, 27,
356 23, 27, 24,
357 27, 24, 26,
358 24, 26, 25,
359
360 // Bottom-right arc.
361 28, 29, 33,
362 29, 33, 30,
363 33, 30, 32,
364 30, 32, 31,
365
366 // Bottom-left arc.
367 34, 35, 39,
368 35, 39, 36,
369 39, 36, 38,
370 36, 38, 37};
371
Chris Dalton0dffbab2019-03-27 13:08:50 -0600372GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500373
Greg Danielf793de12019-09-05 13:23:23 -0400374
375// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
376// by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
377struct MSAAVertex {
378 std::array<float, 4> fRadiiSelector;
379 std::array<float, 2> fCorner;
380 std::array<float, 2> fRadiusOutset;
381};
382
383static constexpr MSAAVertex kMSAAVertexData[] = {
384 // Left edge. (Negative radii selector indicates this is not an arc section.)
385 {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}},
386 {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
387
388 // Top edge.
389 {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
390 {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}},
391
392 // Right edge.
393 {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}},
394 {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}},
395
396 // Bottom edge.
397 {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}},
398 {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}},
399
400 // Top-left corner.
401 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
402 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}},
403 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
404 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}},
405
406 // Top-right corner.
407 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}},
408 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}},
409 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}},
410 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}},
411
412 // Bottom-right corner.
413 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}},
414 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}},
415 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}},
416 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}},
417
418 // Bottom-left corner.
419 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}},
420 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}},
421 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}},
422 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}};
423
424GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
425
426static constexpr uint16_t kMSAAIndexData[] = {
427 // Inset octagon. (Full sample mask.)
428 0, 1, 2,
429 0, 2, 3,
430 0, 3, 6,
431 3, 4, 5,
432 3, 5, 6,
433 6, 7, 0,
434
435 // Top-left arc. (Sample mask is set to the arc.)
436 8, 9, 10,
437 9, 11, 10,
438
439 // Top-right arc.
440 12, 13, 14,
441 13, 15, 14,
442
443 // Bottom-right arc.
444 16, 17, 18,
445 17, 19, 18,
446
447 // Bottom-left arc.
448 20, 21, 22,
449 21, 23, 22};
450
451GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
452
453void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
454 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
455 &fInstanceBuffer, &fBaseInstance)) {
456 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
457 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
458 }
459
460 if (GrAAType::kCoverage == fAAType) {
461 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
462
463 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
464 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
465 gCoverageIndexBufferKey);
466
467 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
468
469 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
470 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
471 gCoverageVertexBufferKey);
472
473 fIndexCount = SK_ARRAY_COUNT(kCoverageIndexData);
474 } else {
475 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
476
477 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
478 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
479 gMSAAIndexBufferKey);
480
481 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
482
483 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
484 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
485 gMSAAVertexBufferKey);
486
487 fIndexCount = SK_ARRAY_COUNT(kMSAAIndexData);
488 }
489}
490
Chris Dalton0dffbab2019-03-27 13:08:50 -0600491class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500492 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
493 const auto& proc = args.fGP.cast<Processor>();
494 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
495
Chris Dalton0dffbab2019-03-27 13:08:50 -0600496 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
497
Chris Dalton133944a2018-11-16 23:30:29 -0500498 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
499 varyings->emitAttributes(proc);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600500 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500501 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
502
503 // Emit the vertex shader.
504 GrGLSLVertexBuilder* v = args.fVertBuilder;
505
506 // Unpack vertex attribs.
507 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
508 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
509 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
510 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
511 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
512
513 // Find the amount to bloat each edge for AA (in source space).
514 v->codeAppend("float2 pixellength = inversesqrt("
515 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
516 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
517 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
518 "abs(normalized_axis_dirs.zw));");
519 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
520
521 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000522 v->codeAppend("float4 radii_and_neighbors = radii_selector"
523 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
524 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
525 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500526
527 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
528 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
529 // or else opposite AA borders will overlap. Instead, fudge the size up to
530 // the width of a coverage ramp, and then reduce total coverage to make
531 // the rect appear more thin.
532 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
533 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
534 // Set radii to zero to ensure we take the "linear coverage" codepath.
535 // (The "coverage" variable only has effect in the linear codepath.)
536 v->codeAppend( "radii = float2(0);");
537 v->codeAppend("}");
538
539 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
540 // The radii are very small. Demote this arc to a sharp 90 degree corner.
541 v->codeAppend( "radii = aa_bloatradius;");
542 // Snap octagon vertices to the corner of the bounding box.
543 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
544 v->codeAppend( "is_linear_coverage = 1;");
545 v->codeAppend("} else {");
Mike Reedd3efa992018-11-28 13:13:15 +0000546 // Don't let radii get smaller than a pixel.
Chris Dalton133944a2018-11-16 23:30:29 -0500547 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
Mike Reedd3efa992018-11-28 13:13:15 +0000548 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
549 // Don't let neighboring radii get closer together than 1/16 pixel.
550 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
551 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
552 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500553 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500554
555 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
556 // normalized [-1,-1,+1,+1] space.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700557 v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
558 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500559
560 // Emit transforms.
561 GrShaderVar localCoord("", kFloat2_GrSLType);
562 if (proc.fFlags & Flags::kHasLocalCoords) {
563 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
564 "local_rect.zw * (1 + vertexpos)) * .5;");
565 localCoord.set(kFloat2_GrSLType, "localcoord");
566 }
567 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
568 args.fFPCoordTransformHandler);
569
570 // Transform to device space.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600571 SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
Chris Dalton133944a2018-11-16 23:30:29 -0500572 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
573 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
574 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
575
576 // Setup interpolants for coverage.
577 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
578 varyings->addVarying("arccoord", &arcCoord);
579 v->codeAppend("if (0 != is_linear_coverage) {");
580 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
581 // interpolate linear coverage across y.
582 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
583 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700584 // Find the normalized arc coordinates for our corner ellipse.
585 // (i.e., the coordinate system where x^2 + y^2 == 1).
586 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500587 // We are a corner piece: Interpolate the arc coordinates for coverage.
588 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
589 // instructs the fragment shader to use linear coverage).
590 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
591 if (!useHWDerivatives) {
592 // The gradient is order-1: Interpolate it across arccoord.zw.
593 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
594 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
595 }
596 v->codeAppend("}");
597
598 // Emit the fragment shader.
599 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
600
601 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
602 f->codeAppendf("half coverage;");
603 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600604 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500605 f->codeAppendf("} else {");
606 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
607 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
608 if (useHWDerivatives) {
609 f->codeAppendf("float fnwidth = fwidth(fn);");
610 } else {
611 // The gradient is interpolated across arccoord.zw.
612 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
613 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
614 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500615 f->codeAppendf( "half d = half(fn/fnwidth);");
Chris Dalton133944a2018-11-16 23:30:29 -0500616 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
617 f->codeAppendf("}");
618 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
619 }
620
621 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
622 FPCoordTransformIter&& transformIter) override {
623 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
624 }
625};
626
Chris Dalton0dffbab2019-03-27 13:08:50 -0600627
628class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
629 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
630 const auto& proc = args.fGP.cast<Processor>();
631 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
632 bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
633 bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
634 SkASSERT(useHWDerivatives == hasPerspective);
635
636 SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
637
638 // Emit the vertex shader.
639 GrGLSLVertexBuilder* v = args.fVertBuilder;
640
641 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
642 varyings->emitAttributes(proc);
643 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
644 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
645
646 // Unpack vertex attribs.
647 v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
648 v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
649
650 // Identify our radii.
651 v->codeAppend("float2 radii;");
652 v->codeAppend("radii.x = dot(radii_selector, radii_x);");
653 v->codeAppend("radii.y = dot(radii_selector, radii_y);");
654 v->codeAppendf("bool is_arc_section = (radii.x > 0);");
655 v->codeAppendf("radii = abs(radii);");
656
657 // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
658 // [-1,-1,+1,+1] space.
659 v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
660
661 // Emit transforms.
662 GrShaderVar localCoord("", kFloat2_GrSLType);
663 if (hasLocalCoords) {
664 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
665 "local_rect.zw * (1 + vertexpos)) * .5;");
666 localCoord.set(kFloat2_GrSLType, "localcoord");
667 }
668 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
669 args.fFPCoordTransformHandler);
670
671 // Transform to device space.
672 if (!hasPerspective) {
673 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
674 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
675 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
676 } else {
677 v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
678 v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
679 gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
680 }
681
682 // Determine normalized arc coordinates for the implicit function.
683 GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
684 varyings->addVarying("arccoord", &arcCoord);
685 v->codeAppendf("if (is_arc_section) {");
686 v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
687 if (!useHWDerivatives) {
688 // The gradient is order-1: Interpolate it across arccoord.zw.
689 // This doesn't work with perspective.
690 SkASSERT(!hasPerspective);
691 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
692 v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
693 arcCoord.vsOut(), arcCoord.vsOut());
694 }
695 v->codeAppendf("} else {");
696 if (useHWDerivatives) {
697 v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
698 } else {
699 v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
700 }
701 v->codeAppendf("}");
702
703 // Emit the fragment shader.
704 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
705
706 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
707
708 // If x,y == 0, then we are drawing a triangle that does not track an arc.
709 f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
710 f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
711 if (GrAAType::kMSAA == proc.fAAType) {
712 using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
713 if (!useHWDerivatives) {
714 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
715 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
716 } else {
717 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
718 }
719 } else {
720 f->codeAppendf("if (fn > 0) {");
721 f->codeAppendf( "%s = half4(0);", args.fOutputCoverage);
722 f->codeAppendf("}");
723 }
724 f->codeAppendf("}");
725 }
726
727 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
728 FPCoordTransformIter&& transformIter) override {
729 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
730 }
731};
732
Chris Dalton82eb9e72019-03-21 14:26:39 -0600733GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
Chris Dalton133944a2018-11-16 23:30:29 -0500734 const GrShaderCaps&) const {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600735 if (GrAAType::kCoverage != fAAType) {
736 return new MSAAImpl();
737 }
738 return new CoverageImpl();
Chris Dalton133944a2018-11-16 23:30:29 -0500739}
740
Chris Dalton82eb9e72019-03-21 14:26:39 -0600741void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Greg Danielf793de12019-09-05 13:23:23 -0400742 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
Chris Dalton133944a2018-11-16 23:30:29 -0500743 return; // Setup failed.
744 }
745
Greg Daniel0b002e22019-08-12 13:25:36 -0400746 Processor* proc = flushState->allocator()->make<Processor>(fAAType, fFlags);
747 SkASSERT(proc->instanceStride() == (size_t)fInstanceStride);
Chris Dalton133944a2018-11-16 23:30:29 -0500748
749 GrPipeline::InitArgs initArgs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600750 if (GrAAType::kMSAA == fAAType) {
Chris Daltonbaa1b352019-04-03 12:03:00 -0600751 initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600752 }
Chris Dalton133944a2018-11-16 23:30:29 -0500753 initArgs.fCaps = &flushState->caps();
Greg Daniel524e28b2019-11-01 11:48:53 -0400754 initArgs.fDstProxyView = flushState->drawOpArgs().dstProxyView();
Robert Phillips405413f2019-10-04 10:39:28 -0400755 initArgs.fOutputSwizzle = flushState->drawOpArgs().outputSwizzle();
Chris Dalton8fa16252018-11-19 13:37:31 -0700756 auto clip = flushState->detachAppliedClip();
Robert Phillipsff2f3802019-11-18 16:36:54 -0500757 GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
758
759 if (clip.scissorState().enabled()) {
760 fixedDynamicState = flushState->allocator()->make<GrPipeline::FixedDynamicState>(
761 clip.scissorState().rect());
762 }
763
Greg Daniel0b002e22019-08-12 13:25:36 -0400764 GrPipeline* pipeline = flushState->allocator()->make<GrPipeline>(initArgs,
765 std::move(fProcessors),
766 std::move(clip));
Chris Dalton133944a2018-11-16 23:30:29 -0500767
Chris Dalton5e8cdfd2019-11-11 15:23:30 -0700768 GrProgramInfo programInfo(flushState->proxy()->numSamples(),
769 flushState->proxy()->numStencilSamples(),
Robert Phillips901aff02019-10-08 12:32:56 -0400770 flushState->drawOpArgs().origin(),
Robert Phillips67a625e2019-11-15 15:37:07 -0500771 pipeline,
772 proc,
Robert Phillips901aff02019-10-08 12:32:56 -0400773 fixedDynamicState,
Robert Phillipscea290f2019-11-06 11:21:03 -0500774 nullptr, 0,
775 GrPrimitiveType::kTriangles);
Robert Phillips901aff02019-10-08 12:32:56 -0400776
Greg Daniel0b002e22019-08-12 13:25:36 -0400777 GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
778 mesh->setIndexedInstanced(
Greg Danielf793de12019-09-05 13:23:23 -0400779 std::move(fIndexBuffer), fIndexCount, std::move(fInstanceBuffer), fInstanceCount,
780 fBaseInstance, GrPrimitiveRestart::kNo);
781 mesh->setVertexData(std::move(fVertexBuffer));
Robert Phillips901aff02019-10-08 12:32:56 -0400782 flushState->opsRenderPass()->draw(programInfo, mesh, 1, this->bounds());
Greg Danielf793de12019-09-05 13:23:23 -0400783 fIndexCount = 0;
Chris Dalton133944a2018-11-16 23:30:29 -0500784}
785
786// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600787static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500788 Sk2f devRadii = devScale * cornerRadii;
789 if (devRadii[1] < devRadii[0]) {
790 devRadii = SkNx_shuffle<1,0>(devRadii);
791 }
792 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
793 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
794 // This threshold was arrived at subjevtively on an NVIDIA chip.
795 return minDevRadius * minDevRadius * 5 > devRadii[1];
796}
797
Chris Dalton0dffbab2019-03-27 13:08:50 -0600798static bool can_use_hw_derivatives_with_coverage(
799 const Sk2f& devScale, const SkVector& cornerRadii) {
800 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500801}
802
803// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600804static bool can_use_hw_derivatives_with_coverage(
805 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500806 if (!shaderCaps.shaderDerivativeSupport()) {
807 return false;
808 }
809
810 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
811 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
812 Sk2f devScale = (x*x + y*y).sqrt();
813 switch (rrect.getType()) {
814 case SkRRect::kEmpty_Type:
815 case SkRRect::kRect_Type:
816 return true;
817
818 case SkRRect::kOval_Type:
819 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600820 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500821
822 case SkRRect::kNinePatch_Type: {
823 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
824 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
825 Sk2f minRadii = Sk2f::Min(r0, r1);
826 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600827 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
828 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500829 }
830
831 case SkRRect::kComplex_Type: {
832 for (int i = 0; i < 4; ++i) {
833 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600834 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500835 return false;
836 }
837 }
838 return true;
839 }
840 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600841 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500842}