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#ifndef tessellate_PatchWriter_DEFINED
9cb93a386Sopenharmony_ci#define tessellate_PatchWriter_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "src/gpu/GrVertexChunkArray.h"
12cb93a386Sopenharmony_ci#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
13cb93a386Sopenharmony_ci#include "src/gpu/tessellate/Tessellation.h"
14cb93a386Sopenharmony_ci#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cinamespace skgpu {
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci#if SK_GPU_V1
19cb93a386Sopenharmony_ciclass PathTessellator;
20cb93a386Sopenharmony_ci#endif
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci// Writes out tessellation patches, formatted with their specific attribs, to a GPU buffer.
23cb93a386Sopenharmony_ciclass PatchWriter {
24cb93a386Sopenharmony_cipublic:
25cb93a386Sopenharmony_ci    PatchWriter(GrMeshDrawTarget* target,
26cb93a386Sopenharmony_ci                GrVertexChunkArray* vertexChunkArray,
27cb93a386Sopenharmony_ci                PatchAttribs attribs,
28cb93a386Sopenharmony_ci                size_t patchStride,
29cb93a386Sopenharmony_ci                int initialAllocCount)
30cb93a386Sopenharmony_ci            : fPatchAttribs(attribs)
31cb93a386Sopenharmony_ci            , fChunker(target, vertexChunkArray, patchStride, initialAllocCount) {
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci#if SK_GPU_V1
35cb93a386Sopenharmony_ci    // Creates a PatchWriter that writes directly to the GrVertexChunkArray stored on the provided
36cb93a386Sopenharmony_ci    // PathTessellator.
37cb93a386Sopenharmony_ci    PatchWriter(GrMeshDrawTarget*, PathTessellator* tessellator, int initialPatchAllocCount);
38cb93a386Sopenharmony_ci#endif
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    // Updates the fan point that will be written out with each patch (i.e., the point that wedges
41cb93a386Sopenharmony_ci    // fan around).
42cb93a386Sopenharmony_ci    // PathPatchAttrib::kFanPoint must be enabled.
43cb93a386Sopenharmony_ci    void updateFanPointAttrib(SkPoint fanPoint) {
44cb93a386Sopenharmony_ci        SkASSERT(fPatchAttribs & PatchAttribs::kFanPoint);
45cb93a386Sopenharmony_ci        fFanPointAttrib = fanPoint;
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    // Updates the color that will be written out with each patch.
49cb93a386Sopenharmony_ci    // PathPatchAttrib::kColor must be enabled.
50cb93a386Sopenharmony_ci    void updateColorAttrib(const SkPMColor4f& color) {
51cb93a386Sopenharmony_ci        SkASSERT(fPatchAttribs & PatchAttribs::kColor);
52cb93a386Sopenharmony_ci        fColorAttrib.set(color, fPatchAttribs & PatchAttribs::kWideColorIfEnabled);
53cb93a386Sopenharmony_ci    }
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    // RAII. Appends a patch during construction and writes the remaining data for a cubic during
56cb93a386Sopenharmony_ci    // destruction. The caller outputs p0,p1,p2,p3 (8 floats):
57cb93a386Sopenharmony_ci    //
58cb93a386Sopenharmony_ci    //    CubicPatch(patchWriter) << p0 << p1 << p2 << p3;
59cb93a386Sopenharmony_ci    //
60cb93a386Sopenharmony_ci    struct CubicPatch {
61cb93a386Sopenharmony_ci        CubicPatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
62cb93a386Sopenharmony_ci        ~CubicPatch() {
63cb93a386Sopenharmony_ci            fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
64cb93a386Sopenharmony_ci                                            GrTessellationShader::kCubicCurveType);
65cb93a386Sopenharmony_ci        }
66cb93a386Sopenharmony_ci        operator VertexWriter&() { return fVertexWriter; }
67cb93a386Sopenharmony_ci        PatchWriter& fPatchWriter;
68cb93a386Sopenharmony_ci        VertexWriter fVertexWriter;
69cb93a386Sopenharmony_ci    };
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    // RAII. Appends a patch during construction and writes the remaining data for a conic during
72cb93a386Sopenharmony_ci    // destruction. The caller outputs p0,p1,p2,w (7 floats):
73cb93a386Sopenharmony_ci    //
74cb93a386Sopenharmony_ci    //     ConicPatch(patchWriter) << p0 << p1 << p2 << w;
75cb93a386Sopenharmony_ci    //
76cb93a386Sopenharmony_ci    struct ConicPatch {
77cb93a386Sopenharmony_ci        ConicPatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
78cb93a386Sopenharmony_ci        ~ConicPatch() {
79cb93a386Sopenharmony_ci            fVertexWriter << VertexWriter::kIEEE_32_infinity;  // p3.y=Inf indicates a conic.
80cb93a386Sopenharmony_ci            fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
81cb93a386Sopenharmony_ci                                            GrTessellationShader::kConicCurveType);
82cb93a386Sopenharmony_ci        }
83cb93a386Sopenharmony_ci        operator VertexWriter&() { return fVertexWriter; }
84cb93a386Sopenharmony_ci        PatchWriter& fPatchWriter;
85cb93a386Sopenharmony_ci        VertexWriter fVertexWriter;
86cb93a386Sopenharmony_ci    };
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    // RAII. Appends a patch during construction and writes the remaining data for a triangle during
89cb93a386Sopenharmony_ci    // destruction. The caller outputs p0,p1,p2 (6 floats):
90cb93a386Sopenharmony_ci    //
91cb93a386Sopenharmony_ci    //     TrianglePatch(patchWriter) << p0 << p1 << p2;
92cb93a386Sopenharmony_ci    //
93cb93a386Sopenharmony_ci    struct TrianglePatch {
94cb93a386Sopenharmony_ci        TrianglePatch(PatchWriter& w) : fPatchWriter(w), fVertexWriter(w.appendPatch()) {}
95cb93a386Sopenharmony_ci        ~TrianglePatch() {
96cb93a386Sopenharmony_ci            // Mark this patch as a triangle by setting it to a conic with w=Inf.
97cb93a386Sopenharmony_ci            fVertexWriter.fill(VertexWriter::kIEEE_32_infinity, 2);
98cb93a386Sopenharmony_ci            fPatchWriter.outputPatchAttribs(std::move(fVertexWriter),
99cb93a386Sopenharmony_ci                                            GrTessellationShader::kTriangularConicCurveType);
100cb93a386Sopenharmony_ci        }
101cb93a386Sopenharmony_ci        operator VertexWriter&() { return fVertexWriter; }
102cb93a386Sopenharmony_ci        PatchWriter& fPatchWriter;
103cb93a386Sopenharmony_ci        VertexWriter fVertexWriter;
104cb93a386Sopenharmony_ci    };
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    // Chops the given quadratic into 'numPatches' equal segments (in the parametric sense) and
107cb93a386Sopenharmony_ci    // writes them to the GPU buffer.
108cb93a386Sopenharmony_ci    //
109cb93a386Sopenharmony_ci    // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
110cb93a386Sopenharmony_ci    void chopAndWriteQuads(float2 p0, float2 p1, float2 p2, int numPatches);
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    // Chops the given conic into 'numPatches' equal segments (in the parametric sense) and
113cb93a386Sopenharmony_ci    // writes them to the GPU buffer.
114cb93a386Sopenharmony_ci    //
115cb93a386Sopenharmony_ci    // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
116cb93a386Sopenharmony_ci    void chopAndWriteConics(float2 p0, float2 p1, float2 p2, float w, int numPatches);
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    // Chops the given cubic into 'numPatches' equal segments (in the parametric sense) and
119cb93a386Sopenharmony_ci    // writes them to the GPU buffer.
120cb93a386Sopenharmony_ci    //
121cb93a386Sopenharmony_ci    // Fills space between chops with triangles if PathPatchAttrib::kFanPoint is not enabled.
122cb93a386Sopenharmony_ci    void chopAndWriteCubics(float2 p0, float2 p1, float2 p2, float2 p3, int numPatches);
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ciprivate:
125cb93a386Sopenharmony_ci    VertexWriter appendPatch() {
126cb93a386Sopenharmony_ci        VertexWriter vertexWriter = fChunker.appendVertex();
127cb93a386Sopenharmony_ci        if (!vertexWriter) {
128cb93a386Sopenharmony_ci            // Failed to allocate GPU storage for the patch. Write to a throwaway location so the
129cb93a386Sopenharmony_ci            // callsites don't have to do null checks.
130cb93a386Sopenharmony_ci            if (!fFallbackPatchStorage) {
131cb93a386Sopenharmony_ci                fFallbackPatchStorage.reset(fChunker.stride());
132cb93a386Sopenharmony_ci            }
133cb93a386Sopenharmony_ci            vertexWriter = fFallbackPatchStorage.data();
134cb93a386Sopenharmony_ci        }
135cb93a386Sopenharmony_ci        return vertexWriter;
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    template <typename T>
139cb93a386Sopenharmony_ci    static VertexWriter::Conditional<T> If(bool c, const T& v) { return VertexWriter::If(c,v); }
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    void outputPatchAttribs(VertexWriter vertexWriter, float explicitCurveType) {
142cb93a386Sopenharmony_ci        vertexWriter << If((fPatchAttribs & PatchAttribs::kFanPoint), fFanPointAttrib)
143cb93a386Sopenharmony_ci                     << If((fPatchAttribs & PatchAttribs::kColor), fColorAttrib)
144cb93a386Sopenharmony_ci                     << If((fPatchAttribs & PatchAttribs::kExplicitCurveType), explicitCurveType);
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    const PatchAttribs fPatchAttribs;
148cb93a386Sopenharmony_ci    SkPoint fFanPointAttrib;
149cb93a386Sopenharmony_ci    GrVertexColor fColorAttrib;
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    GrVertexChunkBuilder fChunker;
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci    // For when fChunker fails to allocate a patch in GPU memory.
154cb93a386Sopenharmony_ci    SkAutoTMalloc<char> fFallbackPatchStorage;
155cb93a386Sopenharmony_ci};
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci// Converts a line to a cubic when being output via '<<' to a VertexWriter.
158cb93a386Sopenharmony_cistruct LineToCubic {
159cb93a386Sopenharmony_ci    float4 fP0P1;
160cb93a386Sopenharmony_ci};
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ciSK_MAYBE_UNUSED SK_ALWAYS_INLINE VertexWriter& operator<<(VertexWriter& vertexWriter,
163cb93a386Sopenharmony_ci                                                          const LineToCubic& line) {
164cb93a386Sopenharmony_ci    float4 p0p1 = line.fP0P1;
165cb93a386Sopenharmony_ci    float4 v = p0p1.zwxy() - p0p1;
166cb93a386Sopenharmony_ci    return vertexWriter << p0p1.lo << (v * (1/3.f) + p0p1) << p0p1.hi;
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci// Converts a quadratic to a cubic when being output via '<<' to a VertexWriter.
170cb93a386Sopenharmony_cistruct QuadToCubic {
171cb93a386Sopenharmony_ci    float2 fP0, fP1, fP2;
172cb93a386Sopenharmony_ci};
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ciSK_MAYBE_UNUSED SK_ALWAYS_INLINE VertexWriter& operator<<(VertexWriter& vertexWriter,
175cb93a386Sopenharmony_ci                                                          const QuadToCubic& quadratic) {
176cb93a386Sopenharmony_ci    auto [p0, p1, p2] = quadratic;
177cb93a386Sopenharmony_ci    return vertexWriter << p0 << mix(float4(p0,p2), p1.xyxy(), 2/3.f) << p2;
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ciSK_MAYBE_UNUSED SK_ALWAYS_INLINE void operator<<(
181cb93a386Sopenharmony_ci        PatchWriter& w, MiddleOutPolygonTriangulator::PoppedTriangleStack&& stack) {
182cb93a386Sopenharmony_ci    for (auto [p0, p1, p2] : stack) {
183cb93a386Sopenharmony_ci        PatchWriter::TrianglePatch(w) << p0 << p1 << p2;
184cb93a386Sopenharmony_ci    }
185cb93a386Sopenharmony_ci}
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci}  // namespace skgpu
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci#endif  // tessellate_PatchWriter_DEFINED
190