| /* | |
| * 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: | |
| friend class DrawOrder; // For depth/stencil co-opting | |
| 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; } | |
| // While the PaintersDepth is a monotonically increasing value, the depth buffer prefers to | |
| // use LESS and LEQUAL comparisons starting with a clear value of 1.f, so we normalize and flip | |
| // the floating point value to count down from 1.0. | |
| float depthAsFloat() const { | |
| return 1.f - fDepth.bits() / (float) PaintersDepth::Last().bits(); | |
| } | |
| // Coopt the stencil index to encode the draw's actual painter's depth in decreasing order, | |
| // for use enforcing F2B order (since the compressed painter's order handles B2F). | |
| DrawOrder& reverseDepthAsStencil() { | |
| SkASSERT(fStencilIndex == kUnassigned); // can't have a real stencil index | |
| fStencilIndex = DisjointStencilIndex::Last().bits() - fDepth.bits(); | |
| return *this; | |
| } | |
| 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 |