Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2014 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 GrProgramElement_DEFINED
      9 #define GrProgramElement_DEFINED
     10 
     11 #include "../private/SkTArray.h"
     12 #include "SkRefCnt.h"
     13 
     14 class GrGpuResourceRef;
     15 
     16 /**
     17  * Base class for GrProcessor. This exists to manage transitioning a GrProcessor from being owned by
     18  * a client to being scheduled for execution. While a GrProcessor is ref'ed by drawing code its
     19  * GrGpu resources must also be ref'ed to prevent incorrectly recycling them through the cache.
     20  * However, once the GrProcessor is baked into a GrPipeline and the drawing code has stopped ref'ing
     21  * it, it's internal resources can be recycled in some cases.
     22  *
     23  * We track this using two types of refs on GrProgramElement. A regular ref is owned by any client
     24  * that may continue to issue draws that use the GrProgramElement. The GrPipeline owns "pending
     25  * executions" instead of refs. A pending execution is cleared by ~GrPipeline().
     26  *
     27  * While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
     28  * into the state where it has pending executions AND no refs then it converts its ownership of
     29  * its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is
     30  * safe to recycle a resource even though we still have buffered GrBatches that read or write to the
     31  * the resource.
     32  *
     33  * To make this work all GrGpuResource objects owned by a GrProgramElement or derived classes
     34  * (either directly or indirectly) must be wrapped in a GrGpuResourceRef and registered with the
     35  * GrProgramElement using addGpuResource(). This allows the regular refs to be converted to pending
     36  * IO events when the program element is scheduled for deferred execution.
     37  *
     38  * Moreover, a GrProgramElement that in turn owns other GrProgramElements must convert its ownership
     39  * of its children to pending executions when its ref count reaches zero so that the GrGpuResources
     40  * owned by the children GrProgramElements are correctly converted from ownership by ref to
     41  * ownership by pending IO. Any GrProgramElement hierarchy is managed by subclasses which must
     42  * implement notifyRefCntIsZero() in order to convert refs of children to pending executions.
     43  */
     44 class GrProgramElement : public SkNoncopyable {
     45 public:
     46     virtual ~GrProgramElement() {
     47         // fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
     48         SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
     49         // Set to invalid values.
     50         SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
     51     }
     52 
     53     void ref() const {
     54         this->validate();
     55         // Once the ref cnt reaches zero it should never be ref'ed again.
     56         SkASSERT(fRefCnt > 0);
     57         ++fRefCnt;
     58         this->validate();
     59     }
     60 
     61     void unref() const {
     62         this->validate();
     63         --fRefCnt;
     64         if (0 == fRefCnt) {
     65             this->notifyRefCntIsZero();
     66             if (0 == fPendingExecutions) {
     67                 delete this;
     68                 return;
     69             } else {
     70                 this->removeRefs();
     71             }
     72         }
     73         this->validate();
     74     }
     75 
     76     /**
     77      * Gets an id that is unique for this GrProgramElement object. This will never return 0.
     78      */
     79     uint32_t getUniqueID() const { return fUniqueID; }
     80 
     81     void validate() const {
     82 #ifdef SK_DEBUG
     83         SkASSERT(fRefCnt >= 0);
     84         SkASSERT(fPendingExecutions >= 0);
     85         SkASSERT(fRefCnt + fPendingExecutions > 0);
     86 #endif
     87     }
     88 
     89 protected:
     90     GrProgramElement() : fRefCnt(1), fPendingExecutions(0), fUniqueID(CreateUniqueID()) {}
     91 
     92     /** Subclasses registers their resources using this function. It is assumed the GrProgramResouce
     93         is and will remain owned by the subclass and this function will retain a raw ptr. Once a
     94         GrGpuResourceRef is registered its setResource must not be called.
     95      */
     96     void addGpuResource(const GrGpuResourceRef* res) {
     97         fGpuResources.push_back(res);
     98     }
     99 
    100     void addPendingExecution() const {
    101         this->validate();
    102         SkASSERT(fRefCnt > 0);
    103         if (0 == fPendingExecutions) {
    104             this->addPendingIOs();
    105         }
    106         ++fPendingExecutions;
    107         this->validate();
    108     }
    109 
    110     void completedExecution() const {
    111         this->validate();
    112         --fPendingExecutions;
    113         if (0 == fPendingExecutions) {
    114             if (0 == fRefCnt) {
    115                 delete this;
    116                 return;
    117             } else {
    118                 this->pendingIOComplete();
    119             }
    120         }
    121         this->validate();
    122     }
    123 
    124 private:
    125     /** This will be called when the ref cnt is zero. The object may or may not have pending
    126         executions. */
    127     virtual void notifyRefCntIsZero() const = 0;
    128 
    129     static uint32_t CreateUniqueID();
    130 
    131     void removeRefs() const;
    132     void addPendingIOs() const;
    133     void pendingIOComplete() const;
    134 
    135     mutable int32_t fRefCnt;
    136     // Count of deferred executions not yet issued to the 3D API.
    137     mutable int32_t fPendingExecutions;
    138     uint32_t        fUniqueID;
    139 
    140     SkSTArray<4, const GrGpuResourceRef*, true> fGpuResources;
    141 
    142     // Only this class can access addPendingExecution() and completedExecution().
    143     template <typename T> friend class GrPendingProgramElement;
    144 
    145     typedef SkNoncopyable INHERITED;
    146 };
    147 
    148 #endif
    149