1 | /* |
2 | * Copyright 2020 Google Inc. |
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 GrResolveLevelCounter_DEFINED |
9 | #define GrResolveLevelCounter_DEFINED |
10 | |
11 | #include "src/core/SkPathPriv.h" |
12 | #include "src/gpu/tessellate/GrTessellationPathRenderer.h" |
13 | #include "src/gpu/tessellate/GrWangsFormula.h" |
14 | |
15 | // This class helps bin cubics by log2 "resolveLevel" when we don't use hardware tessellation. It is |
16 | // composed of simple counters that track how many cubics we intend to draw at each resolveLevel, |
17 | // and how many resolveLevels there are that have at least one cubic. |
18 | class GrResolveLevelCounter { |
19 | public: |
20 | void reset() { |
21 | memset(fInstanceCounts, 0, sizeof(fInstanceCounts)); |
22 | SkDEBUGCODE(fHasCalledReset = true;) |
23 | } |
24 | |
25 | void reset(const SkPath& path, const SkMatrix& viewMatrix, float intolerance) { |
26 | this->reset(); |
27 | GrVectorXform xform(viewMatrix); |
28 | for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { |
29 | switch (verb) { |
30 | case SkPathVerb::kQuad: |
31 | // Quadratics get converted to cubics before rendering. |
32 | this->countCubic(GrWangsFormula::quadratic_log2(intolerance, pts, xform)); |
33 | break; |
34 | case SkPathVerb::kCubic: |
35 | this->countCubic(GrWangsFormula::cubic_log2(intolerance, pts, xform)); |
36 | break; |
37 | default: |
38 | break; |
39 | } |
40 | } |
41 | } |
42 | |
43 | void countCubic(int resolveLevel) { |
44 | SkASSERT(fHasCalledReset); |
45 | SkASSERT(resolveLevel >= 0); |
46 | if (resolveLevel == 0) { |
47 | // Cubics with 2^0=1 segments are empty (zero area). We ignore them completely. |
48 | return; |
49 | } |
50 | resolveLevel = std::min(resolveLevel, GrTessellationPathRenderer::kMaxResolveLevel); |
51 | if (!fInstanceCounts[resolveLevel]++) { |
52 | ++fTotalCubicIndirectDrawCount; |
53 | } |
54 | ++fTotalCubicInstanceCount; |
55 | } |
56 | |
57 | int operator[](int resolveLevel) const { |
58 | SkASSERT(fHasCalledReset); |
59 | SkASSERT(resolveLevel > 0); // Empty cubics with 2^0=1 segments do not need to be drawn. |
60 | SkASSERT(resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel); |
61 | return fInstanceCounts[resolveLevel]; |
62 | } |
63 | int totalCubicInstanceCount() const { return fTotalCubicInstanceCount; } |
64 | int totalCubicIndirectDrawCount() const { return fTotalCubicIndirectDrawCount; } |
65 | |
66 | private: |
67 | SkDEBUGCODE(bool fHasCalledReset = false;) |
68 | int fInstanceCounts[GrTessellationPathRenderer::kMaxResolveLevel + 1]; |
69 | int fTotalCubicInstanceCount = 0; |
70 | int fTotalCubicIndirectDrawCount = 0; |
71 | }; |
72 | |
73 | #endif |
74 | |