blob: 5858dc2538a7ee01ee50c278189e0dcac42e7e74 [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
461 // TODO: need to also give this to the recording context
462 fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, dstView,
463 std::move(appliedClip), dstProxyView);
464}
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&,
635 FPCoordTransformIter&& transformIter) override {
636 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
637 }
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&,
741 FPCoordTransformIter&& transformIter) override {
742 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
743 }
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}