Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2017 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 GrResourceAllocator_DEFINED
      9 #define GrResourceAllocator_DEFINED
     10 
     11 #include "GrGpuResourcePriv.h"
     12 #include "GrSurface.h"
     13 #include "GrSurfaceProxy.h"
     14 
     15 #include "SkArenaAlloc.h"
     16 #include "SkTDynamicHash.h"
     17 #include "SkTMultiMap.h"
     18 
     19 class GrResourceProvider;
     20 
     21 /*
     22  * The ResourceAllocator explicitly distributes GPU resources at flush time. It operates by
     23  * being given the usage intervals of the various proxies. It keeps these intervals in a singly
     24  * linked list sorted by increasing start index. (It also maintains a hash table from proxyID
     25  * to interval to find proxy reuse). When it comes time to allocate the resources it
     26  * traverses the sorted list and:
     27  *     removes intervals from the active list that have completed (returning their GrSurfaces
     28  *     to the free pool)
     29 
     30  *     allocates a new resource (preferably from the free pool) for the new interval
     31  *     adds the new interval to the active list (that is sorted by increasing end index)
     32  *
     33  * Note: the op indices (used in the usage intervals) come from the order of the ops in
     34  * their opLists after the opList DAG has been linearized.
     35  */
     36 class GrResourceAllocator {
     37 public:
     38     GrResourceAllocator(GrResourceProvider* resourceProvider)
     39             : fResourceProvider(resourceProvider) {
     40     }
     41 
     42     ~GrResourceAllocator();
     43 
     44     unsigned int curOp() const { return fNumOps; }
     45     void incOps() { fNumOps++; }
     46     unsigned int numOps() const { return fNumOps; }
     47 
     48     // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets.
     49     // If an existing interval already exists it will be expanded to include the new range.
     50     void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end
     51                      SkDEBUGCODE(, bool isDirectDstRead = false));
     52 
     53     // Add an interval that spans just the current op. Usually this is for texture uses.
     54     // If an existing interval already exists it will be expanded to include the new operation.
     55     void addInterval(GrSurfaceProxy* proxy
     56                      SkDEBUGCODE(, bool isDirectDstRead = false)) {
     57         this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
     58     }
     59 
     60     enum class AssignError {
     61         kNoError,
     62         kFailedProxyInstantiation
     63     };
     64 
     65     // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
     66     // false when nothing remains to be executed.
     67     // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation.
     68     // If this happens, the caller should remove all ops which reference an uninstantiated proxy.
     69     // This is used to execute a portion of the queued opLists in order to reduce the total
     70     // amount of GPU resources required.
     71     bool assign(int* startIndex, int* stopIndex, AssignError* outError);
     72 
     73     void markEndOfOpList(int opListIndex);
     74 
     75 private:
     76     class Interval;
     77 
     78     // Remove dead intervals from the active list
     79     void expire(unsigned int curIndex);
     80 
     81     // These two methods wrap the interactions with the free pool
     82     void freeUpSurface(sk_sp<GrSurface> surface);
     83     sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
     84 
     85     struct FreePoolTraits {
     86         static const GrScratchKey& GetKey(const GrSurface& s) {
     87             return s.resourcePriv().getScratchKey();
     88         }
     89 
     90         static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
     91         static void OnFree(GrSurface* s) { s->unref(); }
     92     };
     93     typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
     94 
     95     typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
     96 
     97     class Interval {
     98     public:
     99         Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
    100             : fProxy(proxy)
    101             , fProxyID(proxy->uniqueID().asUInt())
    102             , fStart(start)
    103             , fEnd(end)
    104             , fNext(nullptr) {
    105             SkASSERT(proxy);
    106         }
    107 
    108         void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
    109             SkASSERT(proxy);
    110 
    111             fProxy = proxy;
    112             fProxyID = proxy->uniqueID().asUInt();
    113             fStart = start;
    114             fEnd = end;
    115             fNext = nullptr;
    116         }
    117 
    118         ~Interval() {
    119             SkASSERT(!fAssignedSurface);
    120         }
    121 
    122         const GrSurfaceProxy* proxy() const { return fProxy; }
    123         GrSurfaceProxy* proxy() { return fProxy; }
    124         unsigned int start() const { return fStart; }
    125         unsigned int end() const { return fEnd; }
    126         const Interval* next() const { return fNext; }
    127         Interval* next() { return fNext; }
    128 
    129         void setNext(Interval* next) { fNext = next; }
    130 
    131         void extendEnd(unsigned int newEnd) {
    132             if (newEnd > fEnd) {
    133                 fEnd = newEnd;
    134             }
    135         }
    136 
    137         void assign(sk_sp<GrSurface>);
    138         bool wasAssignedSurface() const { return fAssignedSurface; }
    139         sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
    140 
    141         // for SkTDynamicHash
    142         static const uint32_t& GetKey(const Interval& intvl) {
    143             return intvl.fProxyID;
    144         }
    145         static uint32_t Hash(const uint32_t& key) { return key; }
    146 
    147     private:
    148         sk_sp<GrSurface> fAssignedSurface;
    149         GrSurfaceProxy*  fProxy;
    150         uint32_t         fProxyID; // This is here b.c. DynamicHash requires a ref to the key
    151         unsigned int     fStart;
    152         unsigned int     fEnd;
    153         Interval*        fNext;
    154     };
    155 
    156     class IntervalList {
    157     public:
    158         IntervalList() = default;
    159         ~IntervalList() {
    160             // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
    161             // Since the arena allocator will clean up for us we don't bother here.
    162         }
    163 
    164         bool empty() const { return !SkToBool(fHead); }
    165         const Interval* peekHead() const { return fHead; }
    166         Interval* popHead();
    167         void insertByIncreasingStart(Interval*);
    168         void insertByIncreasingEnd(Interval*);
    169 
    170     private:
    171         Interval* fHead = nullptr;
    172     };
    173 
    174     // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
    175     static const int kInitialArenaSize = 12 * sizeof(Interval);
    176 
    177     GrResourceProvider*    fResourceProvider;
    178     FreePoolMultiMap       fFreePool;          // Recently created/used GrSurfaces
    179     IntvlHash              fIntvlHash;         // All the intervals, hashed by proxyID
    180 
    181     IntervalList           fIntvlList;         // All the intervals sorted by increasing start
    182     IntervalList           fActiveIntvls;      // List of live intervals during assignment
    183                                                // (sorted by increasing end)
    184     unsigned int           fNumOps = 1;        // op # 0 is reserved for uploads at the start
    185                                                // of a flush
    186     SkTArray<unsigned int> fEndOfOpListOpIndices;
    187     int                    fCurOpListIndex = 0;
    188 
    189     SkDEBUGCODE(bool       fAssigned = false;)
    190 
    191     char                   fStorage[kInitialArenaSize];
    192     SkArenaAlloc           fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
    193     Interval*              fFreeIntervalList = nullptr;
    194 };
    195 
    196 #endif // GrResourceAllocator_DEFINED
    197