8#ifndef skgpu_tessellate_PatchWriter_DEFINED
9#define skgpu_tessellate_PatchWriter_DEFINED
133template <PatchAttribs A,
typename T,
bool Required,
bool Optional>
136 std::conditional_t<Optional, std::pair<T, bool>,
167template <PatchAttribs A,
typename T,
bool Required,
bool Optional>
180template <
size_t Str
ide>
203#define AI SK_ALWAYS_INLINE
204#define ENABLE_IF(cond) template <typename Void=void> std::enable_if_t<cond, Void>
207template <
typename PatchAllocator,
typename... Traits>
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>>;
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>
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) +
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>;
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;
SkRGBA4f< kPremul_SkAlphaType > SkPMColor4f
constexpr float SK_FloatInfinity
#define SkScalarCeilToInt(x)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
float numParametricSegments_p4() const
void setStroke(const StrokeParams &strokeParams, float maxScale)
void setParametricSegments(float n4)
AI void writeTriangle(SkPoint p0, SkPoint p1, SkPoint p2)
PatchWriter(PatchAttribs attribs, Args &&... allocArgs)
ENABLE_IF(JoinAttrib::kEnabled) updateJoinControlPointAttrib(SkPoint lastControlPoint)
AI void writeLine(SkPoint p0, SkPoint p1)
AI void writeTriangle(float2 p0, float2 p1, float2 p2)
ENABLE_IF(kTrackJoinControlPoints) writeDeferredStrokePatch()
AI void writeQuadratic(float2 p0, float2 p1, float2 p2)
AI void writeConic(const SkPoint pts[3], float w)
AI void writeLine(float2 p0, float2 p1)
AI void writeQuadratic(const SkPoint pts[3])
ENABLE_IF(StrokeAttrib::kEnabled) updateUniformStrokeParams(StrokeParams strokeParams)
void setShaderTransform(const wangs_formula::VectorXform &xform, float maxScale=1.f)
PatchAttribs attribs() const
updateSsboIndexAttrib(skvx::ushort2 ssboIndex)
AI void writeLine(float4 p0p1)
ENABLE_IF(DepthAttrib::kEnabled) updatePaintDepthAttrib(float depth)
ENABLE_IF(FanPointAttrib::kEnabled) updateFanPointAttrib(SkPoint fanPoint)
ENABLE_IF(ColorAttrib::kEnabled) updateColorAttrib(const SkPMColor4f &color)
AI void writeConic(float2 p0, float2 p1, float2 p2, float w)
AI void writeCubic(float2 p0, float2 p1, float2 p2, float2 p3)
ENABLE_IF(StrokeAttrib::kEnabled) updateStrokeParamsAttrib(StrokeParams strokeParams)
AI void writeCircle(SkPoint p)
AI void writeCubic(const SkPoint pts[4])
static float min(float r, float g, float b)
const myers::Point & get< 1 >(const myers::Segment &s)
const myers::Point & get< 0 >(const myers::Segment &s)
static constexpr float kMaxSegmentsPerCurve_p4
static constexpr int kMaxParametricSegments_p4
VertexWriter & operator<<(VertexWriter &w, const AttribValue< A, T, Required, Optional > &v)
static constexpr float kTriangularConicCurveType
static constexpr float kPrecision
constexpr size_t PatchStride(PatchAttribs attribs)
static constexpr float kCubicCurveType
static constexpr float kConicCurveType
SIT bool all(const Vec< 1, T > &x)
Vec< 2, uint16_t > ushort2
SIT bool any(const Vec< 1, T > &x)
static SkString join(const CommandLineFlags::StringArray &)
AttribValue(PatchAttribs attribs, const T &t)
static constexpr bool kEnabled
AttribValue(PatchAttribs attribs)
AttribValue & operator=(const T &v)
std::conditional_t< Required, T, std::conditional_t< Optional, std::pair< T, bool >, std::monostate > > DataType
NullTriangulator(int, SkPoint)
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
SKVX_ALWAYS_INLINE void store(void *ptr) const