blob: 099f4cf55094f819b979a4c3212ea807080f0846 [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;
Brian Osman2715bf52019-12-06 14:38:47 -0500146 this->writeInstanceData(finalColor);
Brian Osman5105d682019-02-13 16:06:14 -0500147 } else {
148 this->writeInstanceData(finalColor.toBytes_RGBA());
149 }
150
Chris Dalton133944a2018-11-16 23:30:29 -0500151 if (analysis.usesLocalCoords()) {
152 this->writeInstanceData(fLocalRect);
153 fFlags |= Flags::kHasLocalCoords;
154 }
155 fInstanceStride = fInstanceData.count();
156
Chris Dalton4b62aed2019-01-15 11:53:00 -0700157 return analysis;
Chris Dalton133944a2018-11-16 23:30:29 -0500158}
159
Chris Dalton82eb9e72019-03-21 14:26:39 -0600160GrDrawOp::CombineResult GrFillRRectOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
161 const auto& that = *op->cast<GrFillRRectOp>();
Chris Dalton133944a2018-11-16 23:30:29 -0500162 if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
163 fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
164 return CombineResult::kCannotCombine;
165 }
166
167 fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
168 fInstanceCount += that.fInstanceCount;
169 SkASSERT(fInstanceStride == that.fInstanceStride);
170 return CombineResult::kMerged;
171}
172
Chris Dalton0dffbab2019-03-27 13:08:50 -0600173class GrFillRRectOp::Processor : public GrGeometryProcessor {
174public:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500175 static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, Flags flags) {
176 return arena->make<Processor>(aaType, flags);
177 }
178
Robert Phillips8053c972019-11-21 10:44:53 -0500179 const char* name() const final { return "GrFillRRectOp::Processor"; }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500180
Robert Phillips8053c972019-11-21 10:44:53 -0500181 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const final {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500182 b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
183 }
184
Robert Phillips8053c972019-11-21 10:44:53 -0500185 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500186
187private:
188 friend class ::SkArenaAlloc; // for access to ctor
189
Chris Dalton0dffbab2019-03-27 13:08:50 -0600190 Processor(GrAAType aaType, Flags flags)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500191 : INHERITED(kGrFillRRectOp_Processor_ClassID)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600192 , fAAType(aaType)
193 , fFlags(flags) {
194 int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
195 this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
Chris Dalton133944a2018-11-16 23:30:29 -0500196
Chris Dalton0dffbab2019-03-27 13:08:50 -0600197 if (!(flags & Flags::kHasPerspective)) {
198 // Affine 2D transformation (float2x2 plus float2 translate).
199 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
200 fInstanceAttribs.emplace_back(
201 "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
202 } else {
203 // Perspective float3x3 transformation matrix.
204 fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
205 fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
206 fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
207 }
208 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
209 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
210 fColorAttrib = &fInstanceAttribs.push_back(
211 MakeColorAttribute("color", (flags & Flags::kWideColor)));
212 if (fFlags & Flags::kHasLocalCoords) {
213 fInstanceAttribs.emplace_back(
214 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
215 }
216 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
217
218 if (GrAAType::kMSAA == fAAType) {
219 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
220 }
221 }
222
Chris Dalton0dffbab2019-03-27 13:08:50 -0600223 static constexpr Attribute kVertexAttribs[] = {
224 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
225 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
226 // Coverage only.
227 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
228
229 const GrAAType fAAType;
230 const Flags fFlags;
231
232 SkSTArray<6, Attribute> fInstanceAttribs;
233 const Attribute* fColorAttrib;
234
235 class CoverageImpl;
236 class MSAAImpl;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500237
238 typedef GrGeometryProcessor INHERITED;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600239};
240
241constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
242
243// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500244// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
245// edges. The Vertex struct tells the shader where to place its vertex within a normalized
246// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600247struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500248 std::array<float, 4> fRadiiSelector;
249 std::array<float, 2> fCorner;
250 std::array<float, 2> fRadiusOutset;
251 std::array<float, 2> fAABloatDirection;
252 float fCoverage;
253 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500254};
255
256// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
257// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
258// rectangles.
259static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
260
Chris Dalton0dffbab2019-03-27 13:08:50 -0600261static constexpr CoverageVertex kCoverageVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500262 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700263 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
264 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500265
266 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700267 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
268 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500269
270 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700271 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
272 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500273
274 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700275 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
276 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500277
278
279 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700280 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
281 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500282
283 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700284 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
285 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500286
287 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700288 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
289 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500290
291 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700292 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
293 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500294
295
296 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700297 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
298 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
299 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
300 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
301 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
302 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500303
304 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700305 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
306 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
307 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
308 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
309 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
310 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500311
312 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700313 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
314 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
315 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
316 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
317 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
318 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500319
320 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700321 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
322 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
323 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
324 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700325 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700326 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500327
Chris Dalton0dffbab2019-03-27 13:08:50 -0600328GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500329
Chris Dalton0dffbab2019-03-27 13:08:50 -0600330static constexpr uint16_t kCoverageIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500331 // Inset octagon (solid coverage).
332 0, 1, 7,
333 1, 2, 7,
334 7, 2, 6,
335 2, 3, 6,
336 6, 3, 5,
337 3, 4, 5,
338
339 // AA borders (linear coverage).
340 0, 1, 8, 1, 9, 8,
341 2, 3, 10, 3, 11, 10,
342 4, 5, 12, 5, 13, 12,
343 6, 7, 14, 7, 15, 14,
344
345 // Top-left arc.
346 16, 17, 21,
347 17, 21, 18,
348 21, 18, 20,
349 18, 20, 19,
350
351 // Top-right arc.
352 22, 23, 27,
353 23, 27, 24,
354 27, 24, 26,
355 24, 26, 25,
356
357 // Bottom-right arc.
358 28, 29, 33,
359 29, 33, 30,
360 33, 30, 32,
361 30, 32, 31,
362
363 // Bottom-left arc.
364 34, 35, 39,
365 35, 39, 36,
366 39, 36, 38,
367 36, 38, 37};
368
Chris Dalton0dffbab2019-03-27 13:08:50 -0600369GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500370
Greg Danielf793de12019-09-05 13:23:23 -0400371
372// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
373// by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
374struct MSAAVertex {
375 std::array<float, 4> fRadiiSelector;
376 std::array<float, 2> fCorner;
377 std::array<float, 2> fRadiusOutset;
378};
379
380static constexpr MSAAVertex kMSAAVertexData[] = {
381 // Left edge. (Negative radii selector indicates this is not an arc section.)
382 {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}},
383 {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
384
385 // Top edge.
386 {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
387 {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}},
388
389 // Right edge.
390 {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}},
391 {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}},
392
393 // Bottom edge.
394 {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}},
395 {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}},
396
397 // Top-left corner.
398 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
399 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}},
400 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
401 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}},
402
403 // Top-right corner.
404 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}},
405 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}},
406 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}},
407 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}},
408
409 // Bottom-right corner.
410 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}},
411 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}},
412 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}},
413 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}},
414
415 // Bottom-left corner.
416 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}},
417 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}},
418 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}},
419 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}};
420
421GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
422
423static constexpr uint16_t kMSAAIndexData[] = {
424 // Inset octagon. (Full sample mask.)
425 0, 1, 2,
426 0, 2, 3,
427 0, 3, 6,
428 3, 4, 5,
429 3, 5, 6,
430 6, 7, 0,
431
432 // Top-left arc. (Sample mask is set to the arc.)
433 8, 9, 10,
434 9, 11, 10,
435
436 // Top-right arc.
437 12, 13, 14,
438 13, 15, 14,
439
440 // Bottom-right arc.
441 16, 17, 18,
442 17, 19, 18,
443
444 // Bottom-left arc.
445 20, 21, 22,
446 21, 23, 22};
447
448GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
449
Robert Phillips8053c972019-11-21 10:44:53 -0500450void GrFillRRectOp::onPrePrepare(GrRecordingContext* context,
451 const GrSurfaceProxyView* dstView,
452 GrAppliedClip* clip,
453 const GrXferProcessor::DstProxyView& dstProxyView) {
454 SkArenaAlloc* arena = context->priv().recordTimeAllocator();
455
456 // This is equivalent to a GrOpFlushState::detachAppliedClip
457 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
458
Robert Phillips8053c972019-11-21 10:44:53 -0500459 fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, dstView,
460 std::move(appliedClip), dstProxyView);
Robert Phillips576b6a12019-12-06 13:05:49 -0500461
462 context->priv().recordProgramInfo(fProgramInfo);
Robert Phillips8053c972019-11-21 10:44:53 -0500463}
464
Greg Danielf793de12019-09-05 13:23:23 -0400465void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
466 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
467 &fInstanceBuffer, &fBaseInstance)) {
468 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
469 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
470 }
471
472 if (GrAAType::kCoverage == fAAType) {
473 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
474
475 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
476 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
477 gCoverageIndexBufferKey);
478
479 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
480
481 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
482 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
483 gCoverageVertexBufferKey);
484
485 fIndexCount = SK_ARRAY_COUNT(kCoverageIndexData);
486 } else {
487 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
488
489 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
490 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
491 gMSAAIndexBufferKey);
492
493 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
494
495 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
496 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
497 gMSAAVertexBufferKey);
498
499 fIndexCount = SK_ARRAY_COUNT(kMSAAIndexData);
500 }
501}
502
Chris Dalton0dffbab2019-03-27 13:08:50 -0600503class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500504 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
505 const auto& proc = args.fGP.cast<Processor>();
506 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
507
Chris Dalton0dffbab2019-03-27 13:08:50 -0600508 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
509
Chris Dalton133944a2018-11-16 23:30:29 -0500510 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
511 varyings->emitAttributes(proc);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600512 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500513 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
514
515 // Emit the vertex shader.
516 GrGLSLVertexBuilder* v = args.fVertBuilder;
517
518 // Unpack vertex attribs.
519 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
520 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
521 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
522 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
523 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
524
525 // Find the amount to bloat each edge for AA (in source space).
526 v->codeAppend("float2 pixellength = inversesqrt("
527 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
528 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
529 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
530 "abs(normalized_axis_dirs.zw));");
531 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
532
533 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000534 v->codeAppend("float4 radii_and_neighbors = radii_selector"
535 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
536 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
537 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500538
539 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
540 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
541 // or else opposite AA borders will overlap. Instead, fudge the size up to
542 // the width of a coverage ramp, and then reduce total coverage to make
543 // the rect appear more thin.
544 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
545 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
546 // Set radii to zero to ensure we take the "linear coverage" codepath.
547 // (The "coverage" variable only has effect in the linear codepath.)
548 v->codeAppend( "radii = float2(0);");
549 v->codeAppend("}");
550
551 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
552 // The radii are very small. Demote this arc to a sharp 90 degree corner.
553 v->codeAppend( "radii = aa_bloatradius;");
554 // Snap octagon vertices to the corner of the bounding box.
555 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
556 v->codeAppend( "is_linear_coverage = 1;");
557 v->codeAppend("} else {");
Mike Reedd3efa992018-11-28 13:13:15 +0000558 // Don't let radii get smaller than a pixel.
Chris Dalton133944a2018-11-16 23:30:29 -0500559 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
Mike Reedd3efa992018-11-28 13:13:15 +0000560 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
561 // Don't let neighboring radii get closer together than 1/16 pixel.
562 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
563 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
564 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500565 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500566
567 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
568 // normalized [-1,-1,+1,+1] space.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700569 v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
570 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500571
572 // Emit transforms.
573 GrShaderVar localCoord("", kFloat2_GrSLType);
574 if (proc.fFlags & Flags::kHasLocalCoords) {
575 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
576 "local_rect.zw * (1 + vertexpos)) * .5;");
577 localCoord.set(kFloat2_GrSLType, "localcoord");
578 }
579 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
580 args.fFPCoordTransformHandler);
581
582 // Transform to device space.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600583 SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
Chris Dalton133944a2018-11-16 23:30:29 -0500584 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
585 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
586 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
587
588 // Setup interpolants for coverage.
589 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
590 varyings->addVarying("arccoord", &arcCoord);
591 v->codeAppend("if (0 != is_linear_coverage) {");
592 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
593 // interpolate linear coverage across y.
594 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
595 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700596 // Find the normalized arc coordinates for our corner ellipse.
597 // (i.e., the coordinate system where x^2 + y^2 == 1).
598 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500599 // We are a corner piece: Interpolate the arc coordinates for coverage.
600 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
601 // instructs the fragment shader to use linear coverage).
602 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
603 if (!useHWDerivatives) {
604 // The gradient is order-1: Interpolate it across arccoord.zw.
605 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
606 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
607 }
608 v->codeAppend("}");
609
610 // Emit the fragment shader.
611 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
612
613 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
614 f->codeAppendf("half coverage;");
615 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600616 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500617 f->codeAppendf("} else {");
618 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
619 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
620 if (useHWDerivatives) {
621 f->codeAppendf("float fnwidth = fwidth(fn);");
622 } else {
623 // The gradient is interpolated across arccoord.zw.
624 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
625 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
626 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500627 f->codeAppendf( "half d = half(fn/fnwidth);");
Chris Dalton133944a2018-11-16 23:30:29 -0500628 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
629 f->codeAppendf("}");
630 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
631 }
632
633 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500634 const CoordTransformRange& transformRange) override {
635 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton133944a2018-11-16 23:30:29 -0500636 }
637};
638
Chris Dalton0dffbab2019-03-27 13:08:50 -0600639
640class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
641 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
642 const auto& proc = args.fGP.cast<Processor>();
643 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
644 bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
645 bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
646 SkASSERT(useHWDerivatives == hasPerspective);
647
648 SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
649
650 // Emit the vertex shader.
651 GrGLSLVertexBuilder* v = args.fVertBuilder;
652
653 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
654 varyings->emitAttributes(proc);
655 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
656 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
657
658 // Unpack vertex attribs.
659 v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
660 v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
661
662 // Identify our radii.
663 v->codeAppend("float2 radii;");
664 v->codeAppend("radii.x = dot(radii_selector, radii_x);");
665 v->codeAppend("radii.y = dot(radii_selector, radii_y);");
666 v->codeAppendf("bool is_arc_section = (radii.x > 0);");
667 v->codeAppendf("radii = abs(radii);");
668
669 // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
670 // [-1,-1,+1,+1] space.
671 v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
672
673 // Emit transforms.
674 GrShaderVar localCoord("", kFloat2_GrSLType);
675 if (hasLocalCoords) {
676 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
677 "local_rect.zw * (1 + vertexpos)) * .5;");
678 localCoord.set(kFloat2_GrSLType, "localcoord");
679 }
680 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
681 args.fFPCoordTransformHandler);
682
683 // Transform to device space.
684 if (!hasPerspective) {
685 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
686 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
687 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
688 } else {
689 v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
690 v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
691 gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
692 }
693
694 // Determine normalized arc coordinates for the implicit function.
695 GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
696 varyings->addVarying("arccoord", &arcCoord);
697 v->codeAppendf("if (is_arc_section) {");
698 v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
699 if (!useHWDerivatives) {
700 // The gradient is order-1: Interpolate it across arccoord.zw.
701 // This doesn't work with perspective.
702 SkASSERT(!hasPerspective);
703 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
704 v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
705 arcCoord.vsOut(), arcCoord.vsOut());
706 }
707 v->codeAppendf("} else {");
708 if (useHWDerivatives) {
709 v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
710 } else {
711 v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
712 }
713 v->codeAppendf("}");
714
715 // Emit the fragment shader.
716 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
717
718 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
719
720 // If x,y == 0, then we are drawing a triangle that does not track an arc.
721 f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
722 f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
723 if (GrAAType::kMSAA == proc.fAAType) {
724 using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
725 if (!useHWDerivatives) {
726 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
727 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
728 } else {
729 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
730 }
731 } else {
732 f->codeAppendf("if (fn > 0) {");
733 f->codeAppendf( "%s = half4(0);", args.fOutputCoverage);
734 f->codeAppendf("}");
735 }
736 f->codeAppendf("}");
737 }
738
739 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500740 const CoordTransformRange& transformRange) override {
741 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600742 }
743};
744
Chris Dalton82eb9e72019-03-21 14:26:39 -0600745GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
Chris Dalton133944a2018-11-16 23:30:29 -0500746 const GrShaderCaps&) const {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600747 if (GrAAType::kCoverage != fAAType) {
748 return new MSAAImpl();
749 }
750 return new CoverageImpl();
Chris Dalton133944a2018-11-16 23:30:29 -0500751}
752
Robert Phillips8053c972019-11-21 10:44:53 -0500753GrProgramInfo* GrFillRRectOp::createProgramInfo(const GrCaps* caps,
754 SkArenaAlloc* arena,
755 const GrSurfaceProxyView* dstView,
756 GrAppliedClip&& appliedClip,
757 const GrXferProcessor::DstProxyView& dstProxyView) {
758 GrGeometryProcessor* geomProc = Processor::Make(arena, fAAType, fFlags);
759 SkASSERT(geomProc->instanceStride() == (size_t)fInstanceStride);
Chris Dalton133944a2018-11-16 23:30:29 -0500760
761 GrPipeline::InitArgs initArgs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600762 if (GrAAType::kMSAA == fAAType) {
Chris Daltonbaa1b352019-04-03 12:03:00 -0600763 initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600764 }
Robert Phillips8053c972019-11-21 10:44:53 -0500765 initArgs.fCaps = caps;
766 initArgs.fDstProxyView = dstProxyView;
767 initArgs.fOutputSwizzle = dstView->swizzle();
768
Robert Phillipsff2f3802019-11-18 16:36:54 -0500769 GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
770
Robert Phillips8053c972019-11-21 10:44:53 -0500771 if (appliedClip.scissorState().enabled()) {
772 fixedDynamicState = arena->make<GrPipeline::FixedDynamicState>(
773 appliedClip.scissorState().rect());
Robert Phillipsff2f3802019-11-18 16:36:54 -0500774 }
775
Robert Phillips8053c972019-11-21 10:44:53 -0500776 GrPipeline* pipeline = arena->make<GrPipeline>(initArgs,
777 std::move(fProcessors),
778 std::move(appliedClip));
Chris Dalton133944a2018-11-16 23:30:29 -0500779
Robert Phillips8053c972019-11-21 10:44:53 -0500780 GrRenderTargetProxy* dstProxy = dstView->asRenderTargetProxy();
781 return arena->make<GrProgramInfo>(dstProxy->numSamples(),
782 dstProxy->numStencilSamples(),
Robert Phillips933484f2019-11-26 09:38:55 -0500783 dstProxy->backendFormat(),
Robert Phillips8053c972019-11-21 10:44:53 -0500784 dstView->origin(),
785 pipeline,
786 geomProc,
787 fixedDynamicState,
788 nullptr, 0,
789 GrPrimitiveType::kTriangles);
790}
791
792void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
793 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
794 return; // Setup failed.
795 }
796
797 if (!fProgramInfo) {
798 const GrSurfaceProxyView* dstView = flushState->view();
799
800 fProgramInfo = this->createProgramInfo(&flushState->caps(),
801 flushState->allocator(),
802 dstView,
803 flushState->detachAppliedClip(),
804 flushState->dstProxyView());
805 }
Robert Phillips901aff02019-10-08 12:32:56 -0400806
Greg Daniel0b002e22019-08-12 13:25:36 -0400807 GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
Robert Phillips8053c972019-11-21 10:44:53 -0500808 mesh->setIndexedInstanced(std::move(fIndexBuffer), fIndexCount,
809 std::move(fInstanceBuffer), fInstanceCount,
810 fBaseInstance, GrPrimitiveRestart::kNo);
Greg Danielf793de12019-09-05 13:23:23 -0400811 mesh->setVertexData(std::move(fVertexBuffer));
Robert Phillips8053c972019-11-21 10:44:53 -0500812
813 flushState->opsRenderPass()->draw(*fProgramInfo, mesh, 1, this->bounds());
Chris Dalton133944a2018-11-16 23:30:29 -0500814}
815
816// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600817static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500818 Sk2f devRadii = devScale * cornerRadii;
819 if (devRadii[1] < devRadii[0]) {
820 devRadii = SkNx_shuffle<1,0>(devRadii);
821 }
822 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
823 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
824 // This threshold was arrived at subjevtively on an NVIDIA chip.
825 return minDevRadius * minDevRadius * 5 > devRadii[1];
826}
827
Chris Dalton0dffbab2019-03-27 13:08:50 -0600828static bool can_use_hw_derivatives_with_coverage(
829 const Sk2f& devScale, const SkVector& cornerRadii) {
830 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500831}
832
833// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600834static bool can_use_hw_derivatives_with_coverage(
835 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500836 if (!shaderCaps.shaderDerivativeSupport()) {
837 return false;
838 }
839
840 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
841 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
842 Sk2f devScale = (x*x + y*y).sqrt();
843 switch (rrect.getType()) {
844 case SkRRect::kEmpty_Type:
845 case SkRRect::kRect_Type:
846 return true;
847
848 case SkRRect::kOval_Type:
849 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600850 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500851
852 case SkRRect::kNinePatch_Type: {
853 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
854 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
855 Sk2f minRadii = Sk2f::Min(r0, r1);
856 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600857 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
858 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500859 }
860
861 case SkRRect::kComplex_Type: {
862 for (int i = 0; i < 4; ++i) {
863 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600864 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500865 return false;
866 }
867 }
868 return true;
869 }
870 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600871 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500872}