1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
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
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/render/TessellateStrokesRenderStep.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkM44.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkVx.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Attribute.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawOrder.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawParams.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawTypes.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PipelineData.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Geometry.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Shape.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Transform_graphite.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/render/DynamicInstancesPatchAllocator.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/FixedCountBufferUtils.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/PatchWriter.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/StrokeIterator.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/Tessellation.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/tessellate/WangsFormula.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker namespace {
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker using namespace skgpu::tess;
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker // Always use dynamic stroke params and join control points, track the join control point in
48*c8dee2aaSAndroid Build Coastguard Worker // PatchWriter and replicate line end points (match Ganesh's shader behavior).
49*c8dee2aaSAndroid Build Coastguard Worker //
50*c8dee2aaSAndroid Build Coastguard Worker // No explicit curve type on platforms that support infinity.
51*c8dee2aaSAndroid Build Coastguard Worker // No color or wide color attribs, since it might always be part of the PaintParams
52*c8dee2aaSAndroid Build Coastguard Worker // or we'll add a color-only fast path to RenderStep later.
53*c8dee2aaSAndroid Build Coastguard Worker static constexpr PatchAttribs kAttribs = PatchAttribs::kJoinControlPoint |
54*c8dee2aaSAndroid Build Coastguard Worker PatchAttribs::kStrokeParams |
55*c8dee2aaSAndroid Build Coastguard Worker PatchAttribs::kPaintDepth |
56*c8dee2aaSAndroid Build Coastguard Worker PatchAttribs::kSsboIndex;
57*c8dee2aaSAndroid Build Coastguard Worker static constexpr PatchAttribs kAttribsWithCurveType = kAttribs | PatchAttribs::kExplicitCurveType;
58*c8dee2aaSAndroid Build Coastguard Worker using Writer = PatchWriter<DynamicInstancesPatchAllocator<FixedCountStrokes>,
59*c8dee2aaSAndroid Build Coastguard Worker Required<PatchAttribs::kJoinControlPoint>,
60*c8dee2aaSAndroid Build Coastguard Worker Required<PatchAttribs::kStrokeParams>,
61*c8dee2aaSAndroid Build Coastguard Worker Required<PatchAttribs::kPaintDepth>,
62*c8dee2aaSAndroid Build Coastguard Worker Required<PatchAttribs::kSsboIndex>,
63*c8dee2aaSAndroid Build Coastguard Worker Optional<PatchAttribs::kExplicitCurveType>,
64*c8dee2aaSAndroid Build Coastguard Worker ReplicateLineEndPoints,
65*c8dee2aaSAndroid Build Coastguard Worker TrackJoinControlPoints>;
66*c8dee2aaSAndroid Build Coastguard Worker
67*c8dee2aaSAndroid Build Coastguard Worker // The order of the attribute declarations must match the order used by
68*c8dee2aaSAndroid Build Coastguard Worker // PatchWriter::emitPatchAttribs, i.e.:
69*c8dee2aaSAndroid Build Coastguard Worker // join << fanPoint << stroke << color << depth << curveType << ssboIndices
70*c8dee2aaSAndroid Build Coastguard Worker static constexpr Attribute kBaseAttributes[] = {
71*c8dee2aaSAndroid Build Coastguard Worker {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
72*c8dee2aaSAndroid Build Coastguard Worker {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
73*c8dee2aaSAndroid Build Coastguard Worker {"prevPoint", VertexAttribType::kFloat2, SkSLType::kFloat2},
74*c8dee2aaSAndroid Build Coastguard Worker {"stroke", VertexAttribType::kFloat2, SkSLType::kFloat2},
75*c8dee2aaSAndroid Build Coastguard Worker {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
76*c8dee2aaSAndroid Build Coastguard Worker {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}};
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker static constexpr Attribute kAttributesWithCurveType[] = {
79*c8dee2aaSAndroid Build Coastguard Worker {"p01", VertexAttribType::kFloat4, SkSLType::kFloat4},
80*c8dee2aaSAndroid Build Coastguard Worker {"p23", VertexAttribType::kFloat4, SkSLType::kFloat4},
81*c8dee2aaSAndroid Build Coastguard Worker {"prevPoint", VertexAttribType::kFloat2, SkSLType::kFloat2},
82*c8dee2aaSAndroid Build Coastguard Worker {"stroke", VertexAttribType::kFloat2, SkSLType::kFloat2},
83*c8dee2aaSAndroid Build Coastguard Worker {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
84*c8dee2aaSAndroid Build Coastguard Worker {"curveType", VertexAttribType::kFloat, SkSLType::kFloat},
85*c8dee2aaSAndroid Build Coastguard Worker {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}};
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkSpan<const Attribute> kAttributes[2] = {kAttributesWithCurveType,
88*c8dee2aaSAndroid Build Coastguard Worker kBaseAttributes};
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Worker } // namespace
91*c8dee2aaSAndroid Build Coastguard Worker
TessellateStrokesRenderStep(bool infinitySupport)92*c8dee2aaSAndroid Build Coastguard Worker TessellateStrokesRenderStep::TessellateStrokesRenderStep(bool infinitySupport)
93*c8dee2aaSAndroid Build Coastguard Worker : RenderStep("TessellateStrokesRenderStep",
94*c8dee2aaSAndroid Build Coastguard Worker "",
95*c8dee2aaSAndroid Build Coastguard Worker Flags::kRequiresMSAA | Flags::kPerformsShading,
96*c8dee2aaSAndroid Build Coastguard Worker /*uniforms=*/{{"affineMatrix", SkSLType::kFloat4},
97*c8dee2aaSAndroid Build Coastguard Worker {"translate", SkSLType::kFloat2},
98*c8dee2aaSAndroid Build Coastguard Worker {"maxScale", SkSLType::kFloat}},
99*c8dee2aaSAndroid Build Coastguard Worker PrimitiveType::kTriangleStrip,
100*c8dee2aaSAndroid Build Coastguard Worker kDirectDepthGreaterPass,
101*c8dee2aaSAndroid Build Coastguard Worker /*vertexAttrs=*/ {},
102*c8dee2aaSAndroid Build Coastguard Worker /*instanceAttrs=*/kAttributes[infinitySupport])
103*c8dee2aaSAndroid Build Coastguard Worker , fInfinitySupport(infinitySupport) {}
104*c8dee2aaSAndroid Build Coastguard Worker
~TessellateStrokesRenderStep()105*c8dee2aaSAndroid Build Coastguard Worker TessellateStrokesRenderStep::~TessellateStrokesRenderStep() {}
106*c8dee2aaSAndroid Build Coastguard Worker
vertexSkSL() const107*c8dee2aaSAndroid Build Coastguard Worker std::string TessellateStrokesRenderStep::vertexSkSL() const {
108*c8dee2aaSAndroid Build Coastguard Worker // TODO: Assumes vertex ID support for now, max edges must equal
109*c8dee2aaSAndroid Build Coastguard Worker // skgpu::tess::FixedCountStrokes::kMaxEdges -> (2^14 - 1) -> 16383
110*c8dee2aaSAndroid Build Coastguard Worker return SkSL::String::printf(
111*c8dee2aaSAndroid Build Coastguard Worker R"(
112*c8dee2aaSAndroid Build Coastguard Worker float edgeID = float(sk_VertexID >> 1);
113*c8dee2aaSAndroid Build Coastguard Worker if ((sk_VertexID & 1) != 0) {
114*c8dee2aaSAndroid Build Coastguard Worker edgeID = -edgeID;
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker float2x2 affine = float2x2(affineMatrix.xy, affineMatrix.zw);
117*c8dee2aaSAndroid Build Coastguard Worker float4 devAndLocalCoords = tessellate_stroked_curve(
118*c8dee2aaSAndroid Build Coastguard Worker edgeID, 16383, affine, translate, maxScale, p01, p23, prevPoint,
119*c8dee2aaSAndroid Build Coastguard Worker stroke, %s);
120*c8dee2aaSAndroid Build Coastguard Worker float4 devPosition = float4(devAndLocalCoords.xy, depth, 1.0);
121*c8dee2aaSAndroid Build Coastguard Worker stepLocalCoords = devAndLocalCoords.zw;
122*c8dee2aaSAndroid Build Coastguard Worker )",
123*c8dee2aaSAndroid Build Coastguard Worker fInfinitySupport ? "curve_type_using_inf_support(p23)" : "curveType");
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker
writeVertices(DrawWriter * dw,const DrawParams & params,skvx::uint2 ssboIndices) const126*c8dee2aaSAndroid Build Coastguard Worker void TessellateStrokesRenderStep::writeVertices(DrawWriter* dw,
127*c8dee2aaSAndroid Build Coastguard Worker const DrawParams& params,
128*c8dee2aaSAndroid Build Coastguard Worker skvx::uint2 ssboIndices) const {
129*c8dee2aaSAndroid Build Coastguard Worker SkPath path = params.geometry().shape().asPath(); // TODO: Iterate the Shape directly
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker int patchReserveCount = FixedCountStrokes::PreallocCount(path.countVerbs());
132*c8dee2aaSAndroid Build Coastguard Worker // Stroke tessellation does not use fixed indices or vertex data, and only needs the vertex ID
133*c8dee2aaSAndroid Build Coastguard Worker static const BindBufferInfo kNullBinding = {};
134*c8dee2aaSAndroid Build Coastguard Worker // TODO: All HW that Graphite will run on should support instancing ith sk_VertexID, but when
135*c8dee2aaSAndroid Build Coastguard Worker // we support Vulkan+Swiftshader, we will need the vertex buffer ID fallback unless Swiftshader
136*c8dee2aaSAndroid Build Coastguard Worker // has figured out how to support vertex IDs before then.
137*c8dee2aaSAndroid Build Coastguard Worker Writer writer{fInfinitySupport ? kAttribs : kAttribsWithCurveType,
138*c8dee2aaSAndroid Build Coastguard Worker *dw,
139*c8dee2aaSAndroid Build Coastguard Worker kNullBinding,
140*c8dee2aaSAndroid Build Coastguard Worker kNullBinding,
141*c8dee2aaSAndroid Build Coastguard Worker patchReserveCount};
142*c8dee2aaSAndroid Build Coastguard Worker writer.updatePaintDepthAttrib(params.order().depthAsFloat());
143*c8dee2aaSAndroid Build Coastguard Worker writer.updateSsboIndexAttrib(ssboIndices);
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker // The vector xform approximates how the control points are transformed by the shader to
146*c8dee2aaSAndroid Build Coastguard Worker // more accurately compute how many *parametric* segments are needed.
147*c8dee2aaSAndroid Build Coastguard Worker // getMaxScale() returns -1 if it can't compute a scale factor (e.g. perspective), taking the
148*c8dee2aaSAndroid Build Coastguard Worker // absolute value automatically converts that to an identity scale factor for our purposes.
149*c8dee2aaSAndroid Build Coastguard Worker writer.setShaderTransform(wangs_formula::VectorXform{params.transform().matrix()},
150*c8dee2aaSAndroid Build Coastguard Worker params.transform().maxScaleFactor());
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(params.isStroke());
153*c8dee2aaSAndroid Build Coastguard Worker writer.updateStrokeParamsAttrib({params.strokeStyle().halfWidth(),
154*c8dee2aaSAndroid Build Coastguard Worker params.strokeStyle().joinLimit()});
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker // TODO: If PatchWriter can handle adding caps to its deferred patches, and we can convert
157*c8dee2aaSAndroid Build Coastguard Worker // hairlines to use round caps instead of square, then StrokeIterator can be deleted entirely.
158*c8dee2aaSAndroid Build Coastguard Worker // Besides being simpler, PatchWriter already has what it needs from the shader matrix and
159*c8dee2aaSAndroid Build Coastguard Worker // stroke params, so we don't have to re-extract them here.
160*c8dee2aaSAndroid Build Coastguard Worker SkMatrix shaderMatrix = params.transform();
161*c8dee2aaSAndroid Build Coastguard Worker SkStrokeRec stroke{SkStrokeRec::kHairline_InitStyle};
162*c8dee2aaSAndroid Build Coastguard Worker stroke.setStrokeStyle(params.strokeStyle().width());
163*c8dee2aaSAndroid Build Coastguard Worker stroke.setStrokeParams(params.strokeStyle().cap(),
164*c8dee2aaSAndroid Build Coastguard Worker params.strokeStyle().join(),
165*c8dee2aaSAndroid Build Coastguard Worker params.strokeStyle().miterLimit());
166*c8dee2aaSAndroid Build Coastguard Worker StrokeIterator strokeIter(path, &stroke, &shaderMatrix);
167*c8dee2aaSAndroid Build Coastguard Worker while (strokeIter.next()) {
168*c8dee2aaSAndroid Build Coastguard Worker using Verb = StrokeIterator::Verb;
169*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* p = strokeIter.pts();
170*c8dee2aaSAndroid Build Coastguard Worker int numChops;
171*c8dee2aaSAndroid Build Coastguard Worker
172*c8dee2aaSAndroid Build Coastguard Worker // TODO: The cusp detection logic should be moved into PatchWriter and shared between
173*c8dee2aaSAndroid Build Coastguard Worker // this and StrokeTessellator.cpp, but that will require updating a lot of SkGeometry to
174*c8dee2aaSAndroid Build Coastguard Worker // operate on float2 (skvx) instead of the legacy SkNx or SkPoint.
175*c8dee2aaSAndroid Build Coastguard Worker switch (strokeIter.verb()) {
176*c8dee2aaSAndroid Build Coastguard Worker case Verb::kContourFinished:
177*c8dee2aaSAndroid Build Coastguard Worker writer.writeDeferredStrokePatch();
178*c8dee2aaSAndroid Build Coastguard Worker break;
179*c8dee2aaSAndroid Build Coastguard Worker case Verb::kCircle:
180*c8dee2aaSAndroid Build Coastguard Worker // Round cap or else an empty stroke that is specified to be drawn as a circle.
181*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(p[0]);
182*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]];
183*c8dee2aaSAndroid Build Coastguard Worker case Verb::kMoveWithinContour:
184*c8dee2aaSAndroid Build Coastguard Worker // A regular kMove invalidates the previous control point; the stroke iterator
185*c8dee2aaSAndroid Build Coastguard Worker // tells us a new value to use.
186*c8dee2aaSAndroid Build Coastguard Worker writer.updateJoinControlPointAttrib(p[0]);
187*c8dee2aaSAndroid Build Coastguard Worker break;
188*c8dee2aaSAndroid Build Coastguard Worker case Verb::kLine:
189*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(p[0], p[1]);
190*c8dee2aaSAndroid Build Coastguard Worker break;
191*c8dee2aaSAndroid Build Coastguard Worker case Verb::kQuad:
192*c8dee2aaSAndroid Build Coastguard Worker if (ConicHasCusp(p)) {
193*c8dee2aaSAndroid Build Coastguard Worker // The cusp is always at the midtandent.
194*c8dee2aaSAndroid Build Coastguard Worker SkPoint cusp = SkEvalQuadAt(p, SkFindQuadMidTangent(p));
195*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(cusp);
196*c8dee2aaSAndroid Build Coastguard Worker // A quad can only have a cusp if it's flat with a 180-degree turnaround.
197*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(p[0], cusp);
198*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(cusp, p[2]);
199*c8dee2aaSAndroid Build Coastguard Worker } else {
200*c8dee2aaSAndroid Build Coastguard Worker writer.writeQuadratic(p);
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker break;
203*c8dee2aaSAndroid Build Coastguard Worker case Verb::kConic:
204*c8dee2aaSAndroid Build Coastguard Worker if (ConicHasCusp(p)) {
205*c8dee2aaSAndroid Build Coastguard Worker // The cusp is always at the midtandent.
206*c8dee2aaSAndroid Build Coastguard Worker SkConic conic(p, strokeIter.w());
207*c8dee2aaSAndroid Build Coastguard Worker SkPoint cusp = conic.evalAt(conic.findMidTangent());
208*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(cusp);
209*c8dee2aaSAndroid Build Coastguard Worker // A conic can only have a cusp if it's flat with a 180-degree turnaround.
210*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(p[0], cusp);
211*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(cusp, p[2]);
212*c8dee2aaSAndroid Build Coastguard Worker } else {
213*c8dee2aaSAndroid Build Coastguard Worker writer.writeConic(p, strokeIter.w());
214*c8dee2aaSAndroid Build Coastguard Worker }
215*c8dee2aaSAndroid Build Coastguard Worker break;
216*c8dee2aaSAndroid Build Coastguard Worker case Verb::kCubic:
217*c8dee2aaSAndroid Build Coastguard Worker SkPoint chops[10];
218*c8dee2aaSAndroid Build Coastguard Worker float T[2];
219*c8dee2aaSAndroid Build Coastguard Worker bool areCusps;
220*c8dee2aaSAndroid Build Coastguard Worker numChops = FindCubicConvex180Chops(p, T, &areCusps);
221*c8dee2aaSAndroid Build Coastguard Worker if (numChops == 0) {
222*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(p);
223*c8dee2aaSAndroid Build Coastguard Worker } else if (numChops == 1) {
224*c8dee2aaSAndroid Build Coastguard Worker SkChopCubicAt(p, chops, T[0]);
225*c8dee2aaSAndroid Build Coastguard Worker if (areCusps) {
226*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(chops[3]);
227*c8dee2aaSAndroid Build Coastguard Worker // In a perfect world, these 3 points would be be equal after chopping
228*c8dee2aaSAndroid Build Coastguard Worker // on a cusp.
229*c8dee2aaSAndroid Build Coastguard Worker chops[2] = chops[4] = chops[3];
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(chops);
232*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(chops + 3);
233*c8dee2aaSAndroid Build Coastguard Worker } else {
234*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(numChops == 2);
235*c8dee2aaSAndroid Build Coastguard Worker SkChopCubicAt(p, chops, T[0], T[1]);
236*c8dee2aaSAndroid Build Coastguard Worker if (areCusps) {
237*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(chops[3]);
238*c8dee2aaSAndroid Build Coastguard Worker writer.writeCircle(chops[6]);
239*c8dee2aaSAndroid Build Coastguard Worker // Two cusps are only possible if it's a flat line with two 180-degree
240*c8dee2aaSAndroid Build Coastguard Worker // turnarounds.
241*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(chops[0], chops[3]);
242*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(chops[3], chops[6]);
243*c8dee2aaSAndroid Build Coastguard Worker writer.writeLine(chops[6], chops[9]);
244*c8dee2aaSAndroid Build Coastguard Worker } else {
245*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(chops);
246*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(chops + 3);
247*c8dee2aaSAndroid Build Coastguard Worker writer.writeCubic(chops + 6);
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker }
250*c8dee2aaSAndroid Build Coastguard Worker break;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker
writeUniformsAndTextures(const DrawParams & params,PipelineDataGatherer * gatherer) const255*c8dee2aaSAndroid Build Coastguard Worker void TessellateStrokesRenderStep::writeUniformsAndTextures(const DrawParams& params,
256*c8dee2aaSAndroid Build Coastguard Worker PipelineDataGatherer* gatherer) const {
257*c8dee2aaSAndroid Build Coastguard Worker // TODO: Implement perspective
258*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(params.transform().type() < Transform::Type::kPerspective);
259*c8dee2aaSAndroid Build Coastguard Worker
260*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard Worker // affineMatrix = float4 (2x2 of transform), translate = float2, maxScale = float
263*c8dee2aaSAndroid Build Coastguard Worker // Column-major 2x2 of the transform.
264*c8dee2aaSAndroid Build Coastguard Worker SkV4 upper = {params.transform().matrix().rc(0, 0), params.transform().matrix().rc(1, 0),
265*c8dee2aaSAndroid Build Coastguard Worker params.transform().matrix().rc(0, 1), params.transform().matrix().rc(1, 1)};
266*c8dee2aaSAndroid Build Coastguard Worker gatherer->write(upper);
267*c8dee2aaSAndroid Build Coastguard Worker
268*c8dee2aaSAndroid Build Coastguard Worker gatherer->write(SkPoint{params.transform().matrix().rc(0, 3),
269*c8dee2aaSAndroid Build Coastguard Worker params.transform().matrix().rc(1, 3)});
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker gatherer->write(params.transform().maxScaleFactor());
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker
274*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
275