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