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