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/PathCurveTessellator.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h" 11cb93a386Sopenharmony_ci#include "src/gpu/tessellate/AffineMatrix.h" 12cb93a386Sopenharmony_ci#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h" 13cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PatchWriter.h" 14cb93a386Sopenharmony_ci#include "src/gpu/tessellate/WangsFormula.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#if SK_GPU_V1 17cb93a386Sopenharmony_ci#include "src/gpu/GrMeshDrawTarget.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 20cb93a386Sopenharmony_ci#endif 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_cinamespace skgpu { 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciusing CubicPatch = PatchWriter::CubicPatch; 25cb93a386Sopenharmony_ciusing ConicPatch = PatchWriter::ConicPatch; 26cb93a386Sopenharmony_ciusing TrianglePatch = PatchWriter::TrianglePatch; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciint PathCurveTessellator::patchPreallocCount(int totalCombinedPathVerbCnt) const { 29cb93a386Sopenharmony_ci // Over-allocate enough curves for 1 in 4 to chop. 30cb93a386Sopenharmony_ci int approxNumChops = (totalCombinedPathVerbCnt + 3) / 4; 31cb93a386Sopenharmony_ci // Every chop introduces 2 new patches: another curve patch and a triangle patch that glues the 32cb93a386Sopenharmony_ci // two chops together. 33cb93a386Sopenharmony_ci return totalCombinedPathVerbCnt + approxNumChops * 2; 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_civoid PathCurveTessellator::writePatches(PatchWriter& patchWriter, 37cb93a386Sopenharmony_ci int maxTessellationSegments, 38cb93a386Sopenharmony_ci const SkMatrix& shaderMatrix, 39cb93a386Sopenharmony_ci const PathDrawList& pathDrawList) { 40cb93a386Sopenharmony_ci float maxSegments_pow2 = pow2(maxTessellationSegments); 41cb93a386Sopenharmony_ci float maxSegments_pow4 = pow2(maxSegments_pow2); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci // If using fixed count, this is the number of segments we need to emit per instance. Always 44cb93a386Sopenharmony_ci // emit at least 2 segments so we can support triangles. 45cb93a386Sopenharmony_ci float numFixedSegments_pow4 = 2*2*2*2; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci for (auto [pathMatrix, path, color] : pathDrawList) { 48cb93a386Sopenharmony_ci AffineMatrix m(pathMatrix); 49cb93a386Sopenharmony_ci wangs_formula::VectorXform totalXform(SkMatrix::Concat(shaderMatrix, pathMatrix)); 50cb93a386Sopenharmony_ci if (fAttribs & PatchAttribs::kColor) { 51cb93a386Sopenharmony_ci patchWriter.updateColorAttrib(color); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { 54cb93a386Sopenharmony_ci switch (verb) { 55cb93a386Sopenharmony_ci case SkPathVerb::kQuad: { 56cb93a386Sopenharmony_ci auto [p0, p1] = m.map2Points(pts); 57cb93a386Sopenharmony_ci auto p2 = m.map1Point(pts+2); 58cb93a386Sopenharmony_ci float n4 = wangs_formula::quadratic_pow4(kTessellationPrecision, 59cb93a386Sopenharmony_ci pts, 60cb93a386Sopenharmony_ci totalXform); 61cb93a386Sopenharmony_ci if (n4 <= 1) { 62cb93a386Sopenharmony_ci break; // This quad only needs 1 segment, which is empty. 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci if (n4 <= maxSegments_pow4) { 65cb93a386Sopenharmony_ci // This quad already fits in "maxTessellationSegments". 66cb93a386Sopenharmony_ci CubicPatch(patchWriter) << QuadToCubic{p0, p1, p2}; 67cb93a386Sopenharmony_ci } else { 68cb93a386Sopenharmony_ci // Chop until each quad tessellation requires "maxSegments" or fewer. 69cb93a386Sopenharmony_ci int numPatches = 70cb93a386Sopenharmony_ci SkScalarCeilToInt(wangs_formula::root4(n4/maxSegments_pow4)); 71cb93a386Sopenharmony_ci patchWriter.chopAndWriteQuads(p0, p1, p2, numPatches); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci numFixedSegments_pow4 = std::max(n4, numFixedSegments_pow4); 74cb93a386Sopenharmony_ci break; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci case SkPathVerb::kConic: { 78cb93a386Sopenharmony_ci auto [p0, p1] = m.map2Points(pts); 79cb93a386Sopenharmony_ci auto p2 = m.map1Point(pts+2); 80cb93a386Sopenharmony_ci float n2 = wangs_formula::conic_pow2(kTessellationPrecision, 81cb93a386Sopenharmony_ci pts, 82cb93a386Sopenharmony_ci *w, 83cb93a386Sopenharmony_ci totalXform); 84cb93a386Sopenharmony_ci if (n2 <= 1) { 85cb93a386Sopenharmony_ci break; // This conic only needs 1 segment, which is empty. 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci if (n2 <= maxSegments_pow2) { 88cb93a386Sopenharmony_ci // This conic already fits in "maxTessellationSegments". 89cb93a386Sopenharmony_ci ConicPatch(patchWriter) << p0 << p1 << p2 << *w; 90cb93a386Sopenharmony_ci } else { 91cb93a386Sopenharmony_ci // Chop until each conic tessellation requires "maxSegments" or fewer. 92cb93a386Sopenharmony_ci int numPatches = SkScalarCeilToInt(sqrtf(n2/maxSegments_pow2)); 93cb93a386Sopenharmony_ci patchWriter.chopAndWriteConics(p0, p1, p2, *w, numPatches); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci numFixedSegments_pow4 = std::max(n2*n2, numFixedSegments_pow4); 96cb93a386Sopenharmony_ci break; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci case SkPathVerb::kCubic: { 100cb93a386Sopenharmony_ci auto [p0, p1] = m.map2Points(pts); 101cb93a386Sopenharmony_ci auto [p2, p3] = m.map2Points(pts+2); 102cb93a386Sopenharmony_ci float n4 = wangs_formula::cubic_pow4(kTessellationPrecision, 103cb93a386Sopenharmony_ci pts, 104cb93a386Sopenharmony_ci totalXform); 105cb93a386Sopenharmony_ci if (n4 <= 1) { 106cb93a386Sopenharmony_ci break; // This cubic only needs 1 segment, which is empty. 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci if (n4 <= maxSegments_pow4) { 109cb93a386Sopenharmony_ci // This cubic already fits in "maxTessellationSegments". 110cb93a386Sopenharmony_ci CubicPatch(patchWriter) << p0 << p1 << p2 << p3; 111cb93a386Sopenharmony_ci } else { 112cb93a386Sopenharmony_ci // Chop until each cubic tessellation requires "maxSegments" or fewer. 113cb93a386Sopenharmony_ci int numPatches = 114cb93a386Sopenharmony_ci SkScalarCeilToInt(wangs_formula::root4(n4/maxSegments_pow4)); 115cb93a386Sopenharmony_ci patchWriter.chopAndWriteCubics(p0, p1, p2, p3, numPatches); 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci numFixedSegments_pow4 = std::max(n4, numFixedSegments_pow4); 118cb93a386Sopenharmony_ci break; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci default: break; 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci // log16(n^4) == log2(n). 127cb93a386Sopenharmony_ci // We already chopped curves to make sure none needed a higher resolveLevel than 128cb93a386Sopenharmony_ci // kMaxFixedResolveLevel. 129cb93a386Sopenharmony_ci fFixedResolveLevel = SkTPin(wangs_formula::nextlog16(numFixedSegments_pow4), 130cb93a386Sopenharmony_ci fFixedResolveLevel, 131cb93a386Sopenharmony_ci int(kMaxFixedResolveLevel)); 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_civoid PathCurveTessellator::WriteFixedVertexBuffer(VertexWriter vertexWriter, size_t bufferSize) { 135cb93a386Sopenharmony_ci SkASSERT(bufferSize >= sizeof(SkPoint) * 2); 136cb93a386Sopenharmony_ci SkASSERT(bufferSize % sizeof(SkPoint) == 0); 137cb93a386Sopenharmony_ci int vertexCount = bufferSize / sizeof(SkPoint); 138cb93a386Sopenharmony_ci SkASSERT(vertexCount > 3); 139cb93a386Sopenharmony_ci SkDEBUGCODE(VertexWriter end = vertexWriter.makeOffset(vertexCount * sizeof(SkPoint));) 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci // Lay out the vertices in "middle-out" order: 142cb93a386Sopenharmony_ci // 143cb93a386Sopenharmony_ci // T= 0/1, 1/1, ; resolveLevel=0 144cb93a386Sopenharmony_ci // 1/2, ; resolveLevel=1 (0/2 and 2/2 are already in resolveLevel 0) 145cb93a386Sopenharmony_ci // 1/4, 3/4, ; resolveLevel=2 (2/4 is already in resolveLevel 1) 146cb93a386Sopenharmony_ci // 1/8, 3/8, 5/8, 7/8, ; resolveLevel=3 (2/8 and 6/8 are already in resolveLevel 2) 147cb93a386Sopenharmony_ci // ... ; resolveLevel=... 148cb93a386Sopenharmony_ci // 149cb93a386Sopenharmony_ci // Resolve level 0 is just the beginning and ending vertices. 150cb93a386Sopenharmony_ci vertexWriter << (float)0/*resolveLevel*/ << (float)0/*idx*/; 151cb93a386Sopenharmony_ci vertexWriter << (float)0/*resolveLevel*/ << (float)1/*idx*/; 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci // Resolve levels 1..kMaxResolveLevel. 154cb93a386Sopenharmony_ci int maxResolveLevel = SkPrevLog2(vertexCount - 1); 155cb93a386Sopenharmony_ci SkASSERT((1 << maxResolveLevel) + 1 == vertexCount); 156cb93a386Sopenharmony_ci for (int resolveLevel = 1; resolveLevel <= maxResolveLevel; ++resolveLevel) { 157cb93a386Sopenharmony_ci int numSegmentsInResolveLevel = 1 << resolveLevel; 158cb93a386Sopenharmony_ci // Write out the odd vertices in this resolveLevel. The even vertices were already written 159cb93a386Sopenharmony_ci // out in previous resolveLevels and will be indexed from there. 160cb93a386Sopenharmony_ci for (int i = 1; i < numSegmentsInResolveLevel; i += 2) { 161cb93a386Sopenharmony_ci vertexWriter << (float)resolveLevel << (float)i; 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci SkASSERT(vertexWriter == end); 166cb93a386Sopenharmony_ci} 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_civoid PathCurveTessellator::WriteFixedIndexBufferBaseIndex(VertexWriter vertexWriter, 169cb93a386Sopenharmony_ci size_t bufferSize, 170cb93a386Sopenharmony_ci uint16_t baseIndex) { 171cb93a386Sopenharmony_ci SkASSERT(bufferSize % (sizeof(uint16_t) * 3) == 0); 172cb93a386Sopenharmony_ci int triangleCount = bufferSize / (sizeof(uint16_t) * 3); 173cb93a386Sopenharmony_ci SkASSERT(triangleCount >= 1); 174cb93a386Sopenharmony_ci SkTArray<std::array<uint16_t, 3>> indexData(triangleCount); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci // Connect the vertices with a middle-out triangulation. Refer to InitFixedCountVertexBuffer() 177cb93a386Sopenharmony_ci // for the exact vertex ordering. 178cb93a386Sopenharmony_ci // 179cb93a386Sopenharmony_ci // Resolve level 1 is just a single triangle at T=[0, 1/2, 1]. 180cb93a386Sopenharmony_ci const auto* neighborInLastResolveLevel = &indexData.push_back({baseIndex, 181cb93a386Sopenharmony_ci (uint16_t)(baseIndex + 2), 182cb93a386Sopenharmony_ci (uint16_t)(baseIndex + 1)}); 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci // Resolve levels 2..maxResolveLevel 185cb93a386Sopenharmony_ci int maxResolveLevel = SkPrevLog2(triangleCount + 1); 186cb93a386Sopenharmony_ci uint16_t nextIndex = baseIndex + 3; 187cb93a386Sopenharmony_ci SkASSERT(NumCurveTrianglesAtResolveLevel(maxResolveLevel) == triangleCount); 188cb93a386Sopenharmony_ci for (int resolveLevel = 2; resolveLevel <= maxResolveLevel; ++resolveLevel) { 189cb93a386Sopenharmony_ci SkDEBUGCODE(auto* firstTriangleInCurrentResolveLevel = indexData.end()); 190cb93a386Sopenharmony_ci int numOuterTrianglelsInResolveLevel = 1 << (resolveLevel - 1); 191cb93a386Sopenharmony_ci SkASSERT(numOuterTrianglelsInResolveLevel % 2 == 0); 192cb93a386Sopenharmony_ci int numTrianglePairsInResolveLevel = numOuterTrianglelsInResolveLevel >> 1; 193cb93a386Sopenharmony_ci for (int i = 0; i < numTrianglePairsInResolveLevel; ++i) { 194cb93a386Sopenharmony_ci // First triangle shares the left edge of "neighborInLastResolveLevel". 195cb93a386Sopenharmony_ci indexData.push_back({(*neighborInLastResolveLevel)[0], 196cb93a386Sopenharmony_ci nextIndex++, 197cb93a386Sopenharmony_ci (*neighborInLastResolveLevel)[1]}); 198cb93a386Sopenharmony_ci // Second triangle shares the right edge of "neighborInLastResolveLevel". 199cb93a386Sopenharmony_ci indexData.push_back({(*neighborInLastResolveLevel)[1], 200cb93a386Sopenharmony_ci nextIndex++, 201cb93a386Sopenharmony_ci (*neighborInLastResolveLevel)[2]}); 202cb93a386Sopenharmony_ci ++neighborInLastResolveLevel; 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci SkASSERT(neighborInLastResolveLevel == firstTriangleInCurrentResolveLevel); 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci SkASSERT(indexData.count() == triangleCount); 207cb93a386Sopenharmony_ci SkASSERT(nextIndex == baseIndex + triangleCount + 2); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci vertexWriter.writeArray(indexData.data(), indexData.count()); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci#if SK_GPU_V1 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey); 215cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_civoid PathCurveTessellator::prepareFixedCountBuffers(GrMeshDrawTarget* target) { 218cb93a386Sopenharmony_ci GrResourceProvider* rp = target->resourceProvider(); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci GR_DEFINE_STATIC_UNIQUE_KEY(gFixedVertexBufferKey); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci fFixedVertexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kVertex, 223cb93a386Sopenharmony_ci FixedVertexBufferSize(kMaxFixedResolveLevel), 224cb93a386Sopenharmony_ci gFixedVertexBufferKey, 225cb93a386Sopenharmony_ci WriteFixedVertexBuffer); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci GR_DEFINE_STATIC_UNIQUE_KEY(gFixedIndexBufferKey); 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci fFixedIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex, 230cb93a386Sopenharmony_ci FixedIndexBufferSize(kMaxFixedResolveLevel), 231cb93a386Sopenharmony_ci gFixedIndexBufferKey, 232cb93a386Sopenharmony_ci WriteFixedIndexBuffer); 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_civoid PathCurveTessellator::drawTessellated(GrOpFlushState* flushState) const { 236cb93a386Sopenharmony_ci for (const GrVertexChunk& chunk : fVertexChunkArray) { 237cb93a386Sopenharmony_ci flushState->bindBuffers(nullptr, nullptr, chunk.fBuffer); 238cb93a386Sopenharmony_ci flushState->draw(chunk.fCount * 4, chunk.fBase * 4); 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci} 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_civoid PathCurveTessellator::drawFixedCount(GrOpFlushState* flushState) const { 243cb93a386Sopenharmony_ci if (!fFixedVertexBuffer || !fFixedIndexBuffer) { 244cb93a386Sopenharmony_ci return; 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci int fixedIndexCount = NumCurveTrianglesAtResolveLevel(fFixedResolveLevel) * 3; 247cb93a386Sopenharmony_ci for (const GrVertexChunk& chunk : fVertexChunkArray) { 248cb93a386Sopenharmony_ci flushState->bindBuffers(fFixedIndexBuffer, chunk.fBuffer, fFixedVertexBuffer); 249cb93a386Sopenharmony_ci flushState->drawIndexedInstanced(fixedIndexCount, 0, chunk.fCount, chunk.fBase, 0); 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_civoid PathCurveTessellator::drawHullInstances(GrOpFlushState* flushState, 254cb93a386Sopenharmony_ci sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const { 255cb93a386Sopenharmony_ci for (const GrVertexChunk& chunk : fVertexChunkArray) { 256cb93a386Sopenharmony_ci flushState->bindBuffers(nullptr, chunk.fBuffer, vertexBufferIfNeeded); 257cb93a386Sopenharmony_ci flushState->drawInstanced(chunk.fCount, chunk.fBase, 4, 0); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci} 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci#endif 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci} // namespace skgpu 264