blob: 381c44a95e8275e8e95fb7e81c8dd2af7c688ac0 [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
Michael Ludwig28b0c5d2019-12-19 14:51:00 -0500160GrDrawOp::CombineResult GrFillRRectOp::onCombineIfPossible(GrOp* op, GrRecordingContext::Arenas*,
161 const GrCaps&) {
Chris Dalton82eb9e72019-03-21 14:26:39 -0600162 const auto& that = *op->cast<GrFillRRectOp>();
Chris Dalton133944a2018-11-16 23:30:29 -0500163 if (fFlags != that.fFlags || fProcessors != that.fProcessors ||
164 fInstanceData.count() > std::numeric_limits<int>::max() - that.fInstanceData.count()) {
165 return CombineResult::kCannotCombine;
166 }
167
168 fInstanceData.push_back_n(that.fInstanceData.count(), that.fInstanceData.begin());
169 fInstanceCount += that.fInstanceCount;
170 SkASSERT(fInstanceStride == that.fInstanceStride);
171 return CombineResult::kMerged;
172}
173
Chris Dalton0dffbab2019-03-27 13:08:50 -0600174class GrFillRRectOp::Processor : public GrGeometryProcessor {
175public:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500176 static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, Flags flags) {
177 return arena->make<Processor>(aaType, flags);
178 }
179
Robert Phillips8053c972019-11-21 10:44:53 -0500180 const char* name() const final { return "GrFillRRectOp::Processor"; }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500181
Robert Phillips8053c972019-11-21 10:44:53 -0500182 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const final {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500183 b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType);
184 }
185
Robert Phillips8053c972019-11-21 10:44:53 -0500186 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500187
188private:
189 friend class ::SkArenaAlloc; // for access to ctor
190
Chris Dalton0dffbab2019-03-27 13:08:50 -0600191 Processor(GrAAType aaType, Flags flags)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500192 : INHERITED(kGrFillRRectOp_Processor_ClassID)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600193 , fAAType(aaType)
194 , fFlags(flags) {
195 int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2;
196 this->setVertexAttributes(kVertexAttribs, numVertexAttribs);
Chris Dalton133944a2018-11-16 23:30:29 -0500197
Chris Dalton0dffbab2019-03-27 13:08:50 -0600198 if (!(flags & Flags::kHasPerspective)) {
199 // Affine 2D transformation (float2x2 plus float2 translate).
200 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
201 fInstanceAttribs.emplace_back(
202 "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
203 } else {
204 // Perspective float3x3 transformation matrix.
205 fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
206 fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
207 fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType);
208 }
209 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
210 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
211 fColorAttrib = &fInstanceAttribs.push_back(
212 MakeColorAttribute("color", (flags & Flags::kWideColor)));
213 if (fFlags & Flags::kHasLocalCoords) {
214 fInstanceAttribs.emplace_back(
215 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
216 }
217 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
218
219 if (GrAAType::kMSAA == fAAType) {
220 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
221 }
222 }
223
Chris Dalton0dffbab2019-03-27 13:08:50 -0600224 static constexpr Attribute kVertexAttribs[] = {
225 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
226 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
227 // Coverage only.
228 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
229
230 const GrAAType fAAType;
231 const Flags fFlags;
232
233 SkSTArray<6, Attribute> fInstanceAttribs;
234 const Attribute* fColorAttrib;
235
236 class CoverageImpl;
237 class MSAAImpl;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500238
239 typedef GrGeometryProcessor INHERITED;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600240};
241
242constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[];
243
244// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500245// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
246// edges. The Vertex struct tells the shader where to place its vertex within a normalized
247// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600248struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500249 std::array<float, 4> fRadiiSelector;
250 std::array<float, 2> fCorner;
251 std::array<float, 2> fRadiusOutset;
252 std::array<float, 2> fAABloatDirection;
253 float fCoverage;
254 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500255};
256
257// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
258// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
259// rectangles.
260static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
261
Chris Dalton0dffbab2019-03-27 13:08:50 -0600262static constexpr CoverageVertex kCoverageVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500263 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700264 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
265 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500266
267 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700268 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
269 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500270
271 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700272 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
273 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500274
275 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700276 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
277 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500278
279
280 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700281 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
282 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500283
284 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700285 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
286 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500287
288 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700289 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
290 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500291
292 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700293 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
294 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500295
296
297 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700298 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
299 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
300 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
301 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
302 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
303 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500304
305 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700306 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
307 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
308 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
309 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
310 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
311 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500312
313 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700314 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
315 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
316 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
317 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
318 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
319 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500320
321 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700322 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
323 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
324 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
325 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700326 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700327 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500328
Chris Dalton0dffbab2019-03-27 13:08:50 -0600329GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500330
Chris Dalton0dffbab2019-03-27 13:08:50 -0600331static constexpr uint16_t kCoverageIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500332 // Inset octagon (solid coverage).
333 0, 1, 7,
334 1, 2, 7,
335 7, 2, 6,
336 2, 3, 6,
337 6, 3, 5,
338 3, 4, 5,
339
340 // AA borders (linear coverage).
341 0, 1, 8, 1, 9, 8,
342 2, 3, 10, 3, 11, 10,
343 4, 5, 12, 5, 13, 12,
344 6, 7, 14, 7, 15, 14,
345
346 // Top-left arc.
347 16, 17, 21,
348 17, 21, 18,
349 21, 18, 20,
350 18, 20, 19,
351
352 // Top-right arc.
353 22, 23, 27,
354 23, 27, 24,
355 27, 24, 26,
356 24, 26, 25,
357
358 // Bottom-right arc.
359 28, 29, 33,
360 29, 33, 30,
361 33, 30, 32,
362 30, 32, 31,
363
364 // Bottom-left arc.
365 34, 35, 39,
366 35, 39, 36,
367 39, 36, 38,
368 36, 38, 37};
369
Chris Dalton0dffbab2019-03-27 13:08:50 -0600370GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500371
Greg Danielf793de12019-09-05 13:23:23 -0400372
373// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed
374// by a larger octagon that modifies the sample mask for the arc at each corresponding corner.
375struct MSAAVertex {
376 std::array<float, 4> fRadiiSelector;
377 std::array<float, 2> fCorner;
378 std::array<float, 2> fRadiusOutset;
379};
380
381static constexpr MSAAVertex kMSAAVertexData[] = {
382 // Left edge. (Negative radii selector indicates this is not an arc section.)
383 {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}},
384 {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
385
386 // Top edge.
387 {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
388 {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}},
389
390 // Right edge.
391 {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}},
392 {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}},
393
394 // Bottom edge.
395 {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}},
396 {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}},
397
398 // Top-left corner.
399 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}},
400 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}},
401 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}},
402 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}},
403
404 // Top-right corner.
405 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}},
406 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}},
407 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}},
408 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}},
409
410 // Bottom-right corner.
411 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}},
412 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}},
413 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}},
414 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}},
415
416 // Bottom-left corner.
417 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}},
418 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}},
419 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}},
420 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}};
421
422GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
423
424static constexpr uint16_t kMSAAIndexData[] = {
425 // Inset octagon. (Full sample mask.)
426 0, 1, 2,
427 0, 2, 3,
428 0, 3, 6,
429 3, 4, 5,
430 3, 5, 6,
431 6, 7, 0,
432
433 // Top-left arc. (Sample mask is set to the arc.)
434 8, 9, 10,
435 9, 11, 10,
436
437 // Top-right arc.
438 12, 13, 14,
439 13, 15, 14,
440
441 // Bottom-right arc.
442 16, 17, 18,
443 17, 19, 18,
444
445 // Bottom-left arc.
446 20, 21, 22,
447 21, 23, 22};
448
449GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
450
Robert Phillips8053c972019-11-21 10:44:53 -0500451void GrFillRRectOp::onPrePrepare(GrRecordingContext* context,
452 const GrSurfaceProxyView* dstView,
453 GrAppliedClip* clip,
454 const GrXferProcessor::DstProxyView& dstProxyView) {
455 SkArenaAlloc* arena = context->priv().recordTimeAllocator();
456
457 // This is equivalent to a GrOpFlushState::detachAppliedClip
458 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
459
Robert Phillips8053c972019-11-21 10:44:53 -0500460 fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, dstView,
461 std::move(appliedClip), dstProxyView);
Robert Phillips576b6a12019-12-06 13:05:49 -0500462
463 context->priv().recordProgramInfo(fProgramInfo);
Robert Phillips8053c972019-11-21 10:44:53 -0500464}
465
Greg Danielf793de12019-09-05 13:23:23 -0400466void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) {
467 if (void* instanceData = flushState->makeVertexSpace(fInstanceStride, fInstanceCount,
468 &fInstanceBuffer, &fBaseInstance)) {
469 SkASSERT(fInstanceStride * fInstanceCount == fInstanceData.count());
470 memcpy(instanceData, fInstanceData.begin(), fInstanceData.count());
471 }
472
473 if (GrAAType::kCoverage == fAAType) {
474 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey);
475
476 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
477 GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData,
478 gCoverageIndexBufferKey);
479
480 GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey);
481
482 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
483 GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData,
484 gCoverageVertexBufferKey);
485
486 fIndexCount = SK_ARRAY_COUNT(kCoverageIndexData);
487 } else {
488 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey);
489
490 fIndexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
491 GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData,
492 gMSAAIndexBufferKey);
493
494 GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey);
495
496 fVertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer(
497 GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData,
498 gMSAAVertexBufferKey);
499
500 fIndexCount = SK_ARRAY_COUNT(kMSAAIndexData);
501 }
502}
503
Chris Dalton0dffbab2019-03-27 13:08:50 -0600504class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500505 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
506 const auto& proc = args.fGP.cast<Processor>();
507 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
508
Chris Dalton0dffbab2019-03-27 13:08:50 -0600509 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
510
Chris Dalton133944a2018-11-16 23:30:29 -0500511 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
512 varyings->emitAttributes(proc);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600513 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500514 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
515
516 // Emit the vertex shader.
517 GrGLSLVertexBuilder* v = args.fVertBuilder;
518
519 // Unpack vertex attribs.
520 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
521 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
522 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
523 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
524 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
525
526 // Find the amount to bloat each edge for AA (in source space).
527 v->codeAppend("float2 pixellength = inversesqrt("
528 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
529 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
530 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
531 "abs(normalized_axis_dirs.zw));");
532 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
533
534 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000535 v->codeAppend("float4 radii_and_neighbors = radii_selector"
536 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
537 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
538 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500539
540 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
541 // The rrect is more narrow than an AA coverage ramp. We can't draw as-is
542 // or else opposite AA borders will overlap. Instead, fudge the size up to
543 // the width of a coverage ramp, and then reduce total coverage to make
544 // the rect appear more thin.
545 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
546 v->codeAppend( "coverage /= max(aa_bloatradius.x, 1) * max(aa_bloatradius.y, 1);");
547 // Set radii to zero to ensure we take the "linear coverage" codepath.
548 // (The "coverage" variable only has effect in the linear codepath.)
549 v->codeAppend( "radii = float2(0);");
550 v->codeAppend("}");
551
552 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.25))) {");
553 // The radii are very small. Demote this arc to a sharp 90 degree corner.
554 v->codeAppend( "radii = aa_bloatradius;");
555 // Snap octagon vertices to the corner of the bounding box.
556 v->codeAppend( "radius_outset = floor(abs(radius_outset)) * radius_outset;");
557 v->codeAppend( "is_linear_coverage = 1;");
558 v->codeAppend("} else {");
Mike Reedd3efa992018-11-28 13:13:15 +0000559 // Don't let radii get smaller than a pixel.
Chris Dalton133944a2018-11-16 23:30:29 -0500560 v->codeAppend( "radii = clamp(radii, pixellength, 2 - pixellength);");
Mike Reedd3efa992018-11-28 13:13:15 +0000561 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength, 2 - pixellength);");
562 // Don't let neighboring radii get closer together than 1/16 pixel.
563 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
564 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
565 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500566 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500567
568 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
569 // normalized [-1,-1,+1,+1] space.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700570 v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;");
571 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500572
573 // Emit transforms.
574 GrShaderVar localCoord("", kFloat2_GrSLType);
575 if (proc.fFlags & Flags::kHasLocalCoords) {
576 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
577 "local_rect.zw * (1 + vertexpos)) * .5;");
578 localCoord.set(kFloat2_GrSLType, "localcoord");
579 }
580 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
581 args.fFPCoordTransformHandler);
582
583 // Transform to device space.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600584 SkASSERT(!(proc.fFlags & Flags::kHasPerspective));
Chris Dalton133944a2018-11-16 23:30:29 -0500585 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
586 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
587 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
588
589 // Setup interpolants for coverage.
590 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
591 varyings->addVarying("arccoord", &arcCoord);
592 v->codeAppend("if (0 != is_linear_coverage) {");
593 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
594 // interpolate linear coverage across y.
595 v->codeAppendf( "%s.xy = float2(0, coverage);", arcCoord.vsOut());
596 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700597 // Find the normalized arc coordinates for our corner ellipse.
598 // (i.e., the coordinate system where x^2 + y^2 == 1).
599 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500600 // We are a corner piece: Interpolate the arc coordinates for coverage.
601 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
602 // instructs the fragment shader to use linear coverage).
603 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
604 if (!useHWDerivatives) {
605 // The gradient is order-1: Interpolate it across arccoord.zw.
606 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
607 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
608 }
609 v->codeAppend("}");
610
611 // Emit the fragment shader.
612 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
613
614 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
615 f->codeAppendf("half coverage;");
616 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600617 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500618 f->codeAppendf("} else {");
619 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
620 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
621 if (useHWDerivatives) {
622 f->codeAppendf("float fnwidth = fwidth(fn);");
623 } else {
624 // The gradient is interpolated across arccoord.zw.
625 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
626 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
627 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500628 f->codeAppendf( "half d = half(fn/fnwidth);");
Chris Dalton133944a2018-11-16 23:30:29 -0500629 f->codeAppendf( "coverage = clamp(.5 - d, 0, 1);");
630 f->codeAppendf("}");
631 f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
632 }
633
634 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500635 const CoordTransformRange& transformRange) override {
636 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton133944a2018-11-16 23:30:29 -0500637 }
638};
639
Chris Dalton0dffbab2019-03-27 13:08:50 -0600640
641class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor {
642 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
643 const auto& proc = args.fGP.cast<Processor>();
644 bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives);
645 bool hasPerspective = (proc.fFlags & Flags::kHasPerspective);
646 bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords);
647 SkASSERT(useHWDerivatives == hasPerspective);
648
649 SkASSERT(proc.vertexStride() == sizeof(MSAAVertex));
650
651 // Emit the vertex shader.
652 GrGLSLVertexBuilder* v = args.fVertBuilder;
653
654 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
655 varyings->emitAttributes(proc);
656 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
657 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
658
659 // Unpack vertex attribs.
660 v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;");
661 v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;");
662
663 // Identify our radii.
664 v->codeAppend("float2 radii;");
665 v->codeAppend("radii.x = dot(radii_selector, radii_x);");
666 v->codeAppend("radii.y = dot(radii_selector, radii_y);");
667 v->codeAppendf("bool is_arc_section = (radii.x > 0);");
668 v->codeAppendf("radii = abs(radii);");
669
670 // Find our vertex position, adjusted for radii. Our rect is drawn in normalized
671 // [-1,-1,+1,+1] space.
672 v->codeAppend("float2 vertexpos = corner + radius_outset * radii;");
673
674 // Emit transforms.
675 GrShaderVar localCoord("", kFloat2_GrSLType);
676 if (hasLocalCoords) {
677 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
678 "local_rect.zw * (1 + vertexpos)) * .5;");
679 localCoord.set(kFloat2_GrSLType, "localcoord");
680 }
681 this->emitTransforms(v, varyings, args.fUniformHandler, localCoord,
682 args.fFPCoordTransformHandler);
683
684 // Transform to device space.
685 if (!hasPerspective) {
686 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
687 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
688 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
689 } else {
690 v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);");
691 v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;");
692 gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord");
693 }
694
695 // Determine normalized arc coordinates for the implicit function.
696 GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType);
697 varyings->addVarying("arccoord", &arcCoord);
698 v->codeAppendf("if (is_arc_section) {");
699 v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut());
700 if (!useHWDerivatives) {
701 // The gradient is order-1: Interpolate it across arccoord.zw.
702 // This doesn't work with perspective.
703 SkASSERT(!hasPerspective);
704 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
705 v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);",
706 arcCoord.vsOut(), arcCoord.vsOut());
707 }
708 v->codeAppendf("} else {");
709 if (useHWDerivatives) {
710 v->codeAppendf("%s = float2(0);", arcCoord.vsOut());
711 } else {
712 v->codeAppendf("%s = float4(0);", arcCoord.vsOut());
713 }
714 v->codeAppendf("}");
715
716 // Emit the fragment shader.
717 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
718
719 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
720
721 // If x,y == 0, then we are drawing a triangle that does not track an arc.
722 f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn());
723 f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn());
724 if (GrAAType::kMSAA == proc.fAAType) {
725 using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags;
726 if (!useHWDerivatives) {
727 f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn());
728 f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch);
729 } else {
730 f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch);
731 }
732 } else {
733 f->codeAppendf("if (fn > 0) {");
734 f->codeAppendf( "%s = half4(0);", args.fOutputCoverage);
735 f->codeAppendf("}");
736 }
737 f->codeAppendf("}");
738 }
739
740 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
Brian Salomonc241b582019-11-27 08:57:17 -0500741 const CoordTransformRange& transformRange) override {
742 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600743 }
744};
745
Chris Dalton82eb9e72019-03-21 14:26:39 -0600746GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance(
Chris Dalton133944a2018-11-16 23:30:29 -0500747 const GrShaderCaps&) const {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600748 if (GrAAType::kCoverage != fAAType) {
749 return new MSAAImpl();
750 }
751 return new CoverageImpl();
Chris Dalton133944a2018-11-16 23:30:29 -0500752}
753
Robert Phillips8053c972019-11-21 10:44:53 -0500754GrProgramInfo* GrFillRRectOp::createProgramInfo(const GrCaps* caps,
755 SkArenaAlloc* arena,
756 const GrSurfaceProxyView* dstView,
757 GrAppliedClip&& appliedClip,
758 const GrXferProcessor::DstProxyView& dstProxyView) {
759 GrGeometryProcessor* geomProc = Processor::Make(arena, fAAType, fFlags);
760 SkASSERT(geomProc->instanceStride() == (size_t)fInstanceStride);
Chris Dalton133944a2018-11-16 23:30:29 -0500761
762 GrPipeline::InitArgs initArgs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600763 if (GrAAType::kMSAA == fAAType) {
Chris Daltonbaa1b352019-04-03 12:03:00 -0600764 initArgs.fInputFlags = GrPipeline::InputFlags::kHWAntialias;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600765 }
Robert Phillips8053c972019-11-21 10:44:53 -0500766 initArgs.fCaps = caps;
767 initArgs.fDstProxyView = dstProxyView;
768 initArgs.fOutputSwizzle = dstView->swizzle();
769
Robert Phillipsff2f3802019-11-18 16:36:54 -0500770 GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
771
Robert Phillips8053c972019-11-21 10:44:53 -0500772 if (appliedClip.scissorState().enabled()) {
773 fixedDynamicState = arena->make<GrPipeline::FixedDynamicState>(
774 appliedClip.scissorState().rect());
Robert Phillipsff2f3802019-11-18 16:36:54 -0500775 }
776
Robert Phillips8053c972019-11-21 10:44:53 -0500777 GrPipeline* pipeline = arena->make<GrPipeline>(initArgs,
778 std::move(fProcessors),
779 std::move(appliedClip));
Chris Dalton133944a2018-11-16 23:30:29 -0500780
Robert Phillips8053c972019-11-21 10:44:53 -0500781 GrRenderTargetProxy* dstProxy = dstView->asRenderTargetProxy();
782 return arena->make<GrProgramInfo>(dstProxy->numSamples(),
783 dstProxy->numStencilSamples(),
Robert Phillips933484f2019-11-26 09:38:55 -0500784 dstProxy->backendFormat(),
Robert Phillips8053c972019-11-21 10:44:53 -0500785 dstView->origin(),
786 pipeline,
787 geomProc,
788 fixedDynamicState,
789 nullptr, 0,
790 GrPrimitiveType::kTriangles);
791}
792
793void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
794 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
795 return; // Setup failed.
796 }
797
798 if (!fProgramInfo) {
799 const GrSurfaceProxyView* dstView = flushState->view();
800
801 fProgramInfo = this->createProgramInfo(&flushState->caps(),
802 flushState->allocator(),
803 dstView,
804 flushState->detachAppliedClip(),
805 flushState->dstProxyView());
806 }
Robert Phillips901aff02019-10-08 12:32:56 -0400807
Greg Daniel0b002e22019-08-12 13:25:36 -0400808 GrMesh* mesh = flushState->allocator()->make<GrMesh>(GrPrimitiveType::kTriangles);
Robert Phillips8053c972019-11-21 10:44:53 -0500809 mesh->setIndexedInstanced(std::move(fIndexBuffer), fIndexCount,
810 std::move(fInstanceBuffer), fInstanceCount,
811 fBaseInstance, GrPrimitiveRestart::kNo);
Greg Danielf793de12019-09-05 13:23:23 -0400812 mesh->setVertexData(std::move(fVertexBuffer));
Robert Phillips8053c972019-11-21 10:44:53 -0500813
814 flushState->opsRenderPass()->draw(*fProgramInfo, mesh, 1, this->bounds());
Chris Dalton133944a2018-11-16 23:30:29 -0500815}
816
817// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600818static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500819 Sk2f devRadii = devScale * cornerRadii;
820 if (devRadii[1] < devRadii[0]) {
821 devRadii = SkNx_shuffle<1,0>(devRadii);
822 }
823 float minDevRadius = SkTMax(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
824 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
825 // This threshold was arrived at subjevtively on an NVIDIA chip.
826 return minDevRadius * minDevRadius * 5 > devRadii[1];
827}
828
Chris Dalton0dffbab2019-03-27 13:08:50 -0600829static bool can_use_hw_derivatives_with_coverage(
830 const Sk2f& devScale, const SkVector& cornerRadii) {
831 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500832}
833
834// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600835static bool can_use_hw_derivatives_with_coverage(
836 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500837 if (!shaderCaps.shaderDerivativeSupport()) {
838 return false;
839 }
840
841 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
842 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
843 Sk2f devScale = (x*x + y*y).sqrt();
844 switch (rrect.getType()) {
845 case SkRRect::kEmpty_Type:
846 case SkRRect::kRect_Type:
847 return true;
848
849 case SkRRect::kOval_Type:
850 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600851 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500852
853 case SkRRect::kNinePatch_Type: {
854 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
855 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
856 Sk2f minRadii = Sk2f::Min(r0, r1);
857 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600858 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
859 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500860 }
861
862 case SkRRect::kComplex_Type: {
863 for (int i = 0; i < 4; ++i) {
864 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600865 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500866 return false;
867 }
868 }
869 return true;
870 }
871 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600872 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500873}