| /* |
| * Copyright 2021 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef skgpu_graphite_DrawOrder_DEFINED |
| #define skgpu_graphite_DrawOrder_DEFINED |
| |
| #include "include/core/SkTypes.h" |
| |
| namespace skgpu::graphite { |
| |
| // Helper to encapsulate an unsigned number and enforce that it can only be used to create a |
| // monotonic sequence. The template argument 'Sequence' is used to define different sequences |
| // enforced by the compiler. For simplicity, and current needs within Graphite, it's assumed the |
| // entire sequence can be indexed by uint16_t. |
| template<typename Sequence> |
| class MonotonicValue { |
| public: |
| static constexpr MonotonicValue First() { return 0; } |
| static constexpr MonotonicValue Last() { return 0xffff; } |
| |
| MonotonicValue() = default; |
| MonotonicValue(const MonotonicValue& o) = default; |
| |
| MonotonicValue& operator=(const MonotonicValue& o) = default; |
| |
| bool operator< (MonotonicValue o) const { return fIndex < o.fIndex; } |
| bool operator<=(MonotonicValue o) const { return fIndex <= o.fIndex; } |
| |
| bool operator> (MonotonicValue o) const { return fIndex > o.fIndex; } |
| bool operator>=(MonotonicValue o) const { return fIndex >= o.fIndex; } |
| |
| bool operator==(MonotonicValue o) const { return fIndex == o.fIndex; } |
| bool operator!=(MonotonicValue o) const { return fIndex != o.fIndex; } |
| |
| uint16_t bits() const { return fIndex; } |
| |
| // Get the next value in the sequence after this one |
| MonotonicValue next() const { return fIndex + 1; } |
| |
| private: |
| constexpr MonotonicValue(uint16_t index) : fIndex(index) {} |
| |
| uint16_t fIndex; |
| }; |
| |
| /** |
| * CompressedPaintersOrder is an ordinal number that allows draw commands to be re-ordered so long |
| * as when they are executed, the read/writes to the color|depth attachments respect the original |
| * painter's order. Logical draws with the same CompressedPaintersOrder can be assumed to be |
| * executed in any order, however that may have been determined (e.g. BoundsManager or relying on |
| * a depth test during rasterization). |
| */ |
| struct CompressedPaintersOrderSequence {}; |
| using CompressedPaintersOrder = MonotonicValue<CompressedPaintersOrderSequence>; |
| |
| /** |
| * Each DisjointStencilIndex specifies an implicit set of non-overlapping draws. Assuming that two |
| * draws have the same CompressedPaintersOrder and the same DisjointStencilIndex, their substeps |
| * for multi-pass rendering (stencil-then-cover, etc.) can be intermingled with each other and |
| * produce the same results as if each draw's substeps were executed in order before moving on to |
| * the next draw's. |
| * |
| * Ordering within a set can be entirely arbitrary (i.e. all stencil steps can go before all cover |
| * steps). Ordering between sets is also arbitrary since all draws share the same |
| * CompressedPaintersOrder, so long as one set is entirely drawn before the next. |
| * |
| * Two draws that have different CompressedPaintersOrders but the same DisjointStencilIndex are |
| * unrelated, they may or may not overlap. The painters order scopes the disjoint sets. |
| */ |
| struct DisjointStencilIndexSequence {}; |
| using DisjointStencilIndex = MonotonicValue<DisjointStencilIndexSequence>; |
| |
| /** |
| * Every draw has an associated depth value. The value is constant across the entire draw and is |
| * not related to any varying Z coordinate induced by a 4x4 transform. The painter's depth is stored |
| * in the depth attachment and the GREATER depth test is used to reject or accept pixels/samples |
| * relative to what has already been rendered into the depth attachment. This allows draws that do |
| * not depend on the previous color to be radically re-ordered relative to their original painter's |
| * order while producing correct results. |
| */ |
| struct PaintersDepthSequence {}; |
| using PaintersDepth = MonotonicValue<PaintersDepthSequence>; |
| |
| /** |
| * DrawOrder aggregates the three separate sequences that Graphite uses to re-order draws and their |
| * substeps as much as possible while preserving the painter's order semantics of the Skia API. |
| * |
| * To build the full DrawOrder for a draw, start with its assigned PaintersDepth (i.e. the original |
| * painter's order of the draw call). From there, the DrawOrder can be updated to reflect |
| * dependencies on previous draws, either from depth-only clip draws or because the draw is |
| * transparent and must blend with the previous color values. Lastly, once the |
| * CompressedPaintersOrder is finalized, the DrawOrder can be updated to reflect whether or not |
| * the draw will involve the stencil buffer--and if so, specify the disjoint stencil set it |
| * belongs to. |
| * |
| * The original and effective order that draws are executed in is defined by the PaintersDepth. |
| * However, the actual execution order is defined by first the CompressedPaintersOrder and then |
| * the DisjointStencilIndex. This means that draws with much higher depths can be executed earlier |
| * if painter's order compression allows for it. |
| */ |
| class DrawOrder { |
| public: |
| // The first PaintersDepth is reserved for clearing the depth attachment; any draw using this |
| // depth will always fail the depth test. |
| inline static constexpr PaintersDepth kClearDepth = PaintersDepth::First(); |
| // The first CompressedPaintersOrder is reserved to indicate there is no previous draw that |
| // must come before a draw. |
| inline static constexpr |
| CompressedPaintersOrder kNoIntersection = CompressedPaintersOrder::First(); |
| // The first DisjointStencilIndex is reserved to indicate an unassigned stencil set. |
| inline static constexpr DisjointStencilIndex kUnassigned = DisjointStencilIndex::First(); |
| |
| explicit DrawOrder(PaintersDepth originalOrder) |
| : fPaintOrder(kNoIntersection) |
| , fStencilIndex(kUnassigned) |
| , fDepth(originalOrder) {} |
| |
| DrawOrder(PaintersDepth originalOrder, CompressedPaintersOrder compressedOrder) |
| : fPaintOrder(compressedOrder) |
| , fStencilIndex(kUnassigned) |
| , fDepth(originalOrder) {} |
| |
| CompressedPaintersOrder paintOrder() const { return fPaintOrder; } |
| DisjointStencilIndex stencilIndex() const { return fStencilIndex; } |
| PaintersDepth depth() const { return fDepth; } |
| |
| float depthAsFloat() const { return fDepth.bits() / (float) PaintersDepth::Last().bits(); } |
| |
| DrawOrder& dependsOnPaintersOrder(CompressedPaintersOrder prevDraw) { |
| // A draw must be ordered after all previous draws that it depends on |
| CompressedPaintersOrder next = prevDraw.next(); |
| if (fPaintOrder < next) { |
| fPaintOrder = next; |
| } |
| return *this; |
| } |
| |
| DrawOrder& dependsOnStencil(DisjointStencilIndex disjointSet) { |
| // Stencil usage should only be set once |
| SkASSERT(fStencilIndex == kUnassigned); |
| fStencilIndex = disjointSet; |
| return *this; |
| } |
| |
| private: |
| CompressedPaintersOrder fPaintOrder; |
| DisjointStencilIndex fStencilIndex; |
| PaintersDepth fDepth; |
| }; |
| |
| } // namespace skgpu::graphite |
| |
| #endif // skgpu_graphite_DrawOrder_DEFINED |