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