210 template <
typename F>
struct has_trait : std::disjunction<std::is_same<F, Traits>...> {};
211 template <PatchAttribs A>
using req_attrib = has_trait<Required<A>>;
212 template <PatchAttribs A>
using opt_attrib = has_trait<Optional<A>>;
215 static constexpr bool kTrackJoinControlPoints = has_trait<TrackJoinControlPoints>::value;
216 static constexpr bool kAddTrianglesWhenChopping = has_trait<AddTrianglesWhenChopping>::value;
217 static constexpr bool kDiscardFlatCurves = has_trait<DiscardFlatCurves>::value;
218 static constexpr bool kReplicateLineEndPoints = has_trait<ReplicateLineEndPoints>::value;
226#define DEF_ATTRIB_TYPE(name, A, T) \
227 static constexpr bool kRequire##name = req_attrib<A>::value; \
228 static constexpr bool kOptional##name = opt_attrib<A>::value; \
229 using name = attrib_t<A, T, kRequire##name, kOptional##name>
236 static constexpr bool kRequireWideColor = req_attrib<PatchAttribs::kWideColorIfEnabled>::value;
237 static constexpr bool kOptionalWideColor = opt_attrib<PatchAttribs::kWideColorIfEnabled>::value;
238 using Color = std::conditional_t<kRequireWideColor,
SkPMColor4f,
239 std::conditional_t<kOptionalWideColor, VertexColor,
246#undef DEF_ATTRIB_TYPE
248 static constexpr size_t kMaxStride = 4 *
sizeof(
SkPoint) +
249 (JoinAttrib::kEnabled ?
sizeof(
SkPoint) : 0) +
250 (FanPointAttrib::kEnabled ?
sizeof(
SkPoint) : 0) +
251 (StrokeAttrib::kEnabled ?
sizeof(StrokeParams) : 0) +
252 (ColorAttrib::kEnabled ? std::min(
sizeof(Color),
sizeof(
SkPMColor4f)) : 0) +
253 (DepthAttrib::kEnabled ?
sizeof(
float) : 0) +
254 (CurveTypeAttrib::kEnabled ?
sizeof(
float) : 0) +
255 (SsboIndexAttrib::kEnabled ?
sizeof(
int) : 0);
258 using DeferredPatch = std::conditional_t<kTrackJoinControlPoints,
259 PatchStorage<kMaxStride>, std::monostate>;
260 using InnerTriangulator = std::conditional_t<kAddTrianglesWhenChopping,
261 MiddleOutPolygonTriangulator, NullTriangulator>;
266 static_assert(!kTrackJoinControlPoints || req_attrib<PatchAttribs::kJoinControlPoint>::value,
267 "Deferred patches and auto-updating joins requires kJoinControlPoint attrib");
269 template <
typename... Args>
284 if constexpr (req_attrib<PatchAttribs::kWideColorIfEnabled>::value) {
286 }
else if constexpr (!opt_attrib<PatchAttribs::kWideColorIfEnabled>::value) {
292 if constexpr (kTrackJoinControlPoints) {
294 this->writeDeferredStrokePatch();
303 float maxScale = 1.f) {
304 fApproxTransform = xform;
305 fMaxScale = maxScale;
310 ENABLE_IF(kTrackJoinControlPoints) writeDeferredStrokePatch() {
311 if (fDeferredPatch.hasPending()) {
312 SkASSERT(!fDeferredPatch.fMustDefer);
315 memcpy(SkTAddOffset<void>(fDeferredPatch.fData, 4 *
sizeof(
SkPoint)),
321 if (
VertexWriter vw = fPatchAllocator.append(fTolerances)) {
322 vw << VertexWriter::Array<char>(fDeferredPatch.fData,
PatchStride(fAttribs));
326 fDeferredPatch.reset();
334 fJoin = lastControlPoint;
335 if constexpr (kTrackJoinControlPoints) {
336 fDeferredPatch.fMustDefer =
false;
344 fFanPoint = fanPoint;
350 fStrokeParams = strokeParams;
351 fTolerances.
setStroke(strokeParams, fMaxScale);
357 fTolerances.
setStroke(strokeParams, fMaxScale);
365 if constexpr (req_attrib<PatchAttribs::kWideColorIfEnabled>::value) {
367 }
else if constexpr (opt_attrib<PatchAttribs::kWideColorIfEnabled>::value) {
370 fColor =
color.toBytes_RGBA();
375 ENABLE_IF(DepthAttrib::kEnabled) updatePaintDepthAttrib(
float depth) {
384 fSsboIndex = ssboIndex;
397 if constexpr (kDiscardFlatCurves) {
404 if (
int numPatches = this->accountForCurve(n4)) {
405 this->chopAndWriteCubics(p0, p1, p2, p3, numPatches);
407 this->writeCubicPatch(p0, p1, p2, p3);
420 if constexpr (kDiscardFlatCurves) {
427 if (
int numPatches = this->accountForCurve(n2 * n2)) {
428 this->chopAndWriteConics(p0, p1, p2,
w, numPatches);
430 this->writeConicPatch(p0, p1, p2,
w);
435 sk_bit_cast<float2>(pts[1]),
436 sk_bit_cast<float2>(pts[2]),
444 if constexpr (kDiscardFlatCurves) {
451 if (
int numPatches = this->accountForCurve(n4)) {
452 this->chopAndWriteQuads(p0, p1, p2, numPatches);
454 this->writeQuadPatch(p0, p1, p2);
459 sk_bit_cast<float2>(pts[1]),
460 sk_bit_cast<float2>(pts[2]));
467 if constexpr (kReplicateLineEndPoints) {
471 this->writeCubicPatch(p0p1.
lo, p0p1.
lo, p0p1.
hi, p0p1.
hi);
476 this->writeCubicPatch(p0p1.
lo, (p0p1.zwxy() - p0p1) * (1/3.f) + p0p1, p0p1.
hi);
481 this->
writeLine(sk_bit_cast<float2>(p0), sk_bit_cast<float2>(p1));
489 static constexpr float kTriangleSegments_p4 = 2.f * 2.f * 2.f * 2.f;
496 sk_bit_cast<float2>(p1),
497 sk_bit_cast<float2>(p2));
506 if (
VertexWriter vw = fPatchAllocator.append(fTolerances)) {
507 vw << VertexWriter::Repeat<4>(p);
514 const JoinAttrib& join,
515 float explicitCurveType) {
517 vertexWriter << join << fFanPoint << fStrokeParams << fColor << fDepth
518 << CurveTypeAttrib{fAttribs, explicitCurveType} << fSsboIndex;
521 AI VertexWriter appendPatch() {
522 if constexpr (kTrackJoinControlPoints) {
523 if (fDeferredPatch.fMustDefer) {
524 SkASSERT(!fDeferredPatch.hasPending());
529 return {fDeferredPatch.fData,
PatchStride(fAttribs)};
532 return fPatchAllocator.append(fTolerances);
536 if (VertexWriter vw = this->appendPatch()) {
540 vw << p0 << p1 << p2 << p3;
541 this->emitPatchAttribs(std::move(vw), fJoin, explicitCurveType);
544 if constexpr (kTrackJoinControlPoints) {
548 }
else if (
any(p2 != p1)) {
555 fDeferredPatch.fMustDefer =
false;
565 this->writeCubicPatch(p0, p1p2.
lo, p1p2.
hi, p3);
568 this->writeCubicPatch(p0, mix(
float4(p0, p2), p1.xyxy(), 2/3.f), p2);
574 int accountForCurve(
float n4) {
593 return (
b -
a)*
T +
a;
600 InnerTriangulator triangulator(numPatches, sk_bit_cast<SkPoint>(p0));
601 for (; numPatches >= 3; numPatches -= 2) {
604 float4 ab = mix(p0.xyxy(), p1.xyxy(),
T);
605 float4 bc = mix(p1.xyxy(), p2.xyxy(),
T);
608 float4 middle = mix(
ab, bc, mix(
T,
T.zwxy(), 2/3.f));
610 this->writeQuadPatch(p0,
ab.lo, abc.
lo);
611 if constexpr (kAddTrianglesWhenChopping) {
614 this->writeCubicPatch(abc.
lo, middle, abc.
hi);
615 if constexpr (kAddTrianglesWhenChopping) {
616 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(abc.
hi)));
618 std::tie(p0, p1) = {abc.
hi, bc.
hi};
620 if (numPatches == 2) {
623 float2 bc = (p1 + p2) * .5f;
626 this->writeQuadPatch(p0,
ab, abc);
627 if constexpr (kAddTrianglesWhenChopping) {
630 this->writeQuadPatch(abc, bc, p2);
633 this->writeQuadPatch(p0, p1, p2);
635 if constexpr (kAddTrianglesWhenChopping) {
636 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(p2)));
637 this->writeTriangleStack(triangulator.close());
642 InnerTriangulator triangulator(numPatches, sk_bit_cast<SkPoint>(p0));
647 for (; numPatches >= 2; --numPatches) {
649 float T = 1.f/numPatches;
655 float2 midpoint = abc.xy() / abc.w();
656 this->writeConicPatch(h0.xy() / h0.w(),
659 ab.w() / sqrtf(h0.w() * abc.w()));
660 if constexpr (kAddTrianglesWhenChopping) {
661 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(midpoint)));
663 std::tie(h0, h1) = {abc, bc};
667 this->writeConicPatch(h0.xy() / h0.w(),
670 h1.w() / sqrtf(h0.w()));
671 if constexpr (kAddTrianglesWhenChopping) {
672 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(h2.xy())));
673 this->writeTriangleStack(triangulator.close());
678 InnerTriangulator triangulator(numPatches, sk_bit_cast<SkPoint>(p0));
679 for (; numPatches >= 3; numPatches -= 2) {
682 float4 ab = mix(p0.xyxy(), p1.xyxy(),
T);
683 float4 bc = mix(p1.xyxy(), p2.xyxy(),
T);
684 float4 cd = mix(p2.xyxy(), p3.xyxy(),
T);
687 float4 abcd = mix(abc, bcd,
T);
688 float4 middle = mix(abc, bcd,
T.zwxy());
690 this->writeCubicPatch(p0,
ab.lo, abc.
lo, abcd.
lo);
691 if constexpr (kAddTrianglesWhenChopping) {
694 this->writeCubicPatch(abcd.
lo, middle, abcd.
hi);
695 if constexpr (kAddTrianglesWhenChopping) {
696 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(abcd.
hi)));
698 std::tie(p0, p1, p2) = {abcd.
hi, bcd.
hi, cd.
hi};
700 if (numPatches == 2) {
703 float2 bc = (p1 + p2) * .5f;
704 float2 cd = (p2 + p3) * .5f;
706 float2 bcd = (bc + cd) * .5f;
707 float2 abcd = (abc + bcd) * .5f;
709 this->writeCubicPatch(p0,
ab, abc, abcd);
710 if constexpr (kAddTrianglesWhenChopping) {
713 this->writeCubicPatch(abcd, bcd, cd, p3);
716 this->writeCubicPatch(p0, p1, p2, p3);
718 if constexpr (kAddTrianglesWhenChopping) {
719 this->writeTriangleStack(triangulator.pushVertex(sk_bit_cast<SkPoint>(p3)));
720 this->writeTriangleStack(triangulator.close());
725 writeTriangleStack(MiddleOutPolygonTriangulator::PoppedTriangleStack&& stack) {
726 for (
auto [p0, p1, p2] : stack) {
737 wangs_formula::VectorXform fApproxTransform = {};
739 float fMaxScale = 1.0f;
741 LinearTolerances fTolerances;
743 PatchAllocator fPatchAllocator;
744 DeferredPatch fDeferredPatch;
748 FanPointAttrib fFanPoint;
749 StrokeAttrib fStrokeParams;
756 SsboIndexAttrib fSsboIndex;