1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PatchWriter.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PathTessellator.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_cinamespace skgpu {
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ciSK_ALWAYS_INLINE SkPoint to_skpoint(float2 p) { return skvx::bit_pun<SkPoint>(p); }
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#if SK_GPU_V1
17cb93a386Sopenharmony_ciPatchWriter::PatchWriter(GrMeshDrawTarget* target,
18cb93a386Sopenharmony_ci                         PathTessellator* tessellator,
19cb93a386Sopenharmony_ci                         int initialPatchAllocCount)
20cb93a386Sopenharmony_ci        : PatchWriter(target,
21cb93a386Sopenharmony_ci                      &tessellator->fVertexChunkArray,
22cb93a386Sopenharmony_ci                      tessellator->fAttribs,
23cb93a386Sopenharmony_ci                      sizeof(SkPoint) * 4 + PatchAttribsStride(tessellator->fAttribs),
24cb93a386Sopenharmony_ci                      initialPatchAllocCount) {
25cb93a386Sopenharmony_ci}
26cb93a386Sopenharmony_ci#endif
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_civoid PatchWriter::chopAndWriteQuads(float2 p0, float2 p1, float2 p2, int numPatches) {
29cb93a386Sopenharmony_ci    // If we aren't fanning, we need to fill the space between chops with triangles.
30cb93a386Sopenharmony_ci    bool needsInnerTriangles = !(fPatchAttribs & PatchAttribs::kFanPoint);
31cb93a386Sopenharmony_ci    MiddleOutPolygonTriangulator innerTriangulator(numPatches, to_skpoint(p0));
32cb93a386Sopenharmony_ci    for (; numPatches >= 3; numPatches -= 2) {
33cb93a386Sopenharmony_ci        // Chop into 3 quads.
34cb93a386Sopenharmony_ci        float4 T = float4(1,1,2,2) / numPatches;
35cb93a386Sopenharmony_ci        float4 ab = mix(p0.xyxy(), p1.xyxy(), T);
36cb93a386Sopenharmony_ci        float4 bc = mix(p1.xyxy(), p2.xyxy(), T);
37cb93a386Sopenharmony_ci        float4 abc = mix(ab, bc, T);
38cb93a386Sopenharmony_ci        // p1 & p2 of the cubic representation of the middle quad.
39cb93a386Sopenharmony_ci        float4 middle = mix(ab, bc, mix(T, T.zwxy(), 2/3.f));
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci        CubicPatch(*this) << QuadToCubic{p0, ab.lo, abc.lo};  // Write the 1st quad.
42cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
43cb93a386Sopenharmony_ci            TrianglePatch(*this) << p0 << abc.lo << abc.hi;
44cb93a386Sopenharmony_ci        }
45cb93a386Sopenharmony_ci        CubicPatch(*this) << abc.lo << middle << abc.hi;  // Write the 2nd quad.
46cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
47cb93a386Sopenharmony_ci            *this << innerTriangulator.pushVertex(to_skpoint(abc.hi));
48cb93a386Sopenharmony_ci        }
49cb93a386Sopenharmony_ci        std::tie(p0, p1) = {abc.hi, bc.hi};  // Save the 3rd quad.
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci    if (numPatches == 2) {
52cb93a386Sopenharmony_ci        // Chop into 2 quads.
53cb93a386Sopenharmony_ci        float2 ab = (p0 + p1) * .5f;
54cb93a386Sopenharmony_ci        float2 bc = (p1 + p2) * .5f;
55cb93a386Sopenharmony_ci        float2 abc = (ab + bc) * .5f;
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci        CubicPatch(*this) << QuadToCubic{p0, ab, abc};  // Write the 1st quad.
58cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
59cb93a386Sopenharmony_ci            TrianglePatch(*this) << p0 << abc << p2;
60cb93a386Sopenharmony_ci        }
61cb93a386Sopenharmony_ci        CubicPatch(*this) << QuadToCubic{abc, bc, p2};  // Write the 2nd quad.
62cb93a386Sopenharmony_ci    } else {
63cb93a386Sopenharmony_ci        SkASSERT(numPatches == 1);
64cb93a386Sopenharmony_ci        CubicPatch(*this) << QuadToCubic{p0, p1, p2};  // Write the single quad.
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    if (needsInnerTriangles) {
67cb93a386Sopenharmony_ci        *this << innerTriangulator.pushVertex(to_skpoint(p2));
68cb93a386Sopenharmony_ci        *this << innerTriangulator.close();
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_civoid PatchWriter::chopAndWriteConics(float2 p0, float2 p1, float2 p2, float w, int numPatches) {
73cb93a386Sopenharmony_ci    // If we aren't fanning, we need to fill the space between chops with triangles.
74cb93a386Sopenharmony_ci    bool needsInnerTriangles = !(fPatchAttribs & PatchAttribs::kFanPoint);
75cb93a386Sopenharmony_ci    MiddleOutPolygonTriangulator innerTriangulator(numPatches, to_skpoint(p0));
76cb93a386Sopenharmony_ci    // Load the conic in 3d homogeneous (unprojected) space.
77cb93a386Sopenharmony_ci    float4 h0 = float4(p0,1,1);
78cb93a386Sopenharmony_ci    float4 h1 = float4(p1,1,1) * w;
79cb93a386Sopenharmony_ci    float4 h2 = float4(p2,1,1);
80cb93a386Sopenharmony_ci    for (; numPatches >= 2; --numPatches) {
81cb93a386Sopenharmony_ci        // Chop in homogeneous space.
82cb93a386Sopenharmony_ci        float T = 1.f/numPatches;
83cb93a386Sopenharmony_ci        float4 ab = mix(h0, h1, T);
84cb93a386Sopenharmony_ci        float4 bc = mix(h1, h2, T);
85cb93a386Sopenharmony_ci        float4 abc = mix(ab, bc, T);
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci        // Project and write the 1st conic.
88cb93a386Sopenharmony_ci        float2 midpoint = abc.xy() / abc.w();
89cb93a386Sopenharmony_ci        ConicPatch(*this) << (h0.xy() / h0.w())
90cb93a386Sopenharmony_ci                          << (ab.xy() / ab.w())
91cb93a386Sopenharmony_ci                          << midpoint
92cb93a386Sopenharmony_ci                          << (ab.w() / sqrtf(h0.w() * abc.w()));
93cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
94cb93a386Sopenharmony_ci            *this << innerTriangulator.pushVertex(to_skpoint(midpoint));
95cb93a386Sopenharmony_ci        }
96cb93a386Sopenharmony_ci        std::tie(h0, h1) = {abc, bc};  // Save the 2nd conic (in homogeneous space).
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci    // Project and write the remaining conic.
99cb93a386Sopenharmony_ci    SkASSERT(numPatches == 1);
100cb93a386Sopenharmony_ci    ConicPatch(*this) << (h0.xy() / h0.w())
101cb93a386Sopenharmony_ci                      << (h1.xy() / h1.w())
102cb93a386Sopenharmony_ci                      << h2.xy()  // h2.w == 1
103cb93a386Sopenharmony_ci                      << (h1.w() / sqrtf(h0.w()));
104cb93a386Sopenharmony_ci    if (needsInnerTriangles) {
105cb93a386Sopenharmony_ci        *this << innerTriangulator.pushVertex(to_skpoint(h2.xy()));
106cb93a386Sopenharmony_ci        *this << innerTriangulator.close();
107cb93a386Sopenharmony_ci    }
108cb93a386Sopenharmony_ci}
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_civoid PatchWriter::chopAndWriteCubics(float2 p0, float2 p1, float2 p2, float2 p3, int numPatches) {
111cb93a386Sopenharmony_ci    // If we aren't fanning, we need to fill the space between chops with triangles.
112cb93a386Sopenharmony_ci    bool needsInnerTriangles = !(fPatchAttribs & PatchAttribs::kFanPoint);
113cb93a386Sopenharmony_ci    MiddleOutPolygonTriangulator innerTriangulator(numPatches, to_skpoint(p0));
114cb93a386Sopenharmony_ci    for (; numPatches >= 3; numPatches -= 2) {
115cb93a386Sopenharmony_ci        // Chop into 3 cubics.
116cb93a386Sopenharmony_ci        float4 T = float4(1,1,2,2) / numPatches;
117cb93a386Sopenharmony_ci        float4 ab = mix(p0.xyxy(), p1.xyxy(), T);
118cb93a386Sopenharmony_ci        float4 bc = mix(p1.xyxy(), p2.xyxy(), T);
119cb93a386Sopenharmony_ci        float4 cd = mix(p2.xyxy(), p3.xyxy(), T);
120cb93a386Sopenharmony_ci        float4 abc = mix(ab, bc, T);
121cb93a386Sopenharmony_ci        float4 bcd = mix(bc, cd, T);
122cb93a386Sopenharmony_ci        float4 abcd = mix(abc, bcd, T);
123cb93a386Sopenharmony_ci        float4 middle = mix(abc, bcd, T.zwxy());  // p1 & p2 of the middle cubic.
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci        CubicPatch(*this) << p0 << ab.lo << abc.lo << abcd.lo;  // Write the 1st cubic.
126cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
127cb93a386Sopenharmony_ci            TrianglePatch(*this) << p0 << abcd.lo << abcd.hi;
128cb93a386Sopenharmony_ci        }
129cb93a386Sopenharmony_ci        CubicPatch(*this) << abcd.lo << middle << abcd.hi;  // Write the 2nd cubic.
130cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
131cb93a386Sopenharmony_ci            *this << innerTriangulator.pushVertex(to_skpoint(abcd.hi));
132cb93a386Sopenharmony_ci        }
133cb93a386Sopenharmony_ci        std::tie(p0, p1, p2) = {abcd.hi, bcd.hi, cd.hi};  // Save the 3rd cubic.
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci    if (numPatches == 2) {
136cb93a386Sopenharmony_ci        // Chop into 2 cubics.
137cb93a386Sopenharmony_ci        float2 ab = (p0 + p1) * .5f;
138cb93a386Sopenharmony_ci        float2 bc = (p1 + p2) * .5f;
139cb93a386Sopenharmony_ci        float2 cd = (p2 + p3) * .5f;
140cb93a386Sopenharmony_ci        float2 abc = (ab + bc) * .5f;
141cb93a386Sopenharmony_ci        float2 bcd = (bc + cd) * .5f;
142cb93a386Sopenharmony_ci        float2 abcd = (abc + bcd) * .5f;
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ci        CubicPatch(*this) << p0 << ab << abc << abcd;  // Write the 1st cubic.
145cb93a386Sopenharmony_ci        if (needsInnerTriangles) {
146cb93a386Sopenharmony_ci            TrianglePatch(*this) << p0 << abcd << p3;
147cb93a386Sopenharmony_ci        }
148cb93a386Sopenharmony_ci        CubicPatch(*this) << abcd << bcd << cd << p3;  // Write the 2nd cubic.
149cb93a386Sopenharmony_ci    } else {
150cb93a386Sopenharmony_ci        SkASSERT(numPatches == 1);
151cb93a386Sopenharmony_ci        CubicPatch(*this) << p0 << p1 << p2 << p3;  // Write the single cubic.
152cb93a386Sopenharmony_ci    }
153cb93a386Sopenharmony_ci    if (needsInnerTriangles) {
154cb93a386Sopenharmony_ci        *this << innerTriangulator.pushVertex(to_skpoint(p3));
155cb93a386Sopenharmony_ci        *this << innerTriangulator.close();
156cb93a386Sopenharmony_ci    }
157cb93a386Sopenharmony_ci}
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci}  // namespace skgpu
160