blob: 06c8368e245a96f572f333e51312509900ae5da2 [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
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040010#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#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"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040018#include "src/gpu/GrResourceProvider.h"
Chris Dalton3c636f02021-07-08 14:50:57 -060019#include "src/gpu/GrVertexWriter.h"
20#include "src/gpu/GrVx.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
22#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
23#include "src/gpu/glsl/GrGLSLVarying.h"
24#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Robert Phillipscad8fba2020-03-20 15:39:29 -040025#include "src/gpu/ops/GrMeshDrawOp.h"
Robert Phillipsce978572020-02-28 11:56:44 -050026#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillips366176b2020-02-26 11:40:50 -050027
28namespace {
29
Robert Phillipscad8fba2020-03-20 15:39:29 -040030class FillRRectOp : public GrMeshDrawOp {
Robert Phillips360ec182020-03-26 13:29:50 -040031private:
32 using Helper = GrSimpleMeshDrawOpHelper;
33
Robert Phillips366176b2020-02-26 11:40:50 -050034public:
35 DEFINE_OP_CLASS_ID
36
Herb Derbyc76d4092020-10-07 16:46:15 -040037 static GrOp::Owner Make(GrRecordingContext*,
Chris Dalton3c636f02021-07-08 14:50:57 -060038 SkArenaAlloc*,
Herb Derbyc76d4092020-10-07 16:46:15 -040039 GrPaint&&,
40 const SkMatrix& viewMatrix,
41 const SkRRect&,
Chris Dalton61d694d2021-03-22 00:00:52 -060042 const SkRect& localRect,
Chris Dalton4f447342021-03-12 12:09:12 -070043 GrAA);
Robert Phillips366176b2020-02-26 11:40:50 -050044
45 const char* name() const final { return "GrFillRRectOp"; }
46
Robert Phillips360ec182020-03-26 13:29:50 -040047 FixedFunctionFlags fixedFunctionFlags() const final { return fHelper.fixedFunctionFlags(); }
48
Chris Dalton57ab06c2021-04-22 12:57:28 -060049 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) final;
Herb Derbye25c3002020-10-27 15:57:27 -040050 CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) final;
Robert Phillips360ec182020-03-26 13:29:50 -040051
Robert Phillips294723d2021-06-17 09:23:58 -040052 void visitProxies(const GrVisitProxyFunc& func) const override {
Robert Phillips366176b2020-02-26 11:40:50 -050053 if (fProgramInfo) {
Robert Phillips294723d2021-06-17 09:23:58 -040054 fProgramInfo->visitFPProxies(func);
Robert Phillips366176b2020-02-26 11:40:50 -050055 } else {
Robert Phillips294723d2021-06-17 09:23:58 -040056 fHelper.visitProxies(func);
Robert Phillips366176b2020-02-26 11:40:50 -050057 }
58 }
59
Robert Phillips71143952021-06-17 14:55:07 -040060 void onPrepareDraws(GrMeshDrawTarget*) final;
Robert Phillips366176b2020-02-26 11:40:50 -050061
62 void onExecute(GrOpFlushState*, const SkRect& chainBounds) final;
63
64private:
Robert Phillips360ec182020-03-26 13:29:50 -040065 friend class ::GrSimpleMeshDrawOpHelper; // for access to ctor
Herb Derbyc76d4092020-10-07 16:46:15 -040066 friend class ::GrOp; // for access to ctor
Robert Phillips360ec182020-03-26 13:29:50 -040067
68 enum class ProcessorFlags {
Robert Phillips366176b2020-02-26 11:40:50 -050069 kNone = 0,
70 kUseHWDerivatives = 1 << 0,
Chris Daltoncc13b352021-03-05 14:59:01 -070071 kHasLocalCoords = 1 << 1,
72 kWideColor = 1 << 2,
73 kMSAAEnabled = 1 << 3,
74 kFakeNonAA = 1 << 4,
Robert Phillips366176b2020-02-26 11:40:50 -050075 };
Chris Daltoncc13b352021-03-05 14:59:01 -070076 constexpr static int kNumProcessorFlags = 5;
Robert Phillips366176b2020-02-26 11:40:50 -050077
Robert Phillips360ec182020-03-26 13:29:50 -040078 GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(ProcessorFlags);
Robert Phillips366176b2020-02-26 11:40:50 -050079
80 class Processor;
81
Herb Derbyc76d4092020-10-07 16:46:15 -040082 FillRRectOp(GrProcessorSet*,
Robert Phillips360ec182020-03-26 13:29:50 -040083 const SkPMColor4f& paintColor,
Chris Dalton3c636f02021-07-08 14:50:57 -060084 SkArenaAlloc*,
85 const SkMatrix& viewMatrix,
Robert Phillips360ec182020-03-26 13:29:50 -040086 const SkRRect&,
Chris Dalton61d694d2021-03-22 00:00:52 -060087 const SkRect& localRect,
Chris Dalton3c636f02021-07-08 14:50:57 -060088 ProcessorFlags);
Robert Phillips366176b2020-02-26 11:40:50 -050089
Robert Phillipscad8fba2020-03-20 15:39:29 -040090 GrProgramInfo* programInfo() final { return fProgramInfo; }
91
Robert Phillips366176b2020-02-26 11:40:50 -050092 // Create a GrProgramInfo object in the provided arena
Robert Phillipscad8fba2020-03-20 15:39:29 -040093 void onCreateProgramInfo(const GrCaps*,
94 SkArenaAlloc*,
Adlai Hollere2296f72020-11-19 13:41:26 -050095 const GrSurfaceProxyView& writeView,
Robert Phillipscad8fba2020-03-20 15:39:29 -040096 GrAppliedClip&&,
John Stiles52cb1d02021-06-02 11:58:05 -040097 const GrDstProxyView&,
Greg Daniel42dbca52020-11-20 10:22:43 -050098 GrXferBarrierFlags renderPassXferBarriers,
99 GrLoadOp colorLoadOp) final;
Robert Phillips366176b2020-02-26 11:40:50 -0500100
Robert Phillips360ec182020-03-26 13:29:50 -0400101 Helper fHelper;
Robert Phillips360ec182020-03-26 13:29:50 -0400102 ProcessorFlags fProcessorFlags;
Robert Phillips366176b2020-02-26 11:40:50 -0500103
Chris Dalton3c636f02021-07-08 14:50:57 -0600104 struct Instance {
105 Instance(const SkMatrix& viewMatrix, const SkRRect& rrect, const SkRect& localRect,
106 const SkPMColor4f& color)
107 : fViewMatrix(viewMatrix), fRRect(rrect), fLocalRect(localRect), fColor(color) {}
108 SkMatrix fViewMatrix;
109 SkRRect fRRect;
110 SkRect fLocalRect;
111 SkPMColor4f fColor;
112 Instance* fNext = nullptr;
113 };
114
115 Instance* fHeadInstance;
116 Instance** fTailInstance;
Robert Phillips366176b2020-02-26 11:40:50 -0500117 int fInstanceCount = 1;
Robert Phillips366176b2020-02-26 11:40:50 -0500118
119 sk_sp<const GrBuffer> fInstanceBuffer;
120 sk_sp<const GrBuffer> fVertexBuffer;
121 sk_sp<const GrBuffer> fIndexBuffer;
122 int fBaseInstance = 0;
Robert Phillips366176b2020-02-26 11:40:50 -0500123
124 // If this op is prePrepared the created programInfo will be stored here for use in
125 // onExecute. In the prePrepared case it will have been stored in the record-time arena.
126 GrProgramInfo* fProgramInfo = nullptr;
127
John Stiles7571f9e2020-09-02 22:42:33 -0400128 using INHERITED = GrMeshDrawOp;
Robert Phillips366176b2020-02-26 11:40:50 -0500129};
130
Robert Phillips360ec182020-03-26 13:29:50 -0400131GR_MAKE_BITFIELD_CLASS_OPS(FillRRectOp::ProcessorFlags)
Chris Dalton133944a2018-11-16 23:30:29 -0500132
133// Hardware derivatives are not always accurate enough for highly elliptical corners. This method
134// checks to make sure the corners will still all look good if we use HW derivatives.
Robert Phillips360ec182020-03-26 13:29:50 -0400135static bool can_use_hw_derivatives_with_coverage(const GrShaderCaps&,
136 const SkMatrix&,
137 const SkRRect&);
Chris Dalton133944a2018-11-16 23:30:29 -0500138
Herb Derbyc76d4092020-10-07 16:46:15 -0400139GrOp::Owner FillRRectOp::Make(GrRecordingContext* ctx,
Chris Dalton3c636f02021-07-08 14:50:57 -0600140 SkArenaAlloc* arena,
Herb Derbyc76d4092020-10-07 16:46:15 -0400141 GrPaint&& paint,
142 const SkMatrix& viewMatrix,
143 const SkRRect& rrect,
Chris Dalton61d694d2021-03-22 00:00:52 -0600144 const SkRect& localRect,
Chris Dalton4f447342021-03-12 12:09:12 -0700145 GrAA aa) {
Robert Phillips360ec182020-03-26 13:29:50 -0400146 using Helper = GrSimpleMeshDrawOpHelper;
147
148 const GrCaps* caps = ctx->priv().caps();
149
Chris Daltona77cdee2020-04-03 14:50:43 -0600150 if (!caps->drawInstancedSupport()) {
Chris Dalton133944a2018-11-16 23:30:29 -0500151 return nullptr;
152 }
153
Chris Dalton61d694d2021-03-22 00:00:52 -0600154 // We transform into a normalized -1..+1 space to draw the round rect. If the boundaries are too
155 // large, the math can overflow. The caller can fall back on path rendering if this is the case.
156 if (std::max(rrect.height(), rrect.width()) >= 1e6f) {
157 return nullptr;
158 }
159
Robert Phillips360ec182020-03-26 13:29:50 -0400160 ProcessorFlags flags = ProcessorFlags::kNone;
Chris Daltoncc13b352021-03-05 14:59:01 -0700161 // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we already
162 // use HW derivatives. The only trick will be adjusting the AA outset to account for
163 // perspective. (i.e., outset = 0.5 * z.)
164 if (viewMatrix.hasPerspective()) {
165 return nullptr;
166 }
167 if (can_use_hw_derivatives_with_coverage(*caps->shaderCaps(), viewMatrix, rrect)) {
168 // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms in
169 // coverage mode. We use them as long as the approximation will be accurate enough.
170 flags |= ProcessorFlags::kUseHWDerivatives;
171 }
Chris Dalton4f447342021-03-12 12:09:12 -0700172 if (aa == GrAA::kNo) {
Chris Daltoncc13b352021-03-05 14:59:01 -0700173 flags |= ProcessorFlags::kFakeNonAA;
Chris Dalton133944a2018-11-16 23:30:29 -0500174 }
175
Chris Dalton3c636f02021-07-08 14:50:57 -0600176 return Helper::FactoryHelper<FillRRectOp>(ctx, std::move(paint), arena, viewMatrix, rrect,
177 localRect, flags);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600178}
179
Herb Derbyc76d4092020-10-07 16:46:15 -0400180FillRRectOp::FillRRectOp(GrProcessorSet* processorSet,
Robert Phillips360ec182020-03-26 13:29:50 -0400181 const SkPMColor4f& paintColor,
Chris Dalton3c636f02021-07-08 14:50:57 -0600182 SkArenaAlloc* arena,
183 const SkMatrix& viewMatrix,
Robert Phillips360ec182020-03-26 13:29:50 -0400184 const SkRRect& rrect,
Chris Dalton61d694d2021-03-22 00:00:52 -0600185 const SkRect& localRect,
Chris Dalton3c636f02021-07-08 14:50:57 -0600186 ProcessorFlags processorFlags)
Robert Phillipscad8fba2020-03-20 15:39:29 -0400187 : INHERITED(ClassID())
Chris Daltoncc13b352021-03-05 14:59:01 -0700188 , fHelper(processorSet,
189 (processorFlags & ProcessorFlags::kFakeNonAA)
190 ? GrAAType::kNone
191 : GrAAType::kCoverage) // Use analytic AA even if the RT is MSAA.
Robert Phillips360ec182020-03-26 13:29:50 -0400192 , fProcessorFlags(processorFlags & ~(ProcessorFlags::kHasLocalCoords |
Chris Daltoncc13b352021-03-05 14:59:01 -0700193 ProcessorFlags::kWideColor |
Chris Dalton3c636f02021-07-08 14:50:57 -0600194 ProcessorFlags::kMSAAEnabled))
195 , fHeadInstance(arena->make<Instance>(viewMatrix, rrect, localRect, paintColor))
196 , fTailInstance(&fHeadInstance->fNext) {
Chris Daltoncc13b352021-03-05 14:59:01 -0700197 // FillRRectOp::Make fails if there is perspective.
Chris Dalton3c636f02021-07-08 14:50:57 -0600198 SkASSERT(!viewMatrix.hasPerspective());
199 this->setBounds(viewMatrix.mapRect(rrect.getBounds()),
200 GrOp::HasAABloat(!(processorFlags & ProcessorFlags::kFakeNonAA)),
Chris Dalton4f447342021-03-12 12:09:12 -0700201 GrOp::IsHairline::kNo);
Chris Dalton133944a2018-11-16 23:30:29 -0500202}
203
Chris Dalton57ab06c2021-04-22 12:57:28 -0600204GrProcessorSet::Analysis FillRRectOp::finalize(const GrCaps& caps, const GrAppliedClip* clip,
205 GrClampType clampType) {
Chris Dalton3c636f02021-07-08 14:50:57 -0600206 SkASSERT(fInstanceCount == 1);
207 SkASSERT(fHeadInstance->fNext == nullptr);
Chris Dalton133944a2018-11-16 23:30:29 -0500208
Robert Phillips360ec182020-03-26 13:29:50 -0400209 bool isWideColor;
Chris Dalton57ab06c2021-04-22 12:57:28 -0600210 auto analysis = fHelper.finalizeProcessors(caps, clip, clampType,
Chris Dalton3c636f02021-07-08 14:50:57 -0600211 GrProcessorAnalysisCoverage::kSingleChannel,
212 &fHeadInstance->fColor, &isWideColor);
Robert Phillips360ec182020-03-26 13:29:50 -0400213 if (isWideColor) {
214 fProcessorFlags |= ProcessorFlags::kWideColor;
Brian Osman5105d682019-02-13 16:06:14 -0500215 }
Chris Dalton133944a2018-11-16 23:30:29 -0500216 if (analysis.usesLocalCoords()) {
Robert Phillips360ec182020-03-26 13:29:50 -0400217 fProcessorFlags |= ProcessorFlags::kHasLocalCoords;
Chris Dalton133944a2018-11-16 23:30:29 -0500218 }
Chris Dalton4b62aed2019-01-15 11:53:00 -0700219 return analysis;
Chris Dalton133944a2018-11-16 23:30:29 -0500220}
221
Herb Derbye25c3002020-10-27 15:57:27 -0400222GrOp::CombineResult FillRRectOp::onCombineIfPossible(GrOp* op, SkArenaAlloc*, const GrCaps& caps) {
Robert Phillips366176b2020-02-26 11:40:50 -0500223 const auto& that = *op->cast<FillRRectOp>();
Chris Dalton3c636f02021-07-08 14:50:57 -0600224 if (!fHelper.isCompatible(that.fHelper, caps, this->bounds(), that.bounds()) ||
225 fProcessorFlags != that.fProcessorFlags) {
Robert Phillips360ec182020-03-26 13:29:50 -0400226 return CombineResult::kCannotCombine;
227 }
228
Chris Dalton3c636f02021-07-08 14:50:57 -0600229 *fTailInstance = that.fHeadInstance;
230 fTailInstance = that.fTailInstance;
Chris Dalton133944a2018-11-16 23:30:29 -0500231 fInstanceCount += that.fInstanceCount;
Chris Dalton133944a2018-11-16 23:30:29 -0500232 return CombineResult::kMerged;
233}
234
Robert Phillips366176b2020-02-26 11:40:50 -0500235class FillRRectOp::Processor : public GrGeometryProcessor {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600236public:
Robert Phillips360ec182020-03-26 13:29:50 -0400237 static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, ProcessorFlags flags) {
Mike Kleinf1241082020-12-14 15:59:09 -0600238 return arena->make([&](void* ptr) {
239 return new (ptr) Processor(aaType, flags);
240 });
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500241 }
242
Robert Phillips8053c972019-11-21 10:44:53 -0500243 const char* name() const final { return "GrFillRRectOp::Processor"; }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500244
Robert Phillips8053c972019-11-21 10:44:53 -0500245 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const final {
Chris Daltoncc13b352021-03-05 14:59:01 -0700246 b->addBits(kNumProcessorFlags, (uint32_t)fFlags, "flags");
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500247 }
248
Robert Phillipsf10535f2021-03-23 09:30:45 -0400249 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500250
251private:
Robert Phillips360ec182020-03-26 13:29:50 -0400252 Processor(GrAAType aaType, ProcessorFlags flags)
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500253 : INHERITED(kGrFillRRectOp_Processor_ClassID)
Chris Dalton0dffbab2019-03-27 13:08:50 -0600254 , fFlags(flags) {
Chris Daltoncc13b352021-03-05 14:59:01 -0700255 this->setVertexAttributes(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
Chris Dalton133944a2018-11-16 23:30:29 -0500256
Chris Daltoncc13b352021-03-05 14:59:01 -0700257 fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
258 fInstanceAttribs.emplace_back("translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600259 fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
260 fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
261 fColorAttrib = &fInstanceAttribs.push_back(
Robert Phillips360ec182020-03-26 13:29:50 -0400262 MakeColorAttribute("color", (fFlags & ProcessorFlags::kWideColor)));
263 if (fFlags & ProcessorFlags::kHasLocalCoords) {
Chris Dalton0dffbab2019-03-27 13:08:50 -0600264 fInstanceAttribs.emplace_back(
265 "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
266 }
Chris Dalton3c636f02021-07-08 14:50:57 -0600267 SkASSERT(fInstanceAttribs.count() <= kMaxInstanceAttribs);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600268 this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count());
Chris Dalton0dffbab2019-03-27 13:08:50 -0600269 }
270
Chris Dalton0dffbab2019-03-27 13:08:50 -0600271 static constexpr Attribute kVertexAttribs[] = {
272 {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
273 {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
274 // Coverage only.
275 {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
276
Robert Phillips360ec182020-03-26 13:29:50 -0400277 const ProcessorFlags fFlags;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600278
Chris Dalton3c636f02021-07-08 14:50:57 -0600279 constexpr static int kMaxInstanceAttribs = 6;
280 SkSTArray<kMaxInstanceAttribs, Attribute> fInstanceAttribs;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600281 const Attribute* fColorAttrib;
282
Chris Daltoncc13b352021-03-05 14:59:01 -0700283 class Impl;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500284
John Stiles7571f9e2020-09-02 22:42:33 -0400285 using INHERITED = GrGeometryProcessor;
Chris Dalton0dffbab2019-03-27 13:08:50 -0600286};
287
Robert Phillips787fd9d2021-03-22 14:48:09 -0400288constexpr GrGeometryProcessor::Attribute FillRRectOp::Processor::kVertexAttribs[];
Chris Dalton0dffbab2019-03-27 13:08:50 -0600289
290// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear
Chris Dalton133944a2018-11-16 23:30:29 -0500291// coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal
292// edges. The Vertex struct tells the shader where to place its vertex within a normalized
293// ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode.
Chris Dalton0dffbab2019-03-27 13:08:50 -0600294struct CoverageVertex {
Chris Dalton133944a2018-11-16 23:30:29 -0500295 std::array<float, 4> fRadiiSelector;
296 std::array<float, 2> fCorner;
297 std::array<float, 2> fRadiusOutset;
298 std::array<float, 2> fAABloatDirection;
299 float fCoverage;
300 float fIsLinearCoverage;
Chris Dalton133944a2018-11-16 23:30:29 -0500301};
302
303// This is the offset (when multiplied by radii) from the corners of a bounding box to the vertices
304// of its inscribed octagon. We draw the outside portion of arcs with quarter-octagons rather than
305// rectangles.
306static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2);
307
Chris Daltoncc13b352021-03-05 14:59:01 -0700308static constexpr CoverageVertex kVertexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500309 // Left inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700310 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
311 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500312
313 // Top inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700314 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
315 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500316
317 // Right inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700318 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
319 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500320
321 // Bottom inset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700322 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
323 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500324
325
326 // Left outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700327 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
328 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500329
330 // Top outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700331 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
332 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500333
334 // Right outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700335 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
336 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500337
338 // Bottom outset edge.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700339 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
340 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
Chris Dalton133944a2018-11-16 23:30:29 -0500341
342
343 // Top-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700344 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
345 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
346 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
347 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
348 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
349 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500350
351 // Top-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700352 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
353 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
354 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
355 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
356 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
357 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500358
359 // Bottom-right corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700360 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
361 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
362 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
363 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
364 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
365 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
Chris Dalton133944a2018-11-16 23:30:29 -0500366
367 // Bottom-left corner.
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700368 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
369 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
370 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
371 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
Chris Dalton2d07e862018-11-26 12:30:47 -0700372 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700373 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
Chris Dalton133944a2018-11-16 23:30:29 -0500374
Chris Daltoncc13b352021-03-05 14:59:01 -0700375GR_DECLARE_STATIC_UNIQUE_KEY(gVertexBufferKey);
Chris Dalton133944a2018-11-16 23:30:29 -0500376
Chris Daltoncc13b352021-03-05 14:59:01 -0700377static constexpr uint16_t kIndexData[] = {
Chris Dalton133944a2018-11-16 23:30:29 -0500378 // Inset octagon (solid coverage).
379 0, 1, 7,
380 1, 2, 7,
381 7, 2, 6,
382 2, 3, 6,
383 6, 3, 5,
384 3, 4, 5,
385
386 // AA borders (linear coverage).
387 0, 1, 8, 1, 9, 8,
388 2, 3, 10, 3, 11, 10,
389 4, 5, 12, 5, 13, 12,
390 6, 7, 14, 7, 15, 14,
391
392 // Top-left arc.
393 16, 17, 21,
394 17, 21, 18,
395 21, 18, 20,
396 18, 20, 19,
397
398 // Top-right arc.
399 22, 23, 27,
400 23, 27, 24,
401 27, 24, 26,
402 24, 26, 25,
403
404 // Bottom-right arc.
405 28, 29, 33,
406 29, 33, 30,
407 33, 30, 32,
408 30, 32, 31,
409
410 // Bottom-left arc.
411 34, 35, 39,
412 35, 39, 36,
413 39, 36, 38,
414 36, 38, 37};
415
Chris Daltoncc13b352021-03-05 14:59:01 -0700416GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
Greg Danielf793de12019-09-05 13:23:23 -0400417
Robert Phillips71143952021-06-17 14:55:07 -0400418void FillRRectOp::onPrepareDraws(GrMeshDrawTarget* target) {
Chris Daltoncc13b352021-03-05 14:59:01 -0700419 // We request no multisample, but some platforms don't support disabling it on MSAA targets.
Chris Dalton2517ce32021-04-13 00:21:15 -0600420 if (target->usesMSAASurface() && !target->caps().multisampleDisableSupport()) {
Chris Daltoncc13b352021-03-05 14:59:01 -0700421 fProcessorFlags |= ProcessorFlags::kMSAAEnabled;
422 }
423
Chris Dalton3c636f02021-07-08 14:50:57 -0600424 if (!fProgramInfo) {
425 this->createProgramInfo(target);
426 }
427
428 size_t instanceStride = fProgramInfo->geomProc().instanceStride();
429
430 if (GrVertexWriter instanceWrter = target->makeVertexSpace(instanceStride, fInstanceCount,
431 &fInstanceBuffer, &fBaseInstance)) {
432 SkDEBUGCODE(auto end = instanceWrter.makeOffset(instanceStride * fInstanceCount));
433 for (Instance* i = fHeadInstance; i; i = i->fNext) {
434 auto [l, t, r, b] = i->fRRect.rect();
435
436 // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space.
437 SkMatrix m;
438 // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b].
439 m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2);
440 // Map to device space.
441 m.postConcat(i->fViewMatrix);
442
443 // Convert the radii to [-1, -1, +1, +1] space and write their attribs.
444 grvx::float4 radiiX, radiiY;
445 grvx::strided_load2(&SkRRectPriv::GetRadiiArray(i->fRRect)->fX, radiiX, radiiY);
446 radiiX *= 2 / (r - l);
447 radiiY *= 2 / (b - t);
448
449 instanceWrter.write(
450 m.getScaleX(), m.getSkewX(), m.getSkewY(), m.getScaleY(),
451 m.getTranslateX(), m.getTranslateY(),
452 radiiX,
453 radiiY,
454 GrVertexColor(i->fColor, fProcessorFlags & ProcessorFlags::kWideColor),
455 GrVertexWriter::If(fProcessorFlags & ProcessorFlags::kHasLocalCoords,
456 i->fLocalRect));
457 }
458 SkASSERT(instanceWrter == end);
Greg Danielf793de12019-09-05 13:23:23 -0400459 }
460
Chris Daltoncc13b352021-03-05 14:59:01 -0700461 GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
Greg Danielf793de12019-09-05 13:23:23 -0400462
Chris Daltoncc13b352021-03-05 14:59:01 -0700463 fIndexBuffer = target->resourceProvider()->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
464 sizeof(kIndexData),
465 kIndexData, gIndexBufferKey);
Greg Danielf793de12019-09-05 13:23:23 -0400466
Chris Daltoncc13b352021-03-05 14:59:01 -0700467 GR_DEFINE_STATIC_UNIQUE_KEY(gVertexBufferKey);
Greg Danielf793de12019-09-05 13:23:23 -0400468
Chris Daltoncc13b352021-03-05 14:59:01 -0700469 fVertexBuffer = target->resourceProvider()->findOrMakeStaticBuffer(GrGpuBufferType::kVertex,
470 sizeof(kVertexData),
471 kVertexData,
472 gVertexBufferKey);
Greg Danielf793de12019-09-05 13:23:23 -0400473}
474
Chris Daltoncc13b352021-03-05 14:59:01 -0700475class FillRRectOp::Processor::Impl : public GrGLSLGeometryProcessor {
Chris Dalton133944a2018-11-16 23:30:29 -0500476 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
John Stiles4d7ac492021-03-09 20:16:43 -0500477 GrGLSLVertexBuilder* v = args.fVertBuilder;
478 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
479
Robert Phillips787fd9d2021-03-22 14:48:09 -0400480 const auto& proc = args.fGeomProc.cast<Processor>();
Robert Phillips360ec182020-03-26 13:29:50 -0400481 bool useHWDerivatives = (proc.fFlags & ProcessorFlags::kUseHWDerivatives);
Chris Dalton133944a2018-11-16 23:30:29 -0500482
Chris Dalton0dffbab2019-03-27 13:08:50 -0600483 SkASSERT(proc.vertexStride() == sizeof(CoverageVertex));
484
Chris Dalton133944a2018-11-16 23:30:29 -0500485 GrGLSLVaryingHandler* varyings = args.fVaryingHandler;
486 varyings->emitAttributes(proc);
John Stiles4d7ac492021-03-09 20:16:43 -0500487 f->codeAppendf("half4 %s;", args.fOutputColor);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600488 varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor,
Chris Dalton133944a2018-11-16 23:30:29 -0500489 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
490
491 // Emit the vertex shader.
Chris Daltoncc13b352021-03-05 14:59:01 -0700492 // When MSAA is enabled, we need to make sure every sample gets lit up on pixels that have
493 // fractional coverage. We do this by making the ramp wider.
494 v->codeAppendf("float aa_bloat_multiplier = %i;",
495 (proc.fFlags & ProcessorFlags::kMSAAEnabled)
496 ? 2 // Outset an entire pixel (2 radii).
497 : (!(proc.fFlags & ProcessorFlags::kFakeNonAA))
498 ? 1 // Outset one half pixel (1 radius).
499 : 0); // No AA bloat.
500
Chris Dalton133944a2018-11-16 23:30:29 -0500501 // Unpack vertex attribs.
502 v->codeAppend("float2 corner = corner_and_radius_outsets.xy;");
503 v->codeAppend("float2 radius_outset = corner_and_radius_outsets.zw;");
504 v->codeAppend("float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
Chris Dalton133944a2018-11-16 23:30:29 -0500505 v->codeAppend("float is_linear_coverage = aa_bloat_and_coverage.w;");
506
507 // Find the amount to bloat each edge for AA (in source space).
508 v->codeAppend("float2 pixellength = inversesqrt("
509 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
510 v->codeAppend("float4 normalized_axis_dirs = skew * pixellength.xyxy;");
511 v->codeAppend("float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
512 "abs(normalized_axis_dirs.zw));");
513 v->codeAppend("float2 aa_bloatradius = axiswidths * pixellength * .5;");
514
515 // Identify our radii.
Mike Reedd3efa992018-11-28 13:13:15 +0000516 v->codeAppend("float4 radii_and_neighbors = radii_selector"
517 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
518 v->codeAppend("float2 radii = radii_and_neighbors.xy;");
519 v->codeAppend("float2 neighbor_radii = radii_and_neighbors.zw;");
Chris Dalton133944a2018-11-16 23:30:29 -0500520
Chris Daltoncc13b352021-03-05 14:59:01 -0700521 v->codeAppend("float coverage_multiplier = 1;");
Chris Dalton133944a2018-11-16 23:30:29 -0500522 v->codeAppend("if (any(greaterThan(aa_bloatradius, float2(1)))) {");
Chris Daltoncc13b352021-03-05 14:59:01 -0700523 // The rrect is more narrow than a half-pixel AA coverage ramp. We can't
524 // draw as-is or else opposite AA borders will overlap. Instead, fudge the
525 // size up to the width of a coverage ramp, and then reduce total coverage
526 // to make the rect appear more thin.
Chris Dalton133944a2018-11-16 23:30:29 -0500527 v->codeAppend( "corner = max(abs(corner), aa_bloatradius) * sign(corner);");
Chris Daltoncc13b352021-03-05 14:59:01 -0700528 v->codeAppend( "coverage_multiplier = 1 / (max(aa_bloatradius.x, 1) * "
529 "max(aa_bloatradius.y, 1));");
Chris Dalton133944a2018-11-16 23:30:29 -0500530 // Set radii to zero to ensure we take the "linear coverage" codepath.
531 // (The "coverage" variable only has effect in the linear codepath.)
532 v->codeAppend( "radii = float2(0);");
533 v->codeAppend("}");
534
Chris Daltoncc13b352021-03-05 14:59:01 -0700535 // Unpack coverage.
536 v->codeAppend("float coverage = aa_bloat_and_coverage.z;");
537 if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
538 // MSAA has a wider ramp that goes from -.5 to 1.5 instead of 0 to 1.
539 v->codeAppendf("coverage = (coverage - .5) * aa_bloat_multiplier + .5;");
540 }
541
542 v->codeAppend("if (any(lessThan(radii, aa_bloatradius * 1.5))) {");
Chris Dalton133944a2018-11-16 23:30:29 -0500543 // The radii are very small. Demote this arc to a sharp 90 degree corner.
Chris Daltoncc13b352021-03-05 14:59:01 -0700544 v->codeAppend( "radii = float2(0);");
545 // Convert to a standard picture frame for an AA rect instead of the round
546 // rect geometry.
547 v->codeAppend( "aa_bloat_direction = sign(corner);");
548 v->codeAppend( "if (coverage > .5) {"); // Are we an inset edge?
549 v->codeAppend( "aa_bloat_direction = -aa_bloat_direction;");
550 v->codeAppend( "}");
Chris Dalton133944a2018-11-16 23:30:29 -0500551 v->codeAppend( "is_linear_coverage = 1;");
552 v->codeAppend("} else {");
Chris Daltoncc13b352021-03-05 14:59:01 -0700553 // Don't let radii get smaller than a coverage ramp plus an extra half
554 // pixel for MSAA. Always use the same amount so we don't pop when
555 // switching between MSAA and coverage.
556 v->codeAppend( "radii = clamp(radii, pixellength * 1.5, 2 - pixellength * 1.5);");
557 v->codeAppend( "neighbor_radii = clamp(neighbor_radii, pixellength * 1.5, "
558 "2 - pixellength * 1.5);");
Mike Reedd3efa992018-11-28 13:13:15 +0000559 // Don't let neighboring radii get closer together than 1/16 pixel.
560 v->codeAppend( "float2 spacing = 2 - radii - neighbor_radii;");
561 v->codeAppend( "float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
562 v->codeAppend( "radii -= extra_pad * .5;");
Chris Dalton133944a2018-11-16 23:30:29 -0500563 v->codeAppend("}");
Chris Dalton133944a2018-11-16 23:30:29 -0500564
565 // Find our vertex position, adjusted for radii and bloated for AA. Our rect is drawn in
566 // normalized [-1,-1,+1,+1] space.
Chris Daltoncc13b352021-03-05 14:59:01 -0700567 v->codeAppend("float2 aa_outset = "
568 "aa_bloat_direction * aa_bloatradius * aa_bloat_multiplier;");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700569 v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;");
Chris Dalton133944a2018-11-16 23:30:29 -0500570
Chris Daltoncc13b352021-03-05 14:59:01 -0700571 v->codeAppend("if (coverage > .5) {"); // Are we an inset edge?
572 // Don't allow the aa insets to overlap. i.e., Don't let them inset past
573 // the center (x=y=0). Since we don't allow the rect to become thinner
574 // than 1px, this should only happen when using MSAA, where we inset by an
575 // entire pixel instead of half.
576 v->codeAppend( "if (aa_bloat_direction.x != 0 && vertexpos.x * corner.x < 0) {");
577 v->codeAppend( "float backset = abs(vertexpos.x);");
578 v->codeAppend( "vertexpos.x = 0;");
579 v->codeAppend( "vertexpos.y += "
580 "backset * sign(corner.y) * pixellength.y/pixellength.x;");
581 v->codeAppend( "coverage = (coverage - .5) * abs(corner.x) / "
582 "(abs(corner.x) + backset) + .5;");
583 v->codeAppend( "}");
584 v->codeAppend( "if (aa_bloat_direction.y != 0 && vertexpos.y * corner.y < 0) {");
585 v->codeAppend( "float backset = abs(vertexpos.y);");
586 v->codeAppend( "vertexpos.y = 0;");
587 v->codeAppend( "vertexpos.x += "
588 "backset * sign(corner.x) * pixellength.x/pixellength.y;");
589 v->codeAppend( "coverage = (coverage - .5) * abs(corner.y) / "
590 "(abs(corner.y) + backset) + .5;");
591 v->codeAppend( "}");
592 v->codeAppend("}");
593
Michael Ludwig553db622020-06-19 10:47:30 -0400594 // Write positions
Chris Dalton133944a2018-11-16 23:30:29 -0500595 GrShaderVar localCoord("", kFloat2_GrSLType);
Robert Phillips360ec182020-03-26 13:29:50 -0400596 if (proc.fFlags & ProcessorFlags::kHasLocalCoords) {
Chris Dalton133944a2018-11-16 23:30:29 -0500597 v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + "
598 "local_rect.zw * (1 + vertexpos)) * .5;");
Michael Ludwig553db622020-06-19 10:47:30 -0400599 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
Chris Dalton133944a2018-11-16 23:30:29 -0500600 }
Chris Dalton133944a2018-11-16 23:30:29 -0500601
602 // Transform to device space.
603 v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
604 v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;");
605 gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord");
606
607 // Setup interpolants for coverage.
608 GrGLSLVarying arcCoord(useHWDerivatives ? kFloat2_GrSLType : kFloat4_GrSLType);
609 varyings->addVarying("arccoord", &arcCoord);
610 v->codeAppend("if (0 != is_linear_coverage) {");
611 // We are a non-corner piece: Set x=0 to indicate built-in coverage, and
612 // interpolate linear coverage across y.
Chris Daltoncc13b352021-03-05 14:59:01 -0700613 v->codeAppendf( "%s.xy = float2(0, coverage * coverage_multiplier);",
614 arcCoord.vsOut());
Chris Dalton133944a2018-11-16 23:30:29 -0500615 v->codeAppend("} else {");
Chris Daltonaa71f0a2018-11-21 18:14:45 -0700616 // Find the normalized arc coordinates for our corner ellipse.
617 // (i.e., the coordinate system where x^2 + y^2 == 1).
618 v->codeAppend( "float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
Chris Dalton133944a2018-11-16 23:30:29 -0500619 // We are a corner piece: Interpolate the arc coordinates for coverage.
620 // Emit x+1 to ensure no pixel in the arc has a x value of 0 (since x=0
621 // instructs the fragment shader to use linear coverage).
622 v->codeAppendf( "%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.vsOut());
623 if (!useHWDerivatives) {
624 // The gradient is order-1: Interpolate it across arccoord.zw.
625 v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);");
626 v->codeAppendf("%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.vsOut());
627 }
628 v->codeAppend("}");
629
630 // Emit the fragment shader.
Chris Dalton133944a2018-11-16 23:30:29 -0500631 f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn());
632 f->codeAppendf("half coverage;");
633 f->codeAppendf("if (0 == x_plus_1) {");
Chris Dalton0dffbab2019-03-27 13:08:50 -0600634 f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage).
Chris Dalton133944a2018-11-16 23:30:29 -0500635 f->codeAppendf("} else {");
636 f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1
637 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1
638 if (useHWDerivatives) {
639 f->codeAppendf("float fnwidth = fwidth(fn);");
640 } else {
641 // The gradient is interpolated across arccoord.zw.
642 f->codeAppendf("float gx=%s.z, gy=%s.w;", arcCoord.fsIn(), arcCoord.fsIn());
643 f->codeAppendf("float fnwidth = abs(gx) + abs(gy);");
644 }
Chris Daltoncc13b352021-03-05 14:59:01 -0700645 f->codeAppendf( "coverage = .5 - half(fn/fnwidth);");
646 if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
647 // MSAA uses ramps larger than 1px, so we need to clamp in both branches.
648 f->codeAppendf("}");
649 }
650 f->codeAppendf("coverage = clamp(coverage, 0, 1);");
651 if (!(proc.fFlags & ProcessorFlags::kMSAAEnabled)) {
652 // When not using MSAA, we only need to clamp in the "arc" branch.
653 f->codeAppendf("}");
654 }
655 if (proc.fFlags & ProcessorFlags::kFakeNonAA) {
656 f->codeAppendf("coverage = (coverage >= .5) ? 1 : 0;");
657 }
John Stiles4d7ac492021-03-09 20:16:43 -0500658 f->codeAppendf("half4 %s = half4(coverage);", args.fOutputCoverage);
Chris Dalton133944a2018-11-16 23:30:29 -0500659 }
660
Brian Salomon5a328282021-04-14 10:32:25 -0400661 void setData(const GrGLSLProgramDataManager&,
662 const GrShaderCaps&,
663 const GrGeometryProcessor&) override {}
Chris Dalton133944a2018-11-16 23:30:29 -0500664};
665
Chris Dalton0dffbab2019-03-27 13:08:50 -0600666
Robert Phillipsf10535f2021-03-23 09:30:45 -0400667GrGLSLGeometryProcessor* FillRRectOp::Processor::createGLSLInstance(const GrShaderCaps&) const {
Chris Daltoncc13b352021-03-05 14:59:01 -0700668 return new Impl();
Chris Dalton133944a2018-11-16 23:30:29 -0500669}
670
Robert Phillipscad8fba2020-03-20 15:39:29 -0400671void FillRRectOp::onCreateProgramInfo(const GrCaps* caps,
672 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500673 const GrSurfaceProxyView& writeView,
Robert Phillipscad8fba2020-03-20 15:39:29 -0400674 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400675 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500676 GrXferBarrierFlags renderPassXferBarriers,
677 GrLoadOp colorLoadOp) {
Robert Phillips360ec182020-03-26 13:29:50 -0400678 GrGeometryProcessor* gp = Processor::Make(arena, fHelper.aaType(), fProcessorFlags);
Brian Salomon8afde5f2020-04-01 16:22:00 -0400679 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, std::move(appliedClip),
Greg Danield358cbe2020-09-11 09:33:54 -0400680 dstProxyView, gp, GrPrimitiveType::kTriangles,
Greg Daniel42dbca52020-11-20 10:22:43 -0500681 renderPassXferBarriers, colorLoadOp);
Robert Phillips8053c972019-11-21 10:44:53 -0500682}
683
Robert Phillips366176b2020-02-26 11:40:50 -0500684void FillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
Robert Phillips8053c972019-11-21 10:44:53 -0500685 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
686 return; // Setup failed.
687 }
688
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600689 flushState->bindPipelineAndScissorClip(*fProgramInfo, this->bounds());
Robert Phillips787fd9d2021-03-22 14:48:09 -0400690 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
Greg Daniel426274b2020-07-20 11:37:38 -0400691 flushState->bindBuffers(std::move(fIndexBuffer), std::move(fInstanceBuffer),
692 std::move(fVertexBuffer));
Chris Daltoncc13b352021-03-05 14:59:01 -0700693 flushState->drawIndexedInstanced(SK_ARRAY_COUNT(kIndexData), 0, fInstanceCount, fBaseInstance,
694 0);
Chris Dalton133944a2018-11-16 23:30:29 -0500695}
696
697// Will the given corner look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600698static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) {
Chris Dalton133944a2018-11-16 23:30:29 -0500699 Sk2f devRadii = devScale * cornerRadii;
700 if (devRadii[1] < devRadii[0]) {
701 devRadii = SkNx_shuffle<1,0>(devRadii);
702 }
Brian Osman788b9162020-02-07 10:36:46 -0500703 float minDevRadius = std::max(devRadii[0], 1.f); // Shader clamps radius at a minimum of 1.
Chris Dalton133944a2018-11-16 23:30:29 -0500704 // Is the gradient smooth enough for this corner look ok if we use hardware derivatives?
705 // This threshold was arrived at subjevtively on an NVIDIA chip.
706 return minDevRadius * minDevRadius * 5 > devRadii[1];
707}
708
Chris Dalton0dffbab2019-03-27 13:08:50 -0600709static bool can_use_hw_derivatives_with_coverage(
710 const Sk2f& devScale, const SkVector& cornerRadii) {
711 return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii));
Chris Dalton133944a2018-11-16 23:30:29 -0500712}
713
714// Will the given round rect look good if we use HW derivatives?
Chris Dalton0dffbab2019-03-27 13:08:50 -0600715static bool can_use_hw_derivatives_with_coverage(
716 const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) {
Chris Dalton133944a2018-11-16 23:30:29 -0500717 if (!shaderCaps.shaderDerivativeSupport()) {
718 return false;
719 }
720
721 Sk2f x = Sk2f(viewMatrix.getScaleX(), viewMatrix.getSkewX());
722 Sk2f y = Sk2f(viewMatrix.getSkewY(), viewMatrix.getScaleY());
723 Sk2f devScale = (x*x + y*y).sqrt();
724 switch (rrect.getType()) {
725 case SkRRect::kEmpty_Type:
726 case SkRRect::kRect_Type:
727 return true;
728
729 case SkRRect::kOval_Type:
730 case SkRRect::kSimple_Type:
Chris Dalton0dffbab2019-03-27 13:08:50 -0600731 return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii());
Chris Dalton133944a2018-11-16 23:30:29 -0500732
733 case SkRRect::kNinePatch_Type: {
734 Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect));
735 Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2);
736 Sk2f minRadii = Sk2f::Min(r0, r1);
737 Sk2f maxRadii = Sk2f::Max(r0, r1);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600738 return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) &&
739 can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1]));
Chris Dalton133944a2018-11-16 23:30:29 -0500740 }
741
742 case SkRRect::kComplex_Type: {
743 for (int i = 0; i < 4; ++i) {
744 auto corner = static_cast<SkRRect::Corner>(i);
Chris Dalton0dffbab2019-03-27 13:08:50 -0600745 if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) {
Chris Dalton133944a2018-11-16 23:30:29 -0500746 return false;
747 }
748 }
749 return true;
750 }
751 }
Chris Dalton0dffbab2019-03-27 13:08:50 -0600752 SK_ABORT("Invalid round rect type.");
Chris Dalton133944a2018-11-16 23:30:29 -0500753}
Robert Phillips366176b2020-02-26 11:40:50 -0500754
755} // anonymous namespace
756
757
Herb Derbyc76d4092020-10-07 16:46:15 -0400758GrOp::Owner GrFillRRectOp::Make(GrRecordingContext* ctx,
Chris Dalton3c636f02021-07-08 14:50:57 -0600759 SkArenaAlloc* arena,
Herb Derbyc76d4092020-10-07 16:46:15 -0400760 GrPaint&& paint,
761 const SkMatrix& viewMatrix,
762 const SkRRect& rrect,
Chris Dalton61d694d2021-03-22 00:00:52 -0600763 const SkRect& localRect,
Chris Dalton4f447342021-03-12 12:09:12 -0700764 GrAA aa) {
Chris Dalton3c636f02021-07-08 14:50:57 -0600765 return FillRRectOp::Make(ctx, arena, std::move(paint), viewMatrix, rrect, localRect, aa);
Robert Phillips366176b2020-02-26 11:40:50 -0500766}
767
Chris Dalton61d694d2021-03-22 00:00:52 -0600768
Robert Phillips366176b2020-02-26 11:40:50 -0500769#if GR_TEST_UTILS
770
771#include "src/gpu/GrDrawOpTest.h"
772
773GR_DRAW_OP_TEST_DEFINE(FillRRectOp) {
Chris Dalton3c636f02021-07-08 14:50:57 -0600774 SkArenaAlloc arena(64 * sizeof(float));
Robert Phillips366176b2020-02-26 11:40:50 -0500775 SkMatrix viewMatrix = GrTest::TestMatrix(random);
Chris Dalton4f447342021-03-12 12:09:12 -0700776 GrAA aa = GrAA(random->nextBool());
Robert Phillips366176b2020-02-26 11:40:50 -0500777
778 SkRect rect = GrTest::TestRect(random);
779 float w = rect.width();
780 float h = rect.height();
781
782 SkRRect rrect;
783 // TODO: test out other rrect configurations
784 rrect.setNinePatch(rect, w / 3.0f, h / 4.0f, w / 5.0f, h / 6.0);
785
786 return GrFillRRectOp::Make(context,
Chris Dalton3c636f02021-07-08 14:50:57 -0600787 &arena,
Robert Phillips360ec182020-03-26 13:29:50 -0400788 std::move(paint),
Robert Phillips366176b2020-02-26 11:40:50 -0500789 viewMatrix,
790 rrect,
Chris Dalton61d694d2021-03-22 00:00:52 -0600791 rrect.rect(),
Chris Dalton4f447342021-03-12 12:09:12 -0700792 aa);
Robert Phillips366176b2020-02-26 11:40:50 -0500793}
794
795#endif