blob: a8cf7fbea50c2799d22ae2fdbe9aa589991c1b43 [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
Robert Phillips8053c972019-11-21 10:44:53 -050097GrFillRRectOp::GrFillRRectOp(GrAAType aaType, const SkRRect& rrect, Flags flags,
98 const SkMatrix& totalShapeMatrix, GrPaint&& paint,
99 const SkRect& devBounds)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600100 : 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 fOriginalColor, GrProcessorAnalysisCoverage::kSingleChannel, clip,
Chris Dalton6ce447a2019-06-23 18:07:38 -0600139 &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType,
140 &overrideColor);
Chris Dalton133944a2018-11-16 23:30:29 -0500141
142 // Finish writing the instance attribs.
Brian Osman5105d682019-02-13 16:06:14 -0500143 SkPMColor4f finalColor = analysis.inputColorIsOverridden() ? overrideColor : fOriginalColor;
144 if (!SkPMColor4fFitsInBytes(finalColor)) {
145 fFlags |= Flags::kWideColor;
146 uint32_t halfColor[2];
147 SkFloatToHalf_finite_ftz(Sk4f::Load(finalColor.vec())).store(&halfColor);
148 this->writeInstanceData(halfColor[0], halfColor[1]);
149 } else {
150 this->writeInstanceData(finalColor.toBytes_RGBA());
151 }
152
Chris Dalton133944a2018-11-16 23:30:29 -0500153 if (analysis.usesLocalCoords()) {
154 this->writeInstanceData(fLocalRect);
155 fFlags |= Flags::kHasLocalCoords;
156 }
157 fInstanceStride = fInstanceData.count();
158
Chris Dalton4b62aed2019-01-15 11:53:00 -0700159 return analysis;
Chris Dalton133944a2018-11-16 23:30:29 -0500160}
161
Chris Dalton82eb9e72019-03-21 14:26:39 -0600162GrDrawOp::CombineResult GrFillRRectOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
163 const auto& that = *op->cast<GrFillRRectOp>();
Chris Dalton133944a2018-11-16 23:30:29 -0500164 if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
165 fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
166 return CombineResult::kCannotCombine;
167 }
168
169 fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
170 fInstanceCount += that.fInstanceCount;
171 SkASSERT(fInstanceStride == that.fInstanceStride);
172 return CombineResult::kMerged;
173}
174
Chris Dalton0dffbab2019-03-27 13:08:50 -0600175class GrFillRRectOp::Processor : public GrGeometryProcessor {
176public:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500177 static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, Flags flags) {
178 return arena->make<Processor>(aaType, flags);
179 }
180
Robert Phillips8053c972019-11-21 10:44:53 -0500181 const char* name() const final { return "GrFillRRectOp::Processor"; }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500182
Robert Phillips8053c972019-11-21 10:44:53 -0500183 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const final {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500184 b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
185 }
186
Robert Phillips8053c972019-11-21 10:44:53 -0500187 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500188
189private:
190 friend class ::SkArenaAlloc; // for access to ctor
191
Chris Dalton0dffbab2019-03-27 13:08:50 -0600192 Processor(GrAAType aaType, Flags flags)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500193 : INHERITED(kGrFillRRectOp_Processor_ClassID)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600194 , fAAType(aaType)
195 , fFlags(flags) {
196 int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
197 this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
Chris Dalton133944a2018-11-16 23:30:29 -0500198
Chris Dalton0dffbab2019-03-27 13:08:50 -0600199 if (!(flags & Flags::kHasPerspective)) {
200 // Affine 2D transformation (float2x2 plus float2 translate).
201 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
202 fInstanceAttribs.emplace_back(
203 "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
204 } else {
205 // Perspective float3x3 transformation matrix.
206 fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
207 fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
208 fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
209 }
210 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
211 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
212 fColorAttrib = &fInstanceAttribs.push_back(
213 MakeColorAttribute("color", (flags & Flags::kWideColor)));
214 if (fFlags & Flags::kHasLocalCoords) {
215 fInstanceAttribs.emplace_back(
216 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
217 }
218 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
219
220 if (GrAAType::kMSAA == fAAType) {
221 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
222 }
223 }
224
Chris Dalton0dffbab2019-03-27 13:08:50 -0600225 static constexpr Attribute kVertexAttribs[] = {
226 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
227 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
228 // Coverage only.
229 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
230
231 const GrAAType fAAType;
232 const Flags fFlags;
233
234 SkSTArray<6, Attribute> fInstanceAttribs;
235 const Attribute* fColorAttrib;
236
237 class CoverageImpl;
238 class MSAAImpl;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500239
240 typedef GrGeometryProcessor INHERITED;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600241};
242
243constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
244
245// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500246// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
247// edges. The Vertex struct tells the shader where to place its vertex within a normalized
248// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600249struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500250 std::array<float, 4> fRadiiSelector;
251 std::array<float, 2> fCorner;
252 std::array<float, 2> fRadiusOutset;
253 std::array<float, 2> fAABloatDirection;
254 float fCoverage;
255 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500256};
257
258// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
259// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
260// rectangles.
261static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
262
Chris Dalton0dffbab2019-03-27 13:08:50 -0600263static constexpr CoverageVertex kCoverageVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500264 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700265 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
266 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500267
268 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700269 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
270 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500271
272 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700273 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
274 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500275
276 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700277 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
278 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500279
280
281 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700282 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
283 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500284
285 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700286 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
287 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500288
289 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700290 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
291 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500292
293 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700294 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
295 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500296
297
298 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700299 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
300 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
301 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
302 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
303 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
304 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500305
306 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700307 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
308 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
309 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
310 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
311 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
312 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500313
314 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700315 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
316 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
317 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
318 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
319 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
320 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500321
322 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700323 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
324 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
325 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
326 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700327 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700328 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500329
Chris Dalton0dffbab2019-03-27 13:08:50 -0600330GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500331
Chris Dalton0dffbab2019-03-27 13:08:50 -0600332static constexpr uint16_t kCoverageIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500333 // Inset octagon (solid coverage).
334 0, 1, 7,
335 1, 2, 7,
336 7, 2, 6,
337 2, 3, 6,
338 6, 3, 5,
339 3, 4, 5,
340
341 // AA borders (linear coverage).
342 0, 1, 8, 1, 9, 8,
343 2, 3, 10, 3, 11, 10,
344 4, 5, 12, 5, 13, 12,
345 6, 7, 14, 7, 15, 14,
346
347 // Top-left arc.
348 16, 17, 21,
349 17, 21, 18,
350 21, 18, 20,
351 18, 20, 19,
352
353 // Top-right arc.
354 22, 23, 27,
355 23, 27, 24,
356 27, 24, 26,
357 24, 26, 25,
358
359 // Bottom-right arc.
360 28, 29, 33,
361 29, 33, 30,
362 33, 30, 32,
363 30, 32, 31,
364
365 // Bottom-left arc.
366 34, 35, 39,
367 35, 39, 36,
368 39, 36, 38,
369 36, 38, 37};
370
Chris Dalton0dffbab2019-03-27 13:08:50 -0600371GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500372
Greg Danielf793de12019-09-05 13:23:23 -0400373
374// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
375// by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
376struct MSAAVertex {
377 std::array<float, 4> fRadiiSelector;
378 std::array<float, 2> fCorner;
379 std::array<float, 2> fRadiusOutset;
380};
381
382static constexpr MSAAVertex kMSAAVertexData[] = {
383 // Left edge. (Negative radii selector indicates this is not an arc section.)
384 {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}},
385 {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
386
387 // Top edge.
388 {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
389 {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}},
390
391 // Right edge.
392 {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}},
393 {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}},
394
395 // Bottom edge.
396 {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}},
397 {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}},
398
399 // Top-left corner.
400 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
401 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}},
402 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
403 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}},
404
405 // Top-right corner.
406 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}},
407 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}},
408 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}},
409 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}},
410
411 // Bottom-right corner.
412 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}},
413 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}},
414 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}},
415 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}},
416
417 // Bottom-left corner.
418 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}},
419 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}},
420 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}},
421 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}};
422
423GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
424
425static constexpr uint16_t kMSAAIndexData[] = {
426 // Inset octagon. (Full sample mask.)
427 0, 1, 2,
428 0, 2, 3,
429 0, 3, 6,
430 3, 4, 5,
431 3, 5, 6,
432 6, 7, 0,
433
434 // Top-left arc. (Sample mask is set to the arc.)
435 8, 9, 10,
436 9, 11, 10,
437
438 // Top-right arc.
439 12, 13, 14,
440 13, 15, 14,
441
442 // Bottom-right arc.
443 16, 17, 18,
444 17, 19, 18,
445
446 // Bottom-left arc.
447 20, 21, 22,
448 21, 23, 22};
449
450GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
451
Robert Phillips8053c972019-11-21 10:44:53 -0500452void GrFillRRectOp::onPrePrepare(GrRecordingContext* context,
453 const GrSurfaceProxyView* dstView,
454 GrAppliedClip* clip,
455 const GrXferProcessor::DstProxyView& dstProxyView) {
456 SkArenaAlloc* arena = context->priv().recordTimeAllocator();
457
458 // This is equivalent to a GrOpFlushState::detachAppliedClip
459 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
460
Robert Phillips8053c972019-11-21 10:44:53 -0500461 fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, dstView,
462 std::move(appliedClip), dstProxyView);
Robert Phillips576b6a12019-12-06 13:05:49 -0500463
464 context->priv().recordProgramInfo(fProgramInfo);
Robert Phillips8053c972019-11-21 10:44:53 -0500465}
466
Greg Danielf793de12019-09-05 13:23:23 -0400467void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
468 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
469 &fInstanceBuffer, &fBaseInstance)) {
470 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
471 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
472 }
473
474 if (GrAAType::kCoverage == fAAType) {
475 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
476
477 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
478 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
479 gCoverageIndexBufferKey);
480
481 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
482
483 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
484 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
485 gCoverageVertexBufferKey);
486
487 fIndexCount = SK_ARRAY_COUNT(kCoverageIndexData);
488 } else {
489 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
490
491 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
492 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
493 gMSAAIndexBufferKey);
494
495 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
496
497 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
498 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
499 gMSAAVertexBufferKey);
500
501 fIndexCount = SK_ARRAY_COUNT(kMSAAIndexData);
502 }
503}
504
Chris Dalton0dffbab2019-03-27 13:08:50 -0600505class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500506 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
507 const auto& proc = args.fGP.cast<Processor>();
508 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
509
Chris Dalton0dffbab2019-03-27 13:08:50 -0600510 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
511
Chris Dalton133944a2018-11-16 23:30:29 -0500512 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
513 varyings->emitAttributes(proc);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600514 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500515 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
516
517 // Emit the vertex shader.
518 GrGLSLVertexBuilder* v = args.fVertBuilder;
519
520 // Unpack vertex attribs.
521 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
522 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
523 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
524 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
525 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
526
527 // Find the amount to bloat each edge for AA (in source space).
528 v->codeAppend("float2 pixellength = inversesqrt("
529 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
530 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
531 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
532 "abs(normalized_axis_dirs.zw));");
533 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
534
535 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000536 v->codeAppend("float4 radii_and_neighbors = radii_selector"
537 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
538 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
539 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500540
541 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
542 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
543 // or else opposite AA borders will overlap. Instead, fudge the size up to
544 // the width of a coverage ramp, and then reduce total coverage to make
545 // the rect appear more thin.
546 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
547 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
548 // Set radii to zero to ensure we take the "linear coverage" codepath.
549 // (The "coverage" variable only has effect in the linear codepath.)
550 v->codeAppend( "radii = float2(0);");
551 v->codeAppend("}");
552
553 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
554 // The radii are very small. Demote this arc to a sharp 90 degree corner.
555 v->codeAppend( "radii = aa_bloatradius;");
556 // Snap octagon vertices to the corner of the bounding box.
557 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
558 v->codeAppend( "is_linear_coverage = 1;");
559 v->codeAppend("} else {");
Mike Reedd3efa992018-11-28 13:13:15 +0000560 // Don't let radii get smaller than a pixel.
Chris Dalton133944a2018-11-16 23:30:29 -0500561 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
Mike Reedd3efa992018-11-28 13:13:15 +0000562 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
563 // Don't let neighboring radii get closer together than 1/16 pixel.
564 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
565 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
566 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500567 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500568
569 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
570 // normalized [-1,-1,+1,+1] space.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700571 v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
572 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500573
574 // Emit transforms.
575 GrShaderVar localCoord("", kFloat2_GrSLType);
576 if (proc.fFlags & Flags::kHasLocalCoords) {
577 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
578 "local_rect.zw * (1 + vertexpos)) * .5;");
579 localCoord.set(kFloat2_GrSLType, "localcoord");
580 }
581 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
582 args.fFPCoordTransformHandler);
583
584 // Transform to device space.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600585 SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
Chris Dalton133944a2018-11-16 23:30:29 -0500586 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
587 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
588 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
589
590 // Setup interpolants for coverage.
591 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
592 varyings->addVarying("arccoord", &arcCoord);
593 v->codeAppend("if (0 != is_linear_coverage) {");
594 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
595 // interpolate linear coverage across y.
596 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
597 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700598 // Find the normalized arc coordinates for our corner ellipse.
599 // (i.e., the coordinate system where x^2 + y^2 == 1).
600 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500601 // We are a corner piece: Interpolate the arc coordinates for coverage.
602 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
603 // instructs the fragment shader to use linear coverage).
604 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
605 if (!useHWDerivatives) {
606 // The gradient is order-1: Interpolate it across arccoord.zw.
607 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
608 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
609 }
610 v->codeAppend("}");
611
612 // Emit the fragment shader.
613 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
614
615 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
616 f->codeAppendf("half coverage;");
617 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600618 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500619 f->codeAppendf("} else {");
620 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
621 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
622 if (useHWDerivatives) {
623 f->codeAppendf("float fnwidth = fwidth(fn);");
624 } else {
625 // The gradient is interpolated across arccoord.zw.
626 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
627 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
628 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500629 f->codeAppendf( "half d = half(fn/fnwidth);");
Chris Dalton133944a2018-11-16 23:30:29 -0500630 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
631 f->codeAppendf("}");
632 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
633 }
634
635 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500636 const CoordTransformRange& transformRange) override {
637 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton133944a2018-11-16 23:30:29 -0500638 }
639};
640
Chris Dalton0dffbab2019-03-27 13:08:50 -0600641
642class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
643 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
644 const auto& proc = args.fGP.cast<Processor>();
645 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
646 bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
647 bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
648 SkASSERT(useHWDerivatives == hasPerspective);
649
650 SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
651
652 // Emit the vertex shader.
653 GrGLSLVertexBuilder* v = args.fVertBuilder;
654
655 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
656 varyings->emitAttributes(proc);
657 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
658 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
659
660 // Unpack vertex attribs.
661 v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
662 v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
663
664 // Identify our radii.
665 v->codeAppend("float2 radii;");
666 v->codeAppend("radii.x = dot(radii_selector, radii_x);");
667 v->codeAppend("radii.y = dot(radii_selector, radii_y);");
668 v->codeAppendf("bool is_arc_section = (radii.x > 0);");
669 v->codeAppendf("radii = abs(radii);");
670
671 // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
672 // [-1,-1,+1,+1] space.
673 v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
674
675 // Emit transforms.
676 GrShaderVar localCoord("", kFloat2_GrSLType);
677 if (hasLocalCoords) {
678 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
679 "local_rect.zw * (1 + vertexpos)) * .5;");
680 localCoord.set(kFloat2_GrSLType, "localcoord");
681 }
682 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
683 args.fFPCoordTransformHandler);
684
685 // Transform to device space.
686 if (!hasPerspective) {
687 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
688 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
689 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
690 } else {
691 v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
692 v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
693 gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
694 }
695
696 // Determine normalized arc coordinates for the implicit function.
697 GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
698 varyings->addVarying("arccoord", &arcCoord);
699 v->codeAppendf("if (is_arc_section) {");
700 v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
701 if (!useHWDerivatives) {
702 // The gradient is order-1: Interpolate it across arccoord.zw.
703 // This doesn't work with perspective.
704 SkASSERT(!hasPerspective);
705 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
706 v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
707 arcCoord.vsOut(), arcCoord.vsOut());
708 }
709 v->codeAppendf("} else {");
710 if (useHWDerivatives) {
711 v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
712 } else {
713 v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
714 }
715 v->codeAppendf("}");
716
717 // Emit the fragment shader.
718 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
719
720 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
721
722 // If x,y == 0, then we are drawing a triangle that does not track an arc.
723 f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
724 f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
725 if (GrAAType::kMSAA == proc.fAAType) {
726 using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
727 if (!useHWDerivatives) {
728 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
729 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
730 } else {
731 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
732 }
733 } else {
734 f->codeAppendf("if (fn > 0) {");
735 f->codeAppendf( "%s = half4(0);", args.fOutputCoverage);
736 f->codeAppendf("}");
737 }
738 f->codeAppendf("}");
739 }
740
741 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500742 const CoordTransformRange& transformRange) override {
743 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600744 }
745};
746
Chris Dalton82eb9e72019-03-21 14:26:39 -0600747GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
Chris Dalton133944a2018-11-16 23:30:29 -0500748 const GrShaderCaps&) const {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600749 if (GrAAType::kCoverage != fAAType) {
750 return new MSAAImpl();
751 }
752 return new CoverageImpl();
Chris Dalton133944a2018-11-16 23:30:29 -0500753}
754
Robert Phillips8053c972019-11-21 10:44:53 -0500755GrProgramInfo* GrFillRRectOp::createProgramInfo(const GrCaps* caps,
756 SkArenaAlloc* arena,
757 const GrSurfaceProxyView* dstView,
758 GrAppliedClip&& appliedClip,
759 const GrXferProcessor::DstProxyView& dstProxyView) {
760 GrGeometryProcessor* geomProc = Processor::Make(arena, fAAType, fFlags);
761 SkASSERT(geomProc->instanceStride() == (size_t)fInstanceStride);
Chris Dalton133944a2018-11-16 23:30:29 -0500762
763 GrPipeline::InitArgs initArgs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600764 if (GrAAType::kMSAA == fAAType) {
Chris Daltonbaa1b352019-04-03 12:03:00 -0600765 initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600766 }
Robert Phillips8053c972019-11-21 10:44:53 -0500767 initArgs.fCaps = caps;
768 initArgs.fDstProxyView = dstProxyView;
769 initArgs.fOutputSwizzle = dstView->swizzle();
770
Robert Phillipsff2f3802019-11-18 16:36:54 -0500771 GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
772
Robert Phillips8053c972019-11-21 10:44:53 -0500773 if (appliedClip.scissorState().enabled()) {
774 fixedDynamicState = arena->make<GrPipeline::FixedDynamicState>(
775 appliedClip.scissorState().rect());
Robert Phillipsff2f3802019-11-18 16:36:54 -0500776 }
777
Robert Phillips8053c972019-11-21 10:44:53 -0500778 GrPipeline* pipeline = arena->make<GrPipeline>(initArgs,
779 std::move(fProcessors),
780 std::move(appliedClip));
Chris Dalton133944a2018-11-16 23:30:29 -0500781
Robert Phillips8053c972019-11-21 10:44:53 -0500782 GrRenderTargetProxy* dstProxy = dstView->asRenderTargetProxy();
783 return arena->make<GrProgramInfo>(dstProxy->numSamples(),
784 dstProxy->numStencilSamples(),
Robert Phillips933484f2019-11-26 09:38:55 -0500785 dstProxy->backendFormat(),
Robert Phillips8053c972019-11-21 10:44:53 -0500786 dstView->origin(),
787 pipeline,
788 geomProc,
789 fixedDynamicState,
790 nullptr, 0,
791 GrPrimitiveType::kTriangles);
792}
793
794void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
795 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
796 return; // Setup failed.
797 }
798
799 if (!fProgramInfo) {
800 const GrSurfaceProxyView* dstView = flushState->view();
801
802 fProgramInfo = this->createProgramInfo(&flushState->caps(),
803 flushState->allocator(),
804 dstView,
805 flushState->detachAppliedClip(),
806 flushState->dstProxyView());
807 }
Robert Phillips901aff02019-10-08 12:32:56 -0400808
Greg Daniel0b002e22019-08-12 13:25:36 -0400809 GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
Robert Phillips8053c972019-11-21 10:44:53 -0500810 mesh->setIndexedInstanced(std::move(fIndexBuffer), fIndexCount,
811 std::move(fInstanceBuffer), fInstanceCount,
812 fBaseInstance, GrPrimitiveRestart::kNo);
Greg Danielf793de12019-09-05 13:23:23 -0400813 mesh->setVertexData(std::move(fVertexBuffer));
Robert Phillips8053c972019-11-21 10:44:53 -0500814
815 flushState->opsRenderPass()->draw(*fProgramInfo, mesh, 1, this->bounds());
Chris Dalton133944a2018-11-16 23:30:29 -0500816}
817
818// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600819static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500820 Sk2f devRadii = devScale * cornerRadii;
821 if (devRadii[1] < devRadii[0]) {
822 devRadii = SkNx_shuffle<1,0>(devRadii);
823 }
824 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
825 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
826 // This threshold was arrived at subjevtively on an NVIDIA chip.
827 return minDevRadius * minDevRadius * 5 > devRadii[1];
828}
829
Chris Dalton0dffbab2019-03-27 13:08:50 -0600830static bool can_use_hw_derivatives_with_coverage(
831 const Sk2f& devScale, const SkVector& cornerRadii) {
832 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500833}
834
835// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600836static bool can_use_hw_derivatives_with_coverage(
837 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500838 if (!shaderCaps.shaderDerivativeSupport()) {
839 return false;
840 }
841
842 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
843 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
844 Sk2f devScale = (x*x + y*y).sqrt();
845 switch (rrect.getType()) {
846 case SkRRect::kEmpty_Type:
847 case SkRRect::kRect_Type:
848 return true;
849
850 case SkRRect::kOval_Type:
851 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600852 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500853
854 case SkRRect::kNinePatch_Type: {
855 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
856 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
857 Sk2f minRadii = Sk2f::Min(r0, r1);
858 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600859 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
860 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500861 }
862
863 case SkRRect::kComplex_Type: {
864 for (int i = 0; i < 4; ++i) {
865 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600866 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500867 return false;
868 }
869 }
870 return true;
871 }
872 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600873 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500874}