1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/StrokeRectOp.h"
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlignedStorage.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDefaultGeoProcFactory.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrQuad.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/FillRectOp.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
51*c8dee2aaSAndroid Build Coastguard Worker #include <array>
52*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
53*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
54*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
57*c8dee2aaSAndroid Build Coastguard Worker class GrGpuBuffer;
58*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
59*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc;
60*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
63*c8dee2aaSAndroid Build Coastguard Worker class SurfaceDrawContext;
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh::StrokeRectOp {
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker namespace {
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker // This emits line primitives for hairlines, so only support hairlines if allowed by caps. Otherwise
73*c8dee2aaSAndroid Build Coastguard Worker // we support all hairlines, bevels, and miters, but not round joins. Also, check whether the miter
74*c8dee2aaSAndroid Build Coastguard Worker // limit makes a miter join effectively beveled. If the miter is effectively beveled, it is only
75*c8dee2aaSAndroid Build Coastguard Worker // supported when using an AA stroke.
allowed_stroke(const GrCaps * caps,const SkStrokeRec & stroke,GrAA aa,bool * isMiter)76*c8dee2aaSAndroid Build Coastguard Worker inline bool allowed_stroke(const GrCaps* caps, const SkStrokeRec& stroke, GrAA aa, bool* isMiter) {
77*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style ||
78*c8dee2aaSAndroid Build Coastguard Worker stroke.getStyle() == SkStrokeRec::kHairline_Style);
79*c8dee2aaSAndroid Build Coastguard Worker if (caps->avoidLineDraws() && stroke.isHairlineStyle()) {
80*c8dee2aaSAndroid Build Coastguard Worker return false;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker // For hairlines, make bevel and round joins appear the same as mitered ones.
83*c8dee2aaSAndroid Build Coastguard Worker if (!stroke.getWidth()) {
84*c8dee2aaSAndroid Build Coastguard Worker *isMiter = true;
85*c8dee2aaSAndroid Build Coastguard Worker return true;
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker if (stroke.getJoin() == SkPaint::kBevel_Join) {
88*c8dee2aaSAndroid Build Coastguard Worker *isMiter = false;
89*c8dee2aaSAndroid Build Coastguard Worker return aa == GrAA::kYes; // bevel only supported with AA
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker if (stroke.getJoin() == SkPaint::kMiter_Join) {
92*c8dee2aaSAndroid Build Coastguard Worker *isMiter = stroke.getMiter() >= SK_ScalarSqrt2;
93*c8dee2aaSAndroid Build Coastguard Worker // Supported under non-AA only if it remains mitered
94*c8dee2aaSAndroid Build Coastguard Worker return aa == GrAA::kYes || *isMiter;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker return false;
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker
100*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
101*c8dee2aaSAndroid Build Coastguard Worker // Non-AA Stroking
102*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker /* create a triangle strip that strokes the specified rect. There are 8
105*c8dee2aaSAndroid Build Coastguard Worker unique vertices, but we repeat the last 2 to close up. Alternatively we
106*c8dee2aaSAndroid Build Coastguard Worker could use an indices array, and then only send 8 verts, but not sure that
107*c8dee2aaSAndroid Build Coastguard Worker would be faster.
108*c8dee2aaSAndroid Build Coastguard Worker */
init_nonaa_stroke_rect_strip(SkPoint verts[10],const SkRect & rect,SkScalar width)109*c8dee2aaSAndroid Build Coastguard Worker void init_nonaa_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
110*c8dee2aaSAndroid Build Coastguard Worker const SkScalar rad = SkScalarHalf(width);
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker verts[0].set(rect.fLeft + rad, rect.fTop + rad);
113*c8dee2aaSAndroid Build Coastguard Worker verts[1].set(rect.fLeft - rad, rect.fTop - rad);
114*c8dee2aaSAndroid Build Coastguard Worker verts[2].set(rect.fRight - rad, rect.fTop + rad);
115*c8dee2aaSAndroid Build Coastguard Worker verts[3].set(rect.fRight + rad, rect.fTop - rad);
116*c8dee2aaSAndroid Build Coastguard Worker verts[4].set(rect.fRight - rad, rect.fBottom - rad);
117*c8dee2aaSAndroid Build Coastguard Worker verts[5].set(rect.fRight + rad, rect.fBottom + rad);
118*c8dee2aaSAndroid Build Coastguard Worker verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
119*c8dee2aaSAndroid Build Coastguard Worker verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
120*c8dee2aaSAndroid Build Coastguard Worker verts[8] = verts[0];
121*c8dee2aaSAndroid Build Coastguard Worker verts[9] = verts[1];
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker // TODO: we should be catching this higher up the call stack and just draw a single
124*c8dee2aaSAndroid Build Coastguard Worker // non-AA rect
125*c8dee2aaSAndroid Build Coastguard Worker if (2*rad >= rect.width()) {
126*c8dee2aaSAndroid Build Coastguard Worker verts[0].fX = verts[2].fX = verts[4].fX = verts[6].fX = verts[8].fX = rect.centerX();
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker if (2*rad >= rect.height()) {
129*c8dee2aaSAndroid Build Coastguard Worker verts[0].fY = verts[2].fY = verts[4].fY = verts[6].fY = verts[8].fY = rect.centerY();
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker class NonAAStrokeRectOp final : public GrMeshDrawOp {
134*c8dee2aaSAndroid Build Coastguard Worker private:
135*c8dee2aaSAndroid Build Coastguard Worker using Helper = GrSimpleMeshDrawOpHelper;
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker public:
138*c8dee2aaSAndroid Build Coastguard Worker DEFINE_OP_CLASS_ID
139*c8dee2aaSAndroid Build Coastguard Worker
name() const140*c8dee2aaSAndroid Build Coastguard Worker const char* name() const override { return "NonAAStrokeRectOp"; }
141*c8dee2aaSAndroid Build Coastguard Worker
visitProxies(const GrVisitProxyFunc & func) const142*c8dee2aaSAndroid Build Coastguard Worker void visitProxies(const GrVisitProxyFunc& func) const override {
143*c8dee2aaSAndroid Build Coastguard Worker if (fProgramInfo) {
144*c8dee2aaSAndroid Build Coastguard Worker fProgramInfo->visitFPProxies(func);
145*c8dee2aaSAndroid Build Coastguard Worker } else {
146*c8dee2aaSAndroid Build Coastguard Worker fHelper.visitProxies(func);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
Make(GrRecordingContext * context,GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkStrokeRec & stroke,GrAAType aaType)150*c8dee2aaSAndroid Build Coastguard Worker static GrOp::Owner Make(GrRecordingContext* context,
151*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint,
152*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
153*c8dee2aaSAndroid Build Coastguard Worker const SkRect& rect,
154*c8dee2aaSAndroid Build Coastguard Worker const SkStrokeRec& stroke,
155*c8dee2aaSAndroid Build Coastguard Worker GrAAType aaType) {
156*c8dee2aaSAndroid Build Coastguard Worker bool isMiter;
157*c8dee2aaSAndroid Build Coastguard Worker if (!allowed_stroke(context->priv().caps(), stroke, GrAA::kNo, &isMiter)) {
158*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker Helper::InputFlags inputFlags = Helper::InputFlags::kNone;
161*c8dee2aaSAndroid Build Coastguard Worker // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
162*c8dee2aaSAndroid Build Coastguard Worker // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
163*c8dee2aaSAndroid Build Coastguard Worker // when MSAA is enabled because it can cause ugly artifacts.
164*c8dee2aaSAndroid Build Coastguard Worker if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
165*c8dee2aaSAndroid Build Coastguard Worker inputFlags |= Helper::InputFlags::kSnapVerticesToPixelCenters;
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker return Helper::FactoryHelper<NonAAStrokeRectOp>(context, std::move(paint), inputFlags,
168*c8dee2aaSAndroid Build Coastguard Worker viewMatrix, rect,
169*c8dee2aaSAndroid Build Coastguard Worker stroke, aaType);
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker
NonAAStrokeRectOp(GrProcessorSet * processorSet,const SkPMColor4f & color,Helper::InputFlags inputFlags,const SkMatrix & viewMatrix,const SkRect & rect,const SkStrokeRec & stroke,GrAAType aaType)172*c8dee2aaSAndroid Build Coastguard Worker NonAAStrokeRectOp(GrProcessorSet* processorSet, const SkPMColor4f& color,
173*c8dee2aaSAndroid Build Coastguard Worker Helper::InputFlags inputFlags, const SkMatrix& viewMatrix, const SkRect& rect,
174*c8dee2aaSAndroid Build Coastguard Worker const SkStrokeRec& stroke, GrAAType aaType)
175*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(ClassID())
176*c8dee2aaSAndroid Build Coastguard Worker , fHelper(processorSet, aaType, inputFlags) {
177*c8dee2aaSAndroid Build Coastguard Worker fColor = color;
178*c8dee2aaSAndroid Build Coastguard Worker fViewMatrix = viewMatrix;
179*c8dee2aaSAndroid Build Coastguard Worker fRect = rect;
180*c8dee2aaSAndroid Build Coastguard Worker // Sort the rect for hairlines
181*c8dee2aaSAndroid Build Coastguard Worker fRect.sort();
182*c8dee2aaSAndroid Build Coastguard Worker fStrokeWidth = stroke.getWidth();
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker SkScalar rad = SkScalarHalf(fStrokeWidth);
185*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = rect;
186*c8dee2aaSAndroid Build Coastguard Worker bounds.outset(rad, rad);
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker // If our caller snaps to pixel centers then we have to round out the bounds
189*c8dee2aaSAndroid Build Coastguard Worker if (inputFlags & Helper::InputFlags::kSnapVerticesToPixelCenters) {
190*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fStrokeWidth || aaType == GrAAType::kNone);
191*c8dee2aaSAndroid Build Coastguard Worker viewMatrix.mapRect(&bounds);
192*c8dee2aaSAndroid Build Coastguard Worker // We want to be consistent with how we snap non-aa lines. To match what we do in
193*c8dee2aaSAndroid Build Coastguard Worker // GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
194*c8dee2aaSAndroid Build Coastguard Worker // pixel to force us to pixel centers.
195*c8dee2aaSAndroid Build Coastguard Worker bounds.setLTRB(SkScalarFloorToScalar(bounds.fLeft),
196*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(bounds.fTop),
197*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(bounds.fRight),
198*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(bounds.fBottom));
199*c8dee2aaSAndroid Build Coastguard Worker bounds.offset(0.5f, 0.5f);
200*c8dee2aaSAndroid Build Coastguard Worker this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo);
201*c8dee2aaSAndroid Build Coastguard Worker } else {
202*c8dee2aaSAndroid Build Coastguard Worker HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
203*c8dee2aaSAndroid Build Coastguard Worker this->setTransformedBounds(bounds, fViewMatrix, aaBloat,
204*c8dee2aaSAndroid Build Coastguard Worker fStrokeWidth ? IsHairline::kNo : IsHairline::kYes);
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker
fixedFunctionFlags() const208*c8dee2aaSAndroid Build Coastguard Worker FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
209*c8dee2aaSAndroid Build Coastguard Worker
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)210*c8dee2aaSAndroid Build Coastguard Worker GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
211*c8dee2aaSAndroid Build Coastguard Worker GrClampType clampType) override {
212*c8dee2aaSAndroid Build Coastguard Worker // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
213*c8dee2aaSAndroid Build Coastguard Worker return fHelper.finalizeProcessors(caps, clip, clampType, GrProcessorAnalysisCoverage::kNone,
214*c8dee2aaSAndroid Build Coastguard Worker &fColor, nullptr);
215*c8dee2aaSAndroid Build Coastguard Worker }
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker private:
programInfo()218*c8dee2aaSAndroid Build Coastguard Worker GrProgramInfo* programInfo() override { return fProgramInfo; }
219*c8dee2aaSAndroid Build Coastguard Worker
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)220*c8dee2aaSAndroid Build Coastguard Worker void onCreateProgramInfo(const GrCaps* caps,
221*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* arena,
222*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceProxyView& writeView,
223*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface,
224*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip&& clip,
225*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView& dstProxyView,
226*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierFlags renderPassXferBarriers,
227*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp colorLoadOp) override {
228*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* gp;
229*c8dee2aaSAndroid Build Coastguard Worker {
230*c8dee2aaSAndroid Build Coastguard Worker using namespace GrDefaultGeoProcFactory;
231*c8dee2aaSAndroid Build Coastguard Worker Color color(fColor);
232*c8dee2aaSAndroid Build Coastguard Worker LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
233*c8dee2aaSAndroid Build Coastguard Worker ? LocalCoords::kUsePosition_Type
234*c8dee2aaSAndroid Build Coastguard Worker : LocalCoords::kUnused_Type;
235*c8dee2aaSAndroid Build Coastguard Worker gp = GrDefaultGeoProcFactory::Make(arena, color, Coverage::kSolid_Type, localCoordsType,
236*c8dee2aaSAndroid Build Coastguard Worker fViewMatrix);
237*c8dee2aaSAndroid Build Coastguard Worker }
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker GrPrimitiveType primType = (fStrokeWidth > 0) ? GrPrimitiveType::kTriangleStrip
240*c8dee2aaSAndroid Build Coastguard Worker : GrPrimitiveType::kLineStrip;
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, usesMSAASurface,
243*c8dee2aaSAndroid Build Coastguard Worker std::move(clip), dstProxyView, gp, primType,
244*c8dee2aaSAndroid Build Coastguard Worker renderPassXferBarriers, colorLoadOp);
245*c8dee2aaSAndroid Build Coastguard Worker }
246*c8dee2aaSAndroid Build Coastguard Worker
onPrepareDraws(GrMeshDrawTarget * target)247*c8dee2aaSAndroid Build Coastguard Worker void onPrepareDraws(GrMeshDrawTarget* target) override {
248*c8dee2aaSAndroid Build Coastguard Worker if (!fProgramInfo) {
249*c8dee2aaSAndroid Build Coastguard Worker this->createProgramInfo(target);
250*c8dee2aaSAndroid Build Coastguard Worker }
251*c8dee2aaSAndroid Build Coastguard Worker
252*c8dee2aaSAndroid Build Coastguard Worker size_t kVertexStride = fProgramInfo->geomProc().vertexStride();
253*c8dee2aaSAndroid Build Coastguard Worker int vertexCount = kVertsPerHairlineRect;
254*c8dee2aaSAndroid Build Coastguard Worker if (fStrokeWidth > 0) {
255*c8dee2aaSAndroid Build Coastguard Worker vertexCount = kVertsPerStrokeRect;
256*c8dee2aaSAndroid Build Coastguard Worker }
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrBuffer> vertexBuffer;
259*c8dee2aaSAndroid Build Coastguard Worker int firstVertex;
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker void* verts =
262*c8dee2aaSAndroid Build Coastguard Worker target->makeVertexSpace(kVertexStride, vertexCount, &vertexBuffer, &firstVertex);
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker if (!verts) {
265*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Could not allocate vertices\n");
266*c8dee2aaSAndroid Build Coastguard Worker return;
267*c8dee2aaSAndroid Build Coastguard Worker }
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker if (fStrokeWidth > 0) {
272*c8dee2aaSAndroid Build Coastguard Worker init_nonaa_stroke_rect_strip(vertex, fRect, fStrokeWidth);
273*c8dee2aaSAndroid Build Coastguard Worker } else {
274*c8dee2aaSAndroid Build Coastguard Worker // hairline
275*c8dee2aaSAndroid Build Coastguard Worker vertex[0].set(fRect.fLeft, fRect.fTop);
276*c8dee2aaSAndroid Build Coastguard Worker vertex[1].set(fRect.fRight, fRect.fTop);
277*c8dee2aaSAndroid Build Coastguard Worker vertex[2].set(fRect.fRight, fRect.fBottom);
278*c8dee2aaSAndroid Build Coastguard Worker vertex[3].set(fRect.fLeft, fRect.fBottom);
279*c8dee2aaSAndroid Build Coastguard Worker vertex[4].set(fRect.fLeft, fRect.fTop);
280*c8dee2aaSAndroid Build Coastguard Worker }
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker fMesh = target->allocMesh();
283*c8dee2aaSAndroid Build Coastguard Worker fMesh->set(std::move(vertexBuffer), vertexCount, firstVertex);
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)286*c8dee2aaSAndroid Build Coastguard Worker void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
287*c8dee2aaSAndroid Build Coastguard Worker if (!fMesh) {
288*c8dee2aaSAndroid Build Coastguard Worker return;
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Worker flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
292*c8dee2aaSAndroid Build Coastguard Worker flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
293*c8dee2aaSAndroid Build Coastguard Worker flushState->drawMesh(*fMesh);
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const297*c8dee2aaSAndroid Build Coastguard Worker SkString onDumpInfo() const override {
298*c8dee2aaSAndroid Build Coastguard Worker return SkStringPrintf("Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
299*c8dee2aaSAndroid Build Coastguard Worker "StrokeWidth: %.2f\n%s",
300*c8dee2aaSAndroid Build Coastguard Worker fColor.toBytes_RGBA(), fRect.fLeft, fRect.fTop, fRect.fRight,
301*c8dee2aaSAndroid Build Coastguard Worker fRect.fBottom, fStrokeWidth, fHelper.dumpInfo().c_str());
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker #endif
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker // TODO: override onCombineIfPossible
306*c8dee2aaSAndroid Build Coastguard Worker
307*c8dee2aaSAndroid Build Coastguard Worker Helper fHelper;
308*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f fColor;
309*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fViewMatrix;
310*c8dee2aaSAndroid Build Coastguard Worker SkRect fRect;
311*c8dee2aaSAndroid Build Coastguard Worker SkScalar fStrokeWidth;
312*c8dee2aaSAndroid Build Coastguard Worker GrSimpleMesh* fMesh = nullptr;
313*c8dee2aaSAndroid Build Coastguard Worker GrProgramInfo* fProgramInfo = nullptr;
314*c8dee2aaSAndroid Build Coastguard Worker
315*c8dee2aaSAndroid Build Coastguard Worker const static int kVertsPerHairlineRect = 5;
316*c8dee2aaSAndroid Build Coastguard Worker const static int kVertsPerStrokeRect = 10;
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GrMeshDrawOp;
319*c8dee2aaSAndroid Build Coastguard Worker };
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
322*c8dee2aaSAndroid Build Coastguard Worker // AA Stroking
323*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
324*c8dee2aaSAndroid Build Coastguard Worker
325*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
326*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
327*c8dee2aaSAndroid Build Coastguard Worker
stroke_dev_half_size_supported(SkVector devHalfStrokeSize)328*c8dee2aaSAndroid Build Coastguard Worker bool stroke_dev_half_size_supported(SkVector devHalfStrokeSize) {
329*c8dee2aaSAndroid Build Coastguard Worker // Since the horizontal and vertical strokes share internal corners, the coverage value at that
330*c8dee2aaSAndroid Build Coastguard Worker // corner needs to be equal for the horizontal and vertical strokes both.
331*c8dee2aaSAndroid Build Coastguard Worker //
332*c8dee2aaSAndroid Build Coastguard Worker // The inner coverage values will be equal if the horizontal and vertical stroke widths are
333*c8dee2aaSAndroid Build Coastguard Worker // equal (in which case innerCoverage is same for all sides of the rects) or if the horizontal
334*c8dee2aaSAndroid Build Coastguard Worker // and vertical stroke widths are both greater than 1 (in which case innerCoverage will always
335*c8dee2aaSAndroid Build Coastguard Worker // be 1). In actuality we allow them to be nearly-equal since differing by < 1/1000 will not be
336*c8dee2aaSAndroid Build Coastguard Worker // visually detectable when the shape is already less than 1px in thickness.
337*c8dee2aaSAndroid Build Coastguard Worker return SkScalarNearlyEqual(devHalfStrokeSize.fX, devHalfStrokeSize.fY) ||
338*c8dee2aaSAndroid Build Coastguard Worker std::min(devHalfStrokeSize.fX, devHalfStrokeSize.fY) >= .5f;
339*c8dee2aaSAndroid Build Coastguard Worker }
340*c8dee2aaSAndroid Build Coastguard Worker
compute_aa_rects(const GrCaps & caps,SkRect * devOutside,SkRect * devOutsideAssist,SkRect * devInside,bool * isDegenerate,const SkMatrix & viewMatrix,const SkRect & rect,SkScalar strokeWidth,bool miterStroke,SkVector * devHalfStrokeSize)341*c8dee2aaSAndroid Build Coastguard Worker bool compute_aa_rects(const GrCaps& caps,
342*c8dee2aaSAndroid Build Coastguard Worker SkRect* devOutside,
343*c8dee2aaSAndroid Build Coastguard Worker SkRect* devOutsideAssist,
344*c8dee2aaSAndroid Build Coastguard Worker SkRect* devInside,
345*c8dee2aaSAndroid Build Coastguard Worker bool* isDegenerate,
346*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
347*c8dee2aaSAndroid Build Coastguard Worker const SkRect& rect,
348*c8dee2aaSAndroid Build Coastguard Worker SkScalar strokeWidth,
349*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke,
350*c8dee2aaSAndroid Build Coastguard Worker SkVector* devHalfStrokeSize) {
351*c8dee2aaSAndroid Build Coastguard Worker SkVector devStrokeSize;
352*c8dee2aaSAndroid Build Coastguard Worker if (strokeWidth > 0) {
353*c8dee2aaSAndroid Build Coastguard Worker devStrokeSize.set(strokeWidth, strokeWidth);
354*c8dee2aaSAndroid Build Coastguard Worker viewMatrix.mapVectors(&devStrokeSize, 1);
355*c8dee2aaSAndroid Build Coastguard Worker devStrokeSize.setAbs(devStrokeSize);
356*c8dee2aaSAndroid Build Coastguard Worker } else {
357*c8dee2aaSAndroid Build Coastguard Worker devStrokeSize.set(SK_Scalar1, SK_Scalar1);
358*c8dee2aaSAndroid Build Coastguard Worker }
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker const SkScalar dx = devStrokeSize.fX;
361*c8dee2aaSAndroid Build Coastguard Worker const SkScalar dy = devStrokeSize.fY;
362*c8dee2aaSAndroid Build Coastguard Worker const SkScalar rx = SkScalarHalf(dx);
363*c8dee2aaSAndroid Build Coastguard Worker const SkScalar ry = SkScalarHalf(dy);
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker devHalfStrokeSize->fX = rx;
366*c8dee2aaSAndroid Build Coastguard Worker devHalfStrokeSize->fY = ry;
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker SkRect devRect;
369*c8dee2aaSAndroid Build Coastguard Worker viewMatrix.mapRect(&devRect, rect);
370*c8dee2aaSAndroid Build Coastguard Worker
371*c8dee2aaSAndroid Build Coastguard Worker // Clip our draw rect 1 full stroke width plus bloat outside the viewport. This avoids
372*c8dee2aaSAndroid Build Coastguard Worker // interpolation precision issues with very large coordinates.
373*c8dee2aaSAndroid Build Coastguard Worker const float m = caps.maxRenderTargetSize();
374*c8dee2aaSAndroid Build Coastguard Worker const SkRect visibilityBounds = SkRect::MakeWH(m, m).makeOutset(dx + 1, dy + 1);
375*c8dee2aaSAndroid Build Coastguard Worker if (!devRect.intersect(visibilityBounds)) {
376*c8dee2aaSAndroid Build Coastguard Worker return false;
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker *devOutside = devRect;
380*c8dee2aaSAndroid Build Coastguard Worker *devOutsideAssist = devRect;
381*c8dee2aaSAndroid Build Coastguard Worker *devInside = devRect;
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker devOutside->outset(rx, ry);
384*c8dee2aaSAndroid Build Coastguard Worker devInside->inset(rx, ry);
385*c8dee2aaSAndroid Build Coastguard Worker
386*c8dee2aaSAndroid Build Coastguard Worker // If we have a degenerate stroking rect(ie the stroke is larger than inner rect) then we
387*c8dee2aaSAndroid Build Coastguard Worker // make a degenerate inside rect to avoid double hitting. We will also jam all of the points
388*c8dee2aaSAndroid Build Coastguard Worker // together when we render these rects.
389*c8dee2aaSAndroid Build Coastguard Worker SkScalar spare;
390*c8dee2aaSAndroid Build Coastguard Worker {
391*c8dee2aaSAndroid Build Coastguard Worker SkScalar w = devRect.width() - dx;
392*c8dee2aaSAndroid Build Coastguard Worker SkScalar h = devRect.height() - dy;
393*c8dee2aaSAndroid Build Coastguard Worker spare = std::min(w, h);
394*c8dee2aaSAndroid Build Coastguard Worker }
395*c8dee2aaSAndroid Build Coastguard Worker
396*c8dee2aaSAndroid Build Coastguard Worker *isDegenerate = spare <= 0;
397*c8dee2aaSAndroid Build Coastguard Worker if (*isDegenerate) {
398*c8dee2aaSAndroid Build Coastguard Worker devInside->fLeft = devInside->fRight = devRect.centerX();
399*c8dee2aaSAndroid Build Coastguard Worker devInside->fTop = devInside->fBottom = devRect.centerY();
400*c8dee2aaSAndroid Build Coastguard Worker }
401*c8dee2aaSAndroid Build Coastguard Worker
402*c8dee2aaSAndroid Build Coastguard Worker // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
403*c8dee2aaSAndroid Build Coastguard Worker // to draw the outside of the octagon. Because there are 8 vertices on the outer
404*c8dee2aaSAndroid Build Coastguard Worker // edge, while vertex number of inner edge is 4, the same as miter-stroke.
405*c8dee2aaSAndroid Build Coastguard Worker if (!miterStroke) {
406*c8dee2aaSAndroid Build Coastguard Worker devOutside->inset(0, ry);
407*c8dee2aaSAndroid Build Coastguard Worker devOutsideAssist->outset(0, ry);
408*c8dee2aaSAndroid Build Coastguard Worker }
409*c8dee2aaSAndroid Build Coastguard Worker
410*c8dee2aaSAndroid Build Coastguard Worker return true;
411*c8dee2aaSAndroid Build Coastguard Worker }
412*c8dee2aaSAndroid Build Coastguard Worker
create_aa_stroke_rect_gp(SkArenaAlloc * arena,bool usesMSAASurface,bool tweakAlphaForCoverage,const SkMatrix & viewMatrix,bool usesLocalCoords,bool wideColor)413*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* create_aa_stroke_rect_gp(SkArenaAlloc* arena,
414*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface,
415*c8dee2aaSAndroid Build Coastguard Worker bool tweakAlphaForCoverage,
416*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
417*c8dee2aaSAndroid Build Coastguard Worker bool usesLocalCoords,
418*c8dee2aaSAndroid Build Coastguard Worker bool wideColor) {
419*c8dee2aaSAndroid Build Coastguard Worker using namespace GrDefaultGeoProcFactory;
420*c8dee2aaSAndroid Build Coastguard Worker
421*c8dee2aaSAndroid Build Coastguard Worker // When MSAA is enabled, we have to extend our AA bloats and interpolate coverage values outside
422*c8dee2aaSAndroid Build Coastguard Worker // 0..1. We tell the gp in this case that coverage is an unclamped attribute so it will call
423*c8dee2aaSAndroid Build Coastguard Worker // saturate(coverage) in the fragment shader.
424*c8dee2aaSAndroid Build Coastguard Worker Coverage::Type coverageType = usesMSAASurface ? Coverage::kAttributeUnclamped_Type
425*c8dee2aaSAndroid Build Coastguard Worker : (!tweakAlphaForCoverage ? Coverage::kAttribute_Type
426*c8dee2aaSAndroid Build Coastguard Worker : Coverage::kSolid_Type);
427*c8dee2aaSAndroid Build Coastguard Worker LocalCoords::Type localCoordsType =
428*c8dee2aaSAndroid Build Coastguard Worker usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
429*c8dee2aaSAndroid Build Coastguard Worker Color::Type colorType =
430*c8dee2aaSAndroid Build Coastguard Worker wideColor ? Color::kPremulWideColorAttribute_Type: Color::kPremulGrColorAttribute_Type;
431*c8dee2aaSAndroid Build Coastguard Worker
432*c8dee2aaSAndroid Build Coastguard Worker return MakeForDeviceSpace(arena, colorType, coverageType, localCoordsType, viewMatrix);
433*c8dee2aaSAndroid Build Coastguard Worker }
434*c8dee2aaSAndroid Build Coastguard Worker
435*c8dee2aaSAndroid Build Coastguard Worker class AAStrokeRectOp final : public GrMeshDrawOp {
436*c8dee2aaSAndroid Build Coastguard Worker private:
437*c8dee2aaSAndroid Build Coastguard Worker using Helper = GrSimpleMeshDrawOpHelper;
438*c8dee2aaSAndroid Build Coastguard Worker
439*c8dee2aaSAndroid Build Coastguard Worker public:
440*c8dee2aaSAndroid Build Coastguard Worker DEFINE_OP_CLASS_ID
441*c8dee2aaSAndroid Build Coastguard Worker
442*c8dee2aaSAndroid Build Coastguard Worker // TODO support AA rotated stroke rects by copying around view matrices
443*c8dee2aaSAndroid Build Coastguard Worker struct RectInfo {
444*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f fColor;
445*c8dee2aaSAndroid Build Coastguard Worker SkRect fDevOutside;
446*c8dee2aaSAndroid Build Coastguard Worker SkRect fDevOutsideAssist;
447*c8dee2aaSAndroid Build Coastguard Worker SkRect fDevInside;
448*c8dee2aaSAndroid Build Coastguard Worker SkVector fDevHalfStrokeSize;
449*c8dee2aaSAndroid Build Coastguard Worker bool fDegenerate;
450*c8dee2aaSAndroid Build Coastguard Worker };
451*c8dee2aaSAndroid Build Coastguard Worker
Make(GrRecordingContext * context,GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & devOutside,const SkRect & devInside,const SkVector & devHalfStrokeSize)452*c8dee2aaSAndroid Build Coastguard Worker static GrOp::Owner Make(GrRecordingContext* context,
453*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint,
454*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
455*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devOutside,
456*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devInside,
457*c8dee2aaSAndroid Build Coastguard Worker const SkVector& devHalfStrokeSize) {
458*c8dee2aaSAndroid Build Coastguard Worker if (!viewMatrix.rectStaysRect()) {
459*c8dee2aaSAndroid Build Coastguard Worker // The AA op only supports axis-aligned rectangles
460*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
461*c8dee2aaSAndroid Build Coastguard Worker }
462*c8dee2aaSAndroid Build Coastguard Worker if (!stroke_dev_half_size_supported(devHalfStrokeSize)) {
463*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker return Helper::FactoryHelper<AAStrokeRectOp>(context, std::move(paint), viewMatrix,
466*c8dee2aaSAndroid Build Coastguard Worker devOutside, devInside, devHalfStrokeSize);
467*c8dee2aaSAndroid Build Coastguard Worker }
468*c8dee2aaSAndroid Build Coastguard Worker
AAStrokeRectOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkRect & devOutside,const SkRect & devInside,const SkVector & devHalfStrokeSize)469*c8dee2aaSAndroid Build Coastguard Worker AAStrokeRectOp(GrProcessorSet* processorSet, const SkPMColor4f& color,
470*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix, const SkRect& devOutside, const SkRect& devInside,
471*c8dee2aaSAndroid Build Coastguard Worker const SkVector& devHalfStrokeSize)
472*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(ClassID())
473*c8dee2aaSAndroid Build Coastguard Worker , fHelper(processorSet, GrAAType::kCoverage)
474*c8dee2aaSAndroid Build Coastguard Worker , fViewMatrix(viewMatrix) {
475*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!devOutside.isEmpty());
476*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!devInside.isEmpty());
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker fRects.emplace_back(RectInfo{color, devOutside, devOutside, devInside, devHalfStrokeSize, false});
479*c8dee2aaSAndroid Build Coastguard Worker this->setBounds(devOutside, HasAABloat::kYes, IsHairline::kNo);
480*c8dee2aaSAndroid Build Coastguard Worker fMiterStroke = true;
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker
Make(GrRecordingContext * context,GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkStrokeRec & stroke)483*c8dee2aaSAndroid Build Coastguard Worker static GrOp::Owner Make(GrRecordingContext* context,
484*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint,
485*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
486*c8dee2aaSAndroid Build Coastguard Worker const SkRect& rect,
487*c8dee2aaSAndroid Build Coastguard Worker const SkStrokeRec& stroke) {
488*c8dee2aaSAndroid Build Coastguard Worker if (!viewMatrix.rectStaysRect()) {
489*c8dee2aaSAndroid Build Coastguard Worker // The AA op only supports axis-aligned rectangles
490*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
491*c8dee2aaSAndroid Build Coastguard Worker }
492*c8dee2aaSAndroid Build Coastguard Worker bool isMiter;
493*c8dee2aaSAndroid Build Coastguard Worker if (!allowed_stroke(context->priv().caps(), stroke, GrAA::kYes, &isMiter)) {
494*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker RectInfo info;
497*c8dee2aaSAndroid Build Coastguard Worker if (!compute_aa_rects(*context->priv().caps(),
498*c8dee2aaSAndroid Build Coastguard Worker &info.fDevOutside,
499*c8dee2aaSAndroid Build Coastguard Worker &info.fDevOutsideAssist,
500*c8dee2aaSAndroid Build Coastguard Worker &info.fDevInside,
501*c8dee2aaSAndroid Build Coastguard Worker &info.fDegenerate,
502*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
503*c8dee2aaSAndroid Build Coastguard Worker rect,
504*c8dee2aaSAndroid Build Coastguard Worker stroke.getWidth(),
505*c8dee2aaSAndroid Build Coastguard Worker isMiter,
506*c8dee2aaSAndroid Build Coastguard Worker &info.fDevHalfStrokeSize)) {
507*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
508*c8dee2aaSAndroid Build Coastguard Worker }
509*c8dee2aaSAndroid Build Coastguard Worker if (!stroke_dev_half_size_supported(info.fDevHalfStrokeSize)) {
510*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker return Helper::FactoryHelper<AAStrokeRectOp>(context, std::move(paint), viewMatrix, info,
513*c8dee2aaSAndroid Build Coastguard Worker isMiter);
514*c8dee2aaSAndroid Build Coastguard Worker }
515*c8dee2aaSAndroid Build Coastguard Worker
AAStrokeRectOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const SkMatrix & viewMatrix,const RectInfo & infoExceptColor,bool isMiter)516*c8dee2aaSAndroid Build Coastguard Worker AAStrokeRectOp(GrProcessorSet* processorSet, const SkPMColor4f& color,
517*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix, const RectInfo& infoExceptColor, bool isMiter)
518*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(ClassID())
519*c8dee2aaSAndroid Build Coastguard Worker , fHelper(processorSet, GrAAType::kCoverage)
520*c8dee2aaSAndroid Build Coastguard Worker , fViewMatrix(viewMatrix) {
521*c8dee2aaSAndroid Build Coastguard Worker fMiterStroke = isMiter;
522*c8dee2aaSAndroid Build Coastguard Worker RectInfo& info = fRects.push_back(infoExceptColor);
523*c8dee2aaSAndroid Build Coastguard Worker info.fColor = color;
524*c8dee2aaSAndroid Build Coastguard Worker if (isMiter) {
525*c8dee2aaSAndroid Build Coastguard Worker this->setBounds(info.fDevOutside, HasAABloat::kYes, IsHairline::kNo);
526*c8dee2aaSAndroid Build Coastguard Worker } else {
527*c8dee2aaSAndroid Build Coastguard Worker // The outer polygon of the bevel stroke is an octagon specified by the points of a
528*c8dee2aaSAndroid Build Coastguard Worker // pair of overlapping rectangles where one is wide and the other is narrow.
529*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = info.fDevOutside;
530*c8dee2aaSAndroid Build Coastguard Worker bounds.joinPossiblyEmptyRect(info.fDevOutsideAssist);
531*c8dee2aaSAndroid Build Coastguard Worker this->setBounds(bounds, HasAABloat::kYes, IsHairline::kNo);
532*c8dee2aaSAndroid Build Coastguard Worker }
533*c8dee2aaSAndroid Build Coastguard Worker }
534*c8dee2aaSAndroid Build Coastguard Worker
name() const535*c8dee2aaSAndroid Build Coastguard Worker const char* name() const override { return "AAStrokeRect"; }
536*c8dee2aaSAndroid Build Coastguard Worker
visitProxies(const GrVisitProxyFunc & func) const537*c8dee2aaSAndroid Build Coastguard Worker void visitProxies(const GrVisitProxyFunc& func) const override {
538*c8dee2aaSAndroid Build Coastguard Worker if (fProgramInfo) {
539*c8dee2aaSAndroid Build Coastguard Worker fProgramInfo->visitFPProxies(func);
540*c8dee2aaSAndroid Build Coastguard Worker } else {
541*c8dee2aaSAndroid Build Coastguard Worker fHelper.visitProxies(func);
542*c8dee2aaSAndroid Build Coastguard Worker }
543*c8dee2aaSAndroid Build Coastguard Worker }
544*c8dee2aaSAndroid Build Coastguard Worker
fixedFunctionFlags() const545*c8dee2aaSAndroid Build Coastguard Worker FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
546*c8dee2aaSAndroid Build Coastguard Worker
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)547*c8dee2aaSAndroid Build Coastguard Worker GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
548*c8dee2aaSAndroid Build Coastguard Worker GrClampType clampType) override {
549*c8dee2aaSAndroid Build Coastguard Worker return fHelper.finalizeProcessors(caps, clip, clampType,
550*c8dee2aaSAndroid Build Coastguard Worker GrProcessorAnalysisCoverage::kSingleChannel,
551*c8dee2aaSAndroid Build Coastguard Worker &fRects.back().fColor, &fWideColor);
552*c8dee2aaSAndroid Build Coastguard Worker }
553*c8dee2aaSAndroid Build Coastguard Worker
554*c8dee2aaSAndroid Build Coastguard Worker private:
programInfo()555*c8dee2aaSAndroid Build Coastguard Worker GrProgramInfo* programInfo() override { return fProgramInfo; }
556*c8dee2aaSAndroid Build Coastguard Worker
compatibleWithCoverageAsAlpha(bool usesMSAASurface) const557*c8dee2aaSAndroid Build Coastguard Worker bool compatibleWithCoverageAsAlpha(bool usesMSAASurface) const {
558*c8dee2aaSAndroid Build Coastguard Worker // When MSAA is enabled, we have to extend our AA bloats and interpolate coverage values
559*c8dee2aaSAndroid Build Coastguard Worker // outside 0..1. This makes us incompatible with coverage as alpha.
560*c8dee2aaSAndroid Build Coastguard Worker return !usesMSAASurface && fHelper.compatibleWithCoverageAsAlpha();
561*c8dee2aaSAndroid Build Coastguard Worker }
562*c8dee2aaSAndroid Build Coastguard Worker
563*c8dee2aaSAndroid Build Coastguard Worker void onCreateProgramInfo(const GrCaps*,
564*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc*,
565*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceProxyView& writeView,
566*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface,
567*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip&&,
568*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView&,
569*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierFlags renderPassXferBarriers,
570*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp colorLoadOp) override;
571*c8dee2aaSAndroid Build Coastguard Worker
572*c8dee2aaSAndroid Build Coastguard Worker void onPrepareDraws(GrMeshDrawTarget*) override;
573*c8dee2aaSAndroid Build Coastguard Worker void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
574*c8dee2aaSAndroid Build Coastguard Worker
575*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const576*c8dee2aaSAndroid Build Coastguard Worker SkString onDumpInfo() const override {
577*c8dee2aaSAndroid Build Coastguard Worker SkString string;
578*c8dee2aaSAndroid Build Coastguard Worker for (const auto& info : fRects) {
579*c8dee2aaSAndroid Build Coastguard Worker string.appendf(
580*c8dee2aaSAndroid Build Coastguard Worker "Color: 0x%08x, ORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
581*c8dee2aaSAndroid Build Coastguard Worker "AssistORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
582*c8dee2aaSAndroid Build Coastguard Worker "IRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], Degen: %d",
583*c8dee2aaSAndroid Build Coastguard Worker info.fColor.toBytes_RGBA(), info.fDevOutside.fLeft, info.fDevOutside.fTop,
584*c8dee2aaSAndroid Build Coastguard Worker info.fDevOutside.fRight, info.fDevOutside.fBottom, info.fDevOutsideAssist.fLeft,
585*c8dee2aaSAndroid Build Coastguard Worker info.fDevOutsideAssist.fTop, info.fDevOutsideAssist.fRight,
586*c8dee2aaSAndroid Build Coastguard Worker info.fDevOutsideAssist.fBottom, info.fDevInside.fLeft, info.fDevInside.fTop,
587*c8dee2aaSAndroid Build Coastguard Worker info.fDevInside.fRight, info.fDevInside.fBottom, info.fDegenerate);
588*c8dee2aaSAndroid Build Coastguard Worker }
589*c8dee2aaSAndroid Build Coastguard Worker string += fHelper.dumpInfo();
590*c8dee2aaSAndroid Build Coastguard Worker return string;
591*c8dee2aaSAndroid Build Coastguard Worker }
592*c8dee2aaSAndroid Build Coastguard Worker #endif
593*c8dee2aaSAndroid Build Coastguard Worker
594*c8dee2aaSAndroid Build Coastguard Worker static const int kMiterIndexCnt = 3 * 24;
595*c8dee2aaSAndroid Build Coastguard Worker static const int kMiterVertexCnt = 16;
596*c8dee2aaSAndroid Build Coastguard Worker static const int kNumMiterRectsInIndexBuffer = 256;
597*c8dee2aaSAndroid Build Coastguard Worker
598*c8dee2aaSAndroid Build Coastguard Worker static const int kBevelIndexCnt = 48 + 36 + 24;
599*c8dee2aaSAndroid Build Coastguard Worker static const int kBevelVertexCnt = 24;
600*c8dee2aaSAndroid Build Coastguard Worker static const int kNumBevelRectsInIndexBuffer = 256;
601*c8dee2aaSAndroid Build Coastguard Worker
602*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<const GrGpuBuffer> GetIndexBuffer(GrResourceProvider*, bool miterStroke);
603*c8dee2aaSAndroid Build Coastguard Worker
viewMatrix() const604*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix() const { return fViewMatrix; }
miterStroke() const605*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke() const { return fMiterStroke; }
606*c8dee2aaSAndroid Build Coastguard Worker
607*c8dee2aaSAndroid Build Coastguard Worker CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps&) override;
608*c8dee2aaSAndroid Build Coastguard Worker
609*c8dee2aaSAndroid Build Coastguard Worker void generateAAStrokeRectGeometry(VertexWriter& vertices,
610*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
611*c8dee2aaSAndroid Build Coastguard Worker bool wideColor,
612*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devOutside,
613*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devOutsideAssist,
614*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devInside,
615*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke,
616*c8dee2aaSAndroid Build Coastguard Worker bool degenerate,
617*c8dee2aaSAndroid Build Coastguard Worker const SkVector& devHalfStrokeSize,
618*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface) const;
619*c8dee2aaSAndroid Build Coastguard Worker
620*c8dee2aaSAndroid Build Coastguard Worker Helper fHelper;
621*c8dee2aaSAndroid Build Coastguard Worker STArray<1, RectInfo, true> fRects;
622*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fViewMatrix;
623*c8dee2aaSAndroid Build Coastguard Worker GrSimpleMesh* fMesh = nullptr;
624*c8dee2aaSAndroid Build Coastguard Worker GrProgramInfo* fProgramInfo = nullptr;
625*c8dee2aaSAndroid Build Coastguard Worker bool fMiterStroke;
626*c8dee2aaSAndroid Build Coastguard Worker bool fWideColor;
627*c8dee2aaSAndroid Build Coastguard Worker
628*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GrMeshDrawOp;
629*c8dee2aaSAndroid Build Coastguard Worker };
630*c8dee2aaSAndroid Build Coastguard Worker
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)631*c8dee2aaSAndroid Build Coastguard Worker void AAStrokeRectOp::onCreateProgramInfo(const GrCaps* caps,
632*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* arena,
633*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceProxyView& writeView,
634*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface,
635*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip&& appliedClip,
636*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView& dstProxyView,
637*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierFlags renderPassXferBarriers,
638*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp colorLoadOp) {
639*c8dee2aaSAndroid Build Coastguard Worker
640*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* gp = create_aa_stroke_rect_gp(
641*c8dee2aaSAndroid Build Coastguard Worker arena,
642*c8dee2aaSAndroid Build Coastguard Worker usesMSAASurface,
643*c8dee2aaSAndroid Build Coastguard Worker this->compatibleWithCoverageAsAlpha(usesMSAASurface),
644*c8dee2aaSAndroid Build Coastguard Worker this->viewMatrix(),
645*c8dee2aaSAndroid Build Coastguard Worker fHelper.usesLocalCoords(),
646*c8dee2aaSAndroid Build Coastguard Worker fWideColor);
647*c8dee2aaSAndroid Build Coastguard Worker if (!gp) {
648*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Couldn't create GrGeometryProcessor\n");
649*c8dee2aaSAndroid Build Coastguard Worker return;
650*c8dee2aaSAndroid Build Coastguard Worker }
651*c8dee2aaSAndroid Build Coastguard Worker
652*c8dee2aaSAndroid Build Coastguard Worker fProgramInfo = fHelper.createProgramInfo(caps,
653*c8dee2aaSAndroid Build Coastguard Worker arena,
654*c8dee2aaSAndroid Build Coastguard Worker writeView,
655*c8dee2aaSAndroid Build Coastguard Worker usesMSAASurface,
656*c8dee2aaSAndroid Build Coastguard Worker std::move(appliedClip),
657*c8dee2aaSAndroid Build Coastguard Worker dstProxyView,
658*c8dee2aaSAndroid Build Coastguard Worker gp,
659*c8dee2aaSAndroid Build Coastguard Worker GrPrimitiveType::kTriangles,
660*c8dee2aaSAndroid Build Coastguard Worker renderPassXferBarriers,
661*c8dee2aaSAndroid Build Coastguard Worker colorLoadOp);
662*c8dee2aaSAndroid Build Coastguard Worker }
663*c8dee2aaSAndroid Build Coastguard Worker
onPrepareDraws(GrMeshDrawTarget * target)664*c8dee2aaSAndroid Build Coastguard Worker void AAStrokeRectOp::onPrepareDraws(GrMeshDrawTarget* target) {
665*c8dee2aaSAndroid Build Coastguard Worker
666*c8dee2aaSAndroid Build Coastguard Worker if (!fProgramInfo) {
667*c8dee2aaSAndroid Build Coastguard Worker this->createProgramInfo(target);
668*c8dee2aaSAndroid Build Coastguard Worker if (!fProgramInfo) {
669*c8dee2aaSAndroid Build Coastguard Worker return;
670*c8dee2aaSAndroid Build Coastguard Worker }
671*c8dee2aaSAndroid Build Coastguard Worker }
672*c8dee2aaSAndroid Build Coastguard Worker
673*c8dee2aaSAndroid Build Coastguard Worker int innerVertexNum = 4;
674*c8dee2aaSAndroid Build Coastguard Worker int outerVertexNum = this->miterStroke() ? 4 : 8;
675*c8dee2aaSAndroid Build Coastguard Worker int verticesPerInstance = (outerVertexNum + innerVertexNum) * 2;
676*c8dee2aaSAndroid Build Coastguard Worker int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt;
677*c8dee2aaSAndroid Build Coastguard Worker int instanceCount = fRects.size();
678*c8dee2aaSAndroid Build Coastguard Worker int maxQuads = this->miterStroke() ? kNumMiterRectsInIndexBuffer : kNumBevelRectsInIndexBuffer;
679*c8dee2aaSAndroid Build Coastguard Worker
680*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrGpuBuffer> indexBuffer =
681*c8dee2aaSAndroid Build Coastguard Worker GetIndexBuffer(target->resourceProvider(), this->miterStroke());
682*c8dee2aaSAndroid Build Coastguard Worker if (!indexBuffer) {
683*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Could not allocate indices\n");
684*c8dee2aaSAndroid Build Coastguard Worker return;
685*c8dee2aaSAndroid Build Coastguard Worker }
686*c8dee2aaSAndroid Build Coastguard Worker PatternHelper helper(target, GrPrimitiveType::kTriangles,
687*c8dee2aaSAndroid Build Coastguard Worker fProgramInfo->geomProc().vertexStride(), std::move(indexBuffer),
688*c8dee2aaSAndroid Build Coastguard Worker verticesPerInstance, indicesPerInstance, instanceCount, maxQuads);
689*c8dee2aaSAndroid Build Coastguard Worker VertexWriter vertices{ helper.vertices() };
690*c8dee2aaSAndroid Build Coastguard Worker if (!vertices) {
691*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Could not allocate vertices\n");
692*c8dee2aaSAndroid Build Coastguard Worker return;
693*c8dee2aaSAndroid Build Coastguard Worker }
694*c8dee2aaSAndroid Build Coastguard Worker
695*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < instanceCount; i++) {
696*c8dee2aaSAndroid Build Coastguard Worker const RectInfo& info = fRects[i];
697*c8dee2aaSAndroid Build Coastguard Worker this->generateAAStrokeRectGeometry(vertices,
698*c8dee2aaSAndroid Build Coastguard Worker info.fColor,
699*c8dee2aaSAndroid Build Coastguard Worker fWideColor,
700*c8dee2aaSAndroid Build Coastguard Worker info.fDevOutside,
701*c8dee2aaSAndroid Build Coastguard Worker info.fDevOutsideAssist,
702*c8dee2aaSAndroid Build Coastguard Worker info.fDevInside,
703*c8dee2aaSAndroid Build Coastguard Worker fMiterStroke,
704*c8dee2aaSAndroid Build Coastguard Worker info.fDegenerate,
705*c8dee2aaSAndroid Build Coastguard Worker info.fDevHalfStrokeSize,
706*c8dee2aaSAndroid Build Coastguard Worker target->usesMSAASurface());
707*c8dee2aaSAndroid Build Coastguard Worker }
708*c8dee2aaSAndroid Build Coastguard Worker fMesh = helper.mesh();
709*c8dee2aaSAndroid Build Coastguard Worker }
710*c8dee2aaSAndroid Build Coastguard Worker
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)711*c8dee2aaSAndroid Build Coastguard Worker void AAStrokeRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
712*c8dee2aaSAndroid Build Coastguard Worker if (!fProgramInfo || !fMesh) {
713*c8dee2aaSAndroid Build Coastguard Worker return;
714*c8dee2aaSAndroid Build Coastguard Worker }
715*c8dee2aaSAndroid Build Coastguard Worker
716*c8dee2aaSAndroid Build Coastguard Worker flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
717*c8dee2aaSAndroid Build Coastguard Worker flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
718*c8dee2aaSAndroid Build Coastguard Worker flushState->drawMesh(*fMesh);
719*c8dee2aaSAndroid Build Coastguard Worker }
720*c8dee2aaSAndroid Build Coastguard Worker
GetIndexBuffer(GrResourceProvider * resourceProvider,bool miterStroke)721*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrGpuBuffer> AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider,
722*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke) {
723*c8dee2aaSAndroid Build Coastguard Worker if (miterStroke) {
724*c8dee2aaSAndroid Build Coastguard Worker // clang-format off
725*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t gMiterIndices[] = {
726*c8dee2aaSAndroid Build Coastguard Worker 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
727*c8dee2aaSAndroid Build Coastguard Worker 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
728*c8dee2aaSAndroid Build Coastguard Worker 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
729*c8dee2aaSAndroid Build Coastguard Worker 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
730*c8dee2aaSAndroid Build Coastguard Worker
731*c8dee2aaSAndroid Build Coastguard Worker 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
732*c8dee2aaSAndroid Build Coastguard Worker 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
733*c8dee2aaSAndroid Build Coastguard Worker 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
734*c8dee2aaSAndroid Build Coastguard Worker 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
735*c8dee2aaSAndroid Build Coastguard Worker
736*c8dee2aaSAndroid Build Coastguard Worker 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
737*c8dee2aaSAndroid Build Coastguard Worker 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
738*c8dee2aaSAndroid Build Coastguard Worker 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
739*c8dee2aaSAndroid Build Coastguard Worker 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
740*c8dee2aaSAndroid Build Coastguard Worker };
741*c8dee2aaSAndroid Build Coastguard Worker // clang-format on
742*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(gMiterIndices) == kMiterIndexCnt);
743*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DEFINE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
744*c8dee2aaSAndroid Build Coastguard Worker return resourceProvider->findOrCreatePatternedIndexBuffer(
745*c8dee2aaSAndroid Build Coastguard Worker gMiterIndices, kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt,
746*c8dee2aaSAndroid Build Coastguard Worker gMiterIndexBufferKey);
747*c8dee2aaSAndroid Build Coastguard Worker } else {
748*c8dee2aaSAndroid Build Coastguard Worker /**
749*c8dee2aaSAndroid Build Coastguard Worker * As in miter-stroke, index = a + b, and a is the current index, b is the shift
750*c8dee2aaSAndroid Build Coastguard Worker * from the first index. The index layout:
751*c8dee2aaSAndroid Build Coastguard Worker * outer AA line: 0~3, 4~7
752*c8dee2aaSAndroid Build Coastguard Worker * outer edge: 8~11, 12~15
753*c8dee2aaSAndroid Build Coastguard Worker * inner edge: 16~19
754*c8dee2aaSAndroid Build Coastguard Worker * inner AA line: 20~23
755*c8dee2aaSAndroid Build Coastguard Worker * Following comes a bevel-stroke rect and its indices:
756*c8dee2aaSAndroid Build Coastguard Worker *
757*c8dee2aaSAndroid Build Coastguard Worker * 4 7
758*c8dee2aaSAndroid Build Coastguard Worker * *********************************
759*c8dee2aaSAndroid Build Coastguard Worker * * ______________________________ *
760*c8dee2aaSAndroid Build Coastguard Worker * * / 12 15 \ *
761*c8dee2aaSAndroid Build Coastguard Worker * * / \ *
762*c8dee2aaSAndroid Build Coastguard Worker * 0 * |8 16_____________________19 11 | * 3
763*c8dee2aaSAndroid Build Coastguard Worker * * | | | | *
764*c8dee2aaSAndroid Build Coastguard Worker * * | | **************** | | *
765*c8dee2aaSAndroid Build Coastguard Worker * * | | * 20 23 * | | *
766*c8dee2aaSAndroid Build Coastguard Worker * * | | * * | | *
767*c8dee2aaSAndroid Build Coastguard Worker * * | | * 21 22 * | | *
768*c8dee2aaSAndroid Build Coastguard Worker * * | | **************** | | *
769*c8dee2aaSAndroid Build Coastguard Worker * * | |____________________| | *
770*c8dee2aaSAndroid Build Coastguard Worker * 1 * |9 17 18 10| * 2
771*c8dee2aaSAndroid Build Coastguard Worker * * \ / *
772*c8dee2aaSAndroid Build Coastguard Worker * * \13 __________________________14/ *
773*c8dee2aaSAndroid Build Coastguard Worker * * *
774*c8dee2aaSAndroid Build Coastguard Worker * **********************************
775*c8dee2aaSAndroid Build Coastguard Worker * 5 6
776*c8dee2aaSAndroid Build Coastguard Worker */
777*c8dee2aaSAndroid Build Coastguard Worker // clang-format off
778*c8dee2aaSAndroid Build Coastguard Worker static const uint16_t gBevelIndices[] = {
779*c8dee2aaSAndroid Build Coastguard Worker // Draw outer AA, from outer AA line to outer edge, shift is 0.
780*c8dee2aaSAndroid Build Coastguard Worker 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
781*c8dee2aaSAndroid Build Coastguard Worker 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
782*c8dee2aaSAndroid Build Coastguard Worker 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
783*c8dee2aaSAndroid Build Coastguard Worker 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
784*c8dee2aaSAndroid Build Coastguard Worker 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
785*c8dee2aaSAndroid Build Coastguard Worker 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
786*c8dee2aaSAndroid Build Coastguard Worker 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
787*c8dee2aaSAndroid Build Coastguard Worker 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
788*c8dee2aaSAndroid Build Coastguard Worker
789*c8dee2aaSAndroid Build Coastguard Worker // Draw the stroke, from outer edge to inner edge, shift is 8.
790*c8dee2aaSAndroid Build Coastguard Worker 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
791*c8dee2aaSAndroid Build Coastguard Worker 1 + 8, 5 + 8, 9 + 8,
792*c8dee2aaSAndroid Build Coastguard Worker 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
793*c8dee2aaSAndroid Build Coastguard Worker 6 + 8, 2 + 8, 10 + 8,
794*c8dee2aaSAndroid Build Coastguard Worker 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
795*c8dee2aaSAndroid Build Coastguard Worker 3 + 8, 7 + 8, 11 + 8,
796*c8dee2aaSAndroid Build Coastguard Worker 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
797*c8dee2aaSAndroid Build Coastguard Worker 4 + 8, 0 + 8, 8 + 8,
798*c8dee2aaSAndroid Build Coastguard Worker
799*c8dee2aaSAndroid Build Coastguard Worker // Draw the inner AA, from inner edge to inner AA line, shift is 16.
800*c8dee2aaSAndroid Build Coastguard Worker 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
801*c8dee2aaSAndroid Build Coastguard Worker 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
802*c8dee2aaSAndroid Build Coastguard Worker 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
803*c8dee2aaSAndroid Build Coastguard Worker 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
804*c8dee2aaSAndroid Build Coastguard Worker };
805*c8dee2aaSAndroid Build Coastguard Worker // clang-format on
806*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(gBevelIndices) == kBevelIndexCnt);
807*c8dee2aaSAndroid Build Coastguard Worker
808*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DEFINE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
809*c8dee2aaSAndroid Build Coastguard Worker return resourceProvider->findOrCreatePatternedIndexBuffer(
810*c8dee2aaSAndroid Build Coastguard Worker gBevelIndices, kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt,
811*c8dee2aaSAndroid Build Coastguard Worker gBevelIndexBufferKey);
812*c8dee2aaSAndroid Build Coastguard Worker }
813*c8dee2aaSAndroid Build Coastguard Worker }
814*c8dee2aaSAndroid Build Coastguard Worker
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)815*c8dee2aaSAndroid Build Coastguard Worker GrOp::CombineResult AAStrokeRectOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps)
816*c8dee2aaSAndroid Build Coastguard Worker {
817*c8dee2aaSAndroid Build Coastguard Worker AAStrokeRectOp* that = t->cast<AAStrokeRectOp>();
818*c8dee2aaSAndroid Build Coastguard Worker
819*c8dee2aaSAndroid Build Coastguard Worker if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
820*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine;
821*c8dee2aaSAndroid Build Coastguard Worker }
822*c8dee2aaSAndroid Build Coastguard Worker
823*c8dee2aaSAndroid Build Coastguard Worker // TODO combine across miterstroke changes
824*c8dee2aaSAndroid Build Coastguard Worker if (this->miterStroke() != that->miterStroke()) {
825*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine;
826*c8dee2aaSAndroid Build Coastguard Worker }
827*c8dee2aaSAndroid Build Coastguard Worker
828*c8dee2aaSAndroid Build Coastguard Worker // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
829*c8dee2aaSAndroid Build Coastguard Worker // local coords then we won't be able to combine. TODO: Upload local coords as an attribute.
830*c8dee2aaSAndroid Build Coastguard Worker if (fHelper.usesLocalCoords() &&
831*c8dee2aaSAndroid Build Coastguard Worker !SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix()))
832*c8dee2aaSAndroid Build Coastguard Worker {
833*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kCannotCombine;
834*c8dee2aaSAndroid Build Coastguard Worker }
835*c8dee2aaSAndroid Build Coastguard Worker
836*c8dee2aaSAndroid Build Coastguard Worker fRects.push_back_n(that->fRects.size(), that->fRects.begin());
837*c8dee2aaSAndroid Build Coastguard Worker fWideColor |= that->fWideColor;
838*c8dee2aaSAndroid Build Coastguard Worker return CombineResult::kMerged;
839*c8dee2aaSAndroid Build Coastguard Worker }
840*c8dee2aaSAndroid Build Coastguard Worker
generateAAStrokeRectGeometry(VertexWriter & vertices,const SkPMColor4f & color,bool wideColor,const SkRect & devOutside,const SkRect & devOutsideAssist,const SkRect & devInside,bool miterStroke,bool degenerate,const SkVector & devHalfStrokeSize,bool usesMSAASurface) const841*c8dee2aaSAndroid Build Coastguard Worker void AAStrokeRectOp::generateAAStrokeRectGeometry(VertexWriter& vertices,
842*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f& color,
843*c8dee2aaSAndroid Build Coastguard Worker bool wideColor,
844*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devOutside,
845*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devOutsideAssist,
846*c8dee2aaSAndroid Build Coastguard Worker const SkRect& devInside,
847*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke,
848*c8dee2aaSAndroid Build Coastguard Worker bool degenerate,
849*c8dee2aaSAndroid Build Coastguard Worker const SkVector& devHalfStrokeSize,
850*c8dee2aaSAndroid Build Coastguard Worker bool usesMSAASurface) const {
851*c8dee2aaSAndroid Build Coastguard Worker // We create vertices for four nested rectangles. There are two ramps from 0 to full
852*c8dee2aaSAndroid Build Coastguard Worker // coverage, one on the exterior of the stroke and the other on the interior.
853*c8dee2aaSAndroid Build Coastguard Worker
854*c8dee2aaSAndroid Build Coastguard Worker // The following code only works if either devStrokeSize's fX and fY are
855*c8dee2aaSAndroid Build Coastguard Worker // equal (in which case innerCoverage is same for all sides of the rects) or
856*c8dee2aaSAndroid Build Coastguard Worker // if devStrokeSize's fX and fY are both greater than 1.0 (in which case
857*c8dee2aaSAndroid Build Coastguard Worker // innerCoverage will always be 1).
858*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stroke_dev_half_size_supported(devHalfStrokeSize));
859*c8dee2aaSAndroid Build Coastguard Worker
860*c8dee2aaSAndroid Build Coastguard Worker auto inset_fan = [](const SkRect& r, SkScalar dx, SkScalar dy) {
861*c8dee2aaSAndroid Build Coastguard Worker return VertexWriter::TriFanFromRect(r.makeInset(dx, dy));
862*c8dee2aaSAndroid Build Coastguard Worker };
863*c8dee2aaSAndroid Build Coastguard Worker
864*c8dee2aaSAndroid Build Coastguard Worker bool tweakAlphaForCoverage = this->compatibleWithCoverageAsAlpha(usesMSAASurface);
865*c8dee2aaSAndroid Build Coastguard Worker
866*c8dee2aaSAndroid Build Coastguard Worker auto maybe_coverage = [tweakAlphaForCoverage](float coverage) {
867*c8dee2aaSAndroid Build Coastguard Worker return VertexWriter::If(!tweakAlphaForCoverage, coverage);
868*c8dee2aaSAndroid Build Coastguard Worker };
869*c8dee2aaSAndroid Build Coastguard Worker
870*c8dee2aaSAndroid Build Coastguard Worker // How much do we inset toward the inside of the strokes?
871*c8dee2aaSAndroid Build Coastguard Worker float inset = std::min(0.5f, std::min(devHalfStrokeSize.fX, devHalfStrokeSize.fY));
872*c8dee2aaSAndroid Build Coastguard Worker float innerCoverage = 1;
873*c8dee2aaSAndroid Build Coastguard Worker if (inset < 0.5f) {
874*c8dee2aaSAndroid Build Coastguard Worker // Stroke is subpixel, so reduce the coverage to simulate the narrower strokes.
875*c8dee2aaSAndroid Build Coastguard Worker innerCoverage = 2 * inset / (inset + .5f);
876*c8dee2aaSAndroid Build Coastguard Worker }
877*c8dee2aaSAndroid Build Coastguard Worker
878*c8dee2aaSAndroid Build Coastguard Worker // How much do we outset away from the outside of the strokes?
879*c8dee2aaSAndroid Build Coastguard Worker // We always want to keep the AA picture frame one pixel wide.
880*c8dee2aaSAndroid Build Coastguard Worker float outset = 1 - inset;
881*c8dee2aaSAndroid Build Coastguard Worker float outerCoverage = 0;
882*c8dee2aaSAndroid Build Coastguard Worker
883*c8dee2aaSAndroid Build Coastguard Worker // How much do we outset away from the interior side of the stroke (toward the center)?
884*c8dee2aaSAndroid Build Coastguard Worker float interiorOutset = outset;
885*c8dee2aaSAndroid Build Coastguard Worker float interiorCoverage = outerCoverage;
886*c8dee2aaSAndroid Build Coastguard Worker
887*c8dee2aaSAndroid Build Coastguard Worker if (usesMSAASurface) {
888*c8dee2aaSAndroid Build Coastguard Worker // Since we're using MSAA, extend our outsets to ensure any pixel with partial coverage has
889*c8dee2aaSAndroid Build Coastguard Worker // a full sample mask.
890*c8dee2aaSAndroid Build Coastguard Worker constexpr float msaaExtraBloat = SK_ScalarSqrt2 - .5f;
891*c8dee2aaSAndroid Build Coastguard Worker outset += msaaExtraBloat;
892*c8dee2aaSAndroid Build Coastguard Worker outerCoverage -= msaaExtraBloat;
893*c8dee2aaSAndroid Build Coastguard Worker
894*c8dee2aaSAndroid Build Coastguard Worker float insetExtraBloat =
895*c8dee2aaSAndroid Build Coastguard Worker std::min(inset + msaaExtraBloat,
896*c8dee2aaSAndroid Build Coastguard Worker std::min(devHalfStrokeSize.fX, devHalfStrokeSize.fY)) - inset;
897*c8dee2aaSAndroid Build Coastguard Worker inset += insetExtraBloat;
898*c8dee2aaSAndroid Build Coastguard Worker innerCoverage += insetExtraBloat;
899*c8dee2aaSAndroid Build Coastguard Worker
900*c8dee2aaSAndroid Build Coastguard Worker float interiorExtraBloat =
901*c8dee2aaSAndroid Build Coastguard Worker std::min(interiorOutset + msaaExtraBloat,
902*c8dee2aaSAndroid Build Coastguard Worker std::min(devInside.width(), devInside.height()) / 2) - interiorOutset;
903*c8dee2aaSAndroid Build Coastguard Worker interiorOutset += interiorExtraBloat;
904*c8dee2aaSAndroid Build Coastguard Worker interiorCoverage -= interiorExtraBloat;
905*c8dee2aaSAndroid Build Coastguard Worker }
906*c8dee2aaSAndroid Build Coastguard Worker
907*c8dee2aaSAndroid Build Coastguard Worker VertexColor innerColor(tweakAlphaForCoverage ? color * innerCoverage : color, wideColor);
908*c8dee2aaSAndroid Build Coastguard Worker VertexColor outerColor(tweakAlphaForCoverage ? SK_PMColor4fTRANSPARENT : color, wideColor);
909*c8dee2aaSAndroid Build Coastguard Worker
910*c8dee2aaSAndroid Build Coastguard Worker // Exterior outset rect (away from stroke).
911*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(inset_fan(devOutside, -outset, -outset),
912*c8dee2aaSAndroid Build Coastguard Worker outerColor,
913*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(outerCoverage));
914*c8dee2aaSAndroid Build Coastguard Worker
915*c8dee2aaSAndroid Build Coastguard Worker if (!miterStroke) {
916*c8dee2aaSAndroid Build Coastguard Worker // Second exterior outset.
917*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(inset_fan(devOutsideAssist, -outset, -outset),
918*c8dee2aaSAndroid Build Coastguard Worker outerColor,
919*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(outerCoverage));
920*c8dee2aaSAndroid Build Coastguard Worker }
921*c8dee2aaSAndroid Build Coastguard Worker
922*c8dee2aaSAndroid Build Coastguard Worker // Exterior inset rect (toward stroke).
923*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(inset_fan(devOutside, inset, inset),
924*c8dee2aaSAndroid Build Coastguard Worker innerColor,
925*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(innerCoverage));
926*c8dee2aaSAndroid Build Coastguard Worker
927*c8dee2aaSAndroid Build Coastguard Worker if (!miterStroke) {
928*c8dee2aaSAndroid Build Coastguard Worker // Second exterior inset.
929*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(inset_fan(devOutsideAssist, inset, inset),
930*c8dee2aaSAndroid Build Coastguard Worker innerColor,
931*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(innerCoverage));
932*c8dee2aaSAndroid Build Coastguard Worker }
933*c8dee2aaSAndroid Build Coastguard Worker
934*c8dee2aaSAndroid Build Coastguard Worker if (!degenerate) {
935*c8dee2aaSAndroid Build Coastguard Worker // Interior inset rect (toward stroke).
936*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(inset_fan(devInside, -inset, -inset),
937*c8dee2aaSAndroid Build Coastguard Worker innerColor,
938*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(innerCoverage));
939*c8dee2aaSAndroid Build Coastguard Worker
940*c8dee2aaSAndroid Build Coastguard Worker // Interior outset rect (away from stroke, toward center of rect).
941*c8dee2aaSAndroid Build Coastguard Worker SkRect interiorAABoundary = devInside.makeInset(interiorOutset, interiorOutset);
942*c8dee2aaSAndroid Build Coastguard Worker float coverageBackset = 0; // Adds back coverage when the interior AA edges cross.
943*c8dee2aaSAndroid Build Coastguard Worker if (interiorAABoundary.fLeft > interiorAABoundary.fRight) {
944*c8dee2aaSAndroid Build Coastguard Worker coverageBackset =
945*c8dee2aaSAndroid Build Coastguard Worker (interiorAABoundary.fLeft - interiorAABoundary.fRight) / (interiorOutset * 2);
946*c8dee2aaSAndroid Build Coastguard Worker interiorAABoundary.fLeft = interiorAABoundary.fRight = interiorAABoundary.centerX();
947*c8dee2aaSAndroid Build Coastguard Worker }
948*c8dee2aaSAndroid Build Coastguard Worker if (interiorAABoundary.fTop > interiorAABoundary.fBottom) {
949*c8dee2aaSAndroid Build Coastguard Worker coverageBackset = std::max(
950*c8dee2aaSAndroid Build Coastguard Worker (interiorAABoundary.fTop - interiorAABoundary.fBottom) / (interiorOutset * 2),
951*c8dee2aaSAndroid Build Coastguard Worker coverageBackset);
952*c8dee2aaSAndroid Build Coastguard Worker interiorAABoundary.fTop = interiorAABoundary.fBottom = interiorAABoundary.centerY();
953*c8dee2aaSAndroid Build Coastguard Worker }
954*c8dee2aaSAndroid Build Coastguard Worker if (coverageBackset > 0) {
955*c8dee2aaSAndroid Build Coastguard Worker // The interior edges crossed. Lerp back toward innerCoverage, which is what this op
956*c8dee2aaSAndroid Build Coastguard Worker // will draw in the degenerate case. This gives a smooth transition into the degenerate
957*c8dee2aaSAndroid Build Coastguard Worker // case.
958*c8dee2aaSAndroid Build Coastguard Worker interiorCoverage += interiorCoverage * (1 - coverageBackset) +
959*c8dee2aaSAndroid Build Coastguard Worker innerCoverage * coverageBackset;
960*c8dee2aaSAndroid Build Coastguard Worker }
961*c8dee2aaSAndroid Build Coastguard Worker VertexColor interiorColor(tweakAlphaForCoverage ? color * interiorCoverage : color,
962*c8dee2aaSAndroid Build Coastguard Worker wideColor);
963*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(VertexWriter::TriFanFromRect(interiorAABoundary),
964*c8dee2aaSAndroid Build Coastguard Worker interiorColor,
965*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(interiorCoverage));
966*c8dee2aaSAndroid Build Coastguard Worker } else {
967*c8dee2aaSAndroid Build Coastguard Worker // When the interior rect has become degenerate we smoosh to a single point
968*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(devInside.fLeft == devInside.fRight && devInside.fTop == devInside.fBottom);
969*c8dee2aaSAndroid Build Coastguard Worker
970*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(VertexWriter::TriFanFromRect(devInside),
971*c8dee2aaSAndroid Build Coastguard Worker innerColor,
972*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(innerCoverage));
973*c8dee2aaSAndroid Build Coastguard Worker
974*c8dee2aaSAndroid Build Coastguard Worker // ... unless we are degenerate, in which case we must apply the scaled coverage
975*c8dee2aaSAndroid Build Coastguard Worker vertices.writeQuad(VertexWriter::TriFanFromRect(devInside),
976*c8dee2aaSAndroid Build Coastguard Worker innerColor,
977*c8dee2aaSAndroid Build Coastguard Worker maybe_coverage(innerCoverage));
978*c8dee2aaSAndroid Build Coastguard Worker }
979*c8dee2aaSAndroid Build Coastguard Worker }
980*c8dee2aaSAndroid Build Coastguard Worker
981*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
982*c8dee2aaSAndroid Build Coastguard Worker
Make(GrRecordingContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect,const SkStrokeRec & stroke)983*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner Make(GrRecordingContext* context,
984*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint,
985*c8dee2aaSAndroid Build Coastguard Worker GrAAType aaType,
986*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
987*c8dee2aaSAndroid Build Coastguard Worker const SkRect& rect,
988*c8dee2aaSAndroid Build Coastguard Worker const SkStrokeRec& stroke) {
989*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!context->priv().caps()->reducedShaderMode());
990*c8dee2aaSAndroid Build Coastguard Worker if (aaType == GrAAType::kCoverage) {
991*c8dee2aaSAndroid Build Coastguard Worker return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke);
992*c8dee2aaSAndroid Build Coastguard Worker } else {
993*c8dee2aaSAndroid Build Coastguard Worker return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke, aaType);
994*c8dee2aaSAndroid Build Coastguard Worker }
995*c8dee2aaSAndroid Build Coastguard Worker }
996*c8dee2aaSAndroid Build Coastguard Worker
MakeNested(GrRecordingContext * context,GrPaint && paint,const SkMatrix & viewMatrix,const SkRect rects[2])997*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner MakeNested(GrRecordingContext* context,
998*c8dee2aaSAndroid Build Coastguard Worker GrPaint&& paint,
999*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
1000*c8dee2aaSAndroid Build Coastguard Worker const SkRect rects[2]) {
1001*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(viewMatrix.rectStaysRect());
1002*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty());
1003*c8dee2aaSAndroid Build Coastguard Worker
1004*c8dee2aaSAndroid Build Coastguard Worker SkRect devOutside = viewMatrix.mapRect(rects[0]);
1005*c8dee2aaSAndroid Build Coastguard Worker SkRect devInside = viewMatrix.mapRect(rects[1]);
1006*c8dee2aaSAndroid Build Coastguard Worker float dx = devOutside.fRight - devInside.fRight;
1007*c8dee2aaSAndroid Build Coastguard Worker float dy = devOutside.fBottom - devInside.fBottom;
1008*c8dee2aaSAndroid Build Coastguard Worker
1009*c8dee2aaSAndroid Build Coastguard Worker // Clips our draw rects 1 full pixel outside the viewport. This avoids interpolation precision
1010*c8dee2aaSAndroid Build Coastguard Worker // issues with very large coordinates.
1011*c8dee2aaSAndroid Build Coastguard Worker const float m = context->priv().caps()->maxRenderTargetSize();
1012*c8dee2aaSAndroid Build Coastguard Worker const SkRect visibilityBounds = SkRect::MakeWH(m, m).makeOutset(1, 1);
1013*c8dee2aaSAndroid Build Coastguard Worker
1014*c8dee2aaSAndroid Build Coastguard Worker if (!devOutside.intersect(visibilityBounds.makeOutset(dx, dy))) {
1015*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1016*c8dee2aaSAndroid Build Coastguard Worker }
1017*c8dee2aaSAndroid Build Coastguard Worker
1018*c8dee2aaSAndroid Build Coastguard Worker if (devInside.isEmpty() || !devInside.intersect(visibilityBounds)) {
1019*c8dee2aaSAndroid Build Coastguard Worker if (devOutside.isEmpty()) {
1020*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1021*c8dee2aaSAndroid Build Coastguard Worker }
1022*c8dee2aaSAndroid Build Coastguard Worker DrawQuad quad{GrQuad::MakeFromRect(rects[0], viewMatrix), GrQuad(rects[0]),
1023*c8dee2aaSAndroid Build Coastguard Worker GrQuadAAFlags::kAll};
1024*c8dee2aaSAndroid Build Coastguard Worker return ganesh::FillRectOp::Make(context, std::move(paint), GrAAType::kCoverage, &quad);
1025*c8dee2aaSAndroid Build Coastguard Worker }
1026*c8dee2aaSAndroid Build Coastguard Worker
1027*c8dee2aaSAndroid Build Coastguard Worker return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, devOutside,
1028*c8dee2aaSAndroid Build Coastguard Worker devInside, SkVector{dx, dy} * .5f);
1029*c8dee2aaSAndroid Build Coastguard Worker }
1030*c8dee2aaSAndroid Build Coastguard Worker
1031*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh::StrokeRectOp
1032*c8dee2aaSAndroid Build Coastguard Worker
1033*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
1034*c8dee2aaSAndroid Build Coastguard Worker
GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp)1035*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
1036*c8dee2aaSAndroid Build Coastguard Worker SkMatrix viewMatrix = GrTest::TestMatrix(random);
1037*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = GrTest::TestRect(random);
1038*c8dee2aaSAndroid Build Coastguard Worker SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
1039*c8dee2aaSAndroid Build Coastguard Worker SkPaint strokePaint;
1040*c8dee2aaSAndroid Build Coastguard Worker strokePaint.setStrokeWidth(strokeWidth);
1041*c8dee2aaSAndroid Build Coastguard Worker strokePaint.setStyle(SkPaint::kStroke_Style);
1042*c8dee2aaSAndroid Build Coastguard Worker strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
1043*c8dee2aaSAndroid Build Coastguard Worker SkStrokeRec strokeRec(strokePaint);
1044*c8dee2aaSAndroid Build Coastguard Worker GrAAType aaType = GrAAType::kNone;
1045*c8dee2aaSAndroid Build Coastguard Worker if (numSamples > 1) {
1046*c8dee2aaSAndroid Build Coastguard Worker aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
1047*c8dee2aaSAndroid Build Coastguard Worker }
1048*c8dee2aaSAndroid Build Coastguard Worker return skgpu::ganesh::StrokeRectOp::NonAAStrokeRectOp::Make(context, std::move(paint),
1049*c8dee2aaSAndroid Build Coastguard Worker viewMatrix, rect, strokeRec,
1050*c8dee2aaSAndroid Build Coastguard Worker aaType);
1051*c8dee2aaSAndroid Build Coastguard Worker }
1052*c8dee2aaSAndroid Build Coastguard Worker
GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp)1053*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
1054*c8dee2aaSAndroid Build Coastguard Worker bool miterStroke = random->nextBool();
1055*c8dee2aaSAndroid Build Coastguard Worker
1056*c8dee2aaSAndroid Build Coastguard Worker // Create either a empty rect or a non-empty rect.
1057*c8dee2aaSAndroid Build Coastguard Worker SkRect rect =
1058*c8dee2aaSAndroid Build Coastguard Worker random->nextBool() ? SkRect::MakeXYWH(10, 10, 50, 40) : SkRect::MakeXYWH(6, 7, 0, 0);
1059*c8dee2aaSAndroid Build Coastguard Worker SkScalar minDim = std::min(rect.width(), rect.height());
1060*c8dee2aaSAndroid Build Coastguard Worker SkScalar strokeWidth = random->nextUScalar1() * minDim;
1061*c8dee2aaSAndroid Build Coastguard Worker
1062*c8dee2aaSAndroid Build Coastguard Worker SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
1063*c8dee2aaSAndroid Build Coastguard Worker rec.setStrokeStyle(strokeWidth);
1064*c8dee2aaSAndroid Build Coastguard Worker rec.setStrokeParams(SkPaint::kButt_Cap,
1065*c8dee2aaSAndroid Build Coastguard Worker miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, 1.f);
1066*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random);
1067*c8dee2aaSAndroid Build Coastguard Worker return skgpu::ganesh::StrokeRectOp::AAStrokeRectOp::Make(context, std::move(paint), matrix,
1068*c8dee2aaSAndroid Build Coastguard Worker rect, rec);
1069*c8dee2aaSAndroid Build Coastguard Worker }
1070*c8dee2aaSAndroid Build Coastguard Worker
1071*c8dee2aaSAndroid Build Coastguard Worker #endif
1072