/src/skia/src/gpu/graphite/DrawOrder.h
Line | Count | Source (jump to first uncovered line) |
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 skgpu_graphite_DrawOrder_DEFINED |
9 | | #define skgpu_graphite_DrawOrder_DEFINED |
10 | | |
11 | | #include "include/core/SkTypes.h" |
12 | | |
13 | | namespace skgpu::graphite { |
14 | | |
15 | | // Helper to encapsulate an unsigned number and enforce that it can only be used to create a |
16 | | // monotonic sequence. The template argument 'Sequence' is used to define different sequences |
17 | | // enforced by the compiler. For simplicity, and current needs within Graphite, it's assumed the |
18 | | // entire sequence can be indexed by uint16_t. |
19 | | template<typename Sequence> |
20 | | class MonotonicValue { |
21 | | public: |
22 | 0 | static constexpr MonotonicValue First() { return 0; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>::First() Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::First() Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::First() |
23 | 0 | static constexpr MonotonicValue Last() { return 0xffff; } |
24 | | |
25 | | MonotonicValue() = default; |
26 | | MonotonicValue(const MonotonicValue& o) = default; |
27 | | |
28 | | MonotonicValue& operator=(const MonotonicValue& o) = default; |
29 | | |
30 | 0 | bool operator< (MonotonicValue o) const { return fIndex < o.fIndex; } |
31 | | bool operator<=(MonotonicValue o) const { return fIndex <= o.fIndex; } |
32 | | |
33 | 0 | bool operator> (MonotonicValue o) const { return fIndex > o.fIndex; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::operator>(skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>) const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>::operator>(skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>) const |
34 | | bool operator>=(MonotonicValue o) const { return fIndex >= o.fIndex; } |
35 | | |
36 | 0 | bool operator==(MonotonicValue o) const { return fIndex == o.fIndex; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::operator==(skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>) const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::operator==(skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>) const |
37 | 0 | bool operator!=(MonotonicValue o) const { return fIndex != o.fIndex; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::operator!=(skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>) const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::operator!=(skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>) const |
38 | | |
39 | 0 | uint16_t bits() const { return fIndex; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>::bits() const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::bits() const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::bits() const |
40 | | |
41 | | // Get the next value in the sequence after this one |
42 | 0 | MonotonicValue next() const { return fIndex + 1; } Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::next() const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::next() const Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>::next() const |
43 | | |
44 | | private: |
45 | 0 | constexpr MonotonicValue(uint16_t index) : fIndex(index) {} Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::PaintersDepthSequence>::MonotonicValue(unsigned short) Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::CompressedPaintersOrderSequence>::MonotonicValue(unsigned short) Unexecuted instantiation: skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>::MonotonicValue(unsigned short) |
46 | | |
47 | | uint16_t fIndex; |
48 | | }; |
49 | | |
50 | | /** |
51 | | * CompressedPaintersOrder is an ordinal number that allows draw commands to be re-ordered so long |
52 | | * as when they are executed, the read/writes to the color|depth attachments respect the original |
53 | | * painter's order. Logical draws with the same CompressedPaintersOrder can be assumed to be |
54 | | * executed in any order, however that may have been determined (e.g. BoundsManager or relying on |
55 | | * a depth test during rasterization). |
56 | | */ |
57 | | struct CompressedPaintersOrderSequence {}; |
58 | | using CompressedPaintersOrder = MonotonicValue<CompressedPaintersOrderSequence>; |
59 | | |
60 | | /** |
61 | | * Each DisjointStencilIndex specifies an implicit set of non-overlapping draws. Assuming that two |
62 | | * draws have the same CompressedPaintersOrder and the same DisjointStencilIndex, their substeps |
63 | | * for multi-pass rendering (stencil-then-cover, etc.) can be intermingled with each other and |
64 | | * produce the same results as if each draw's substeps were executed in order before moving on to |
65 | | * the next draw's. |
66 | | * |
67 | | * Ordering within a set can be entirely arbitrary (i.e. all stencil steps can go before all cover |
68 | | * steps). Ordering between sets is also arbitrary since all draws share the same |
69 | | * CompressedPaintersOrder, so long as one set is entirely drawn before the next. |
70 | | * |
71 | | * Two draws that have different CompressedPaintersOrders but the same DisjointStencilIndex are |
72 | | * unrelated, they may or may not overlap. The painters order scopes the disjoint sets. |
73 | | */ |
74 | | struct DisjointStencilIndexSequence {}; |
75 | | using DisjointStencilIndex = MonotonicValue<DisjointStencilIndexSequence>; |
76 | | |
77 | | /** |
78 | | * Every draw has an associated depth value. The value is constant across the entire draw and is |
79 | | * not related to any varying Z coordinate induced by a 4x4 transform. The painter's depth is stored |
80 | | * in the depth attachment and the GREATER depth test is used to reject or accept pixels/samples |
81 | | * relative to what has already been rendered into the depth attachment. This allows draws that do |
82 | | * not depend on the previous color to be radically re-ordered relative to their original painter's |
83 | | * order while producing correct results. |
84 | | */ |
85 | | struct PaintersDepthSequence {}; |
86 | | using PaintersDepth = MonotonicValue<PaintersDepthSequence>; |
87 | | |
88 | | /** |
89 | | * DrawOrder aggregates the three separate sequences that Graphite uses to re-order draws and their |
90 | | * substeps as much as possible while preserving the painter's order semantics of the Skia API. |
91 | | * |
92 | | * To build the full DrawOrder for a draw, start with its assigned PaintersDepth (i.e. the original |
93 | | * painter's order of the draw call). From there, the DrawOrder can be updated to reflect |
94 | | * dependencies on previous draws, either from depth-only clip draws or because the draw is |
95 | | * transparent and must blend with the previous color values. Lastly, once the |
96 | | * CompressedPaintersOrder is finalized, the DrawOrder can be updated to reflect whether or not |
97 | | * the draw will involve the stencil buffer--and if so, specify the disjoint stencil set it |
98 | | * belongs to. |
99 | | * |
100 | | * The original and effective order that draws are executed in is defined by the PaintersDepth. |
101 | | * However, the actual execution order is defined by first the CompressedPaintersOrder and then |
102 | | * the DisjointStencilIndex. This means that draws with much higher depths can be executed earlier |
103 | | * if painter's order compression allows for it. |
104 | | */ |
105 | | class DrawOrder { |
106 | | public: |
107 | | // The first PaintersDepth is reserved for clearing the depth attachment; any draw using this |
108 | | // depth will always fail the depth test. |
109 | | inline static constexpr PaintersDepth kClearDepth = PaintersDepth::First(); |
110 | | // The first CompressedPaintersOrder is reserved to indicate there is no previous draw that |
111 | | // must come before a draw. |
112 | | inline static constexpr |
113 | | CompressedPaintersOrder kNoIntersection = CompressedPaintersOrder::First(); |
114 | | // The first DisjointStencilIndex is reserved to indicate an unassigned stencil set. |
115 | | inline static constexpr DisjointStencilIndex kUnassigned = DisjointStencilIndex::First(); |
116 | | |
117 | | explicit DrawOrder(PaintersDepth originalOrder) |
118 | | : fPaintOrder(kNoIntersection) |
119 | | , fStencilIndex(kUnassigned) |
120 | 0 | , fDepth(originalOrder) {} |
121 | | |
122 | | DrawOrder(PaintersDepth originalOrder, CompressedPaintersOrder compressedOrder) |
123 | | : fPaintOrder(compressedOrder) |
124 | | , fStencilIndex(kUnassigned) |
125 | 0 | , fDepth(originalOrder) {} |
126 | | |
127 | 0 | CompressedPaintersOrder paintOrder() const { return fPaintOrder; } |
128 | 0 | DisjointStencilIndex stencilIndex() const { return fStencilIndex; } |
129 | 0 | PaintersDepth depth() const { return fDepth; } |
130 | | |
131 | 0 | float depthAsFloat() const { return fDepth.bits() / (float) PaintersDepth::Last().bits(); } |
132 | | |
133 | 0 | DrawOrder& dependsOnPaintersOrder(CompressedPaintersOrder prevDraw) { |
134 | | // A draw must be ordered after all previous draws that it depends on |
135 | 0 | CompressedPaintersOrder next = prevDraw.next(); |
136 | 0 | if (fPaintOrder < next) { |
137 | 0 | fPaintOrder = next; |
138 | 0 | } |
139 | 0 | return *this; |
140 | 0 | } |
141 | | |
142 | 0 | DrawOrder& dependsOnStencil(DisjointStencilIndex disjointSet) { |
143 | | // Stencil usage should only be set once |
144 | 0 | SkASSERT(fStencilIndex == kUnassigned); |
145 | 0 | fStencilIndex = disjointSet; |
146 | 0 | return *this; |
147 | 0 | } Unexecuted instantiation: skgpu::graphite::DrawOrder::dependsOnStencil(skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>) Unexecuted instantiation: skgpu::graphite::DrawOrder::dependsOnStencil(skgpu::graphite::MonotonicValue<skgpu::graphite::DisjointStencilIndexSequence>) |
148 | | |
149 | | private: |
150 | | CompressedPaintersOrder fPaintOrder; |
151 | | DisjointStencilIndex fStencilIndex; |
152 | | PaintersDepth fDepth; |
153 | | }; |
154 | | |
155 | | } // namespace skgpu::graphite |
156 | | |
157 | | #endif // skgpu_graphite_DrawOrder_DEFINED |