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  * Note: We are converting GrProcessor from ref counting to a single owner model using move
     18  * semantics. This class will be removed.
     19  *
     20  * Base class for GrProcessor. This exists to manage transitioning a GrProcessor from being owned by
     21  * a client to being scheduled for execution. While a GrProcessor is ref'ed by drawing code its
     22  * GrGpu resources must also be ref'ed to prevent incorrectly recycling them through the cache.
     23  * However, once the GrProcessor is baked into a GrPipeline and the drawing code has stopped ref'ing
     24  * it, it's internal resources can be recycled in some cases.
     25  *
     26  * We track this using two types of refs on GrProgramElement. A regular ref is owned by any client
     27  * that may continue to issue draws that use the GrProgramElement. The GrPipeline owns "pending
     28  * executions" instead of refs. A pending execution is cleared by ~GrPipeline().
     29  *
     30  * While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
     31  * into the state where it has pending executions AND no refs then it converts its ownership of
     32  * its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is
     33  * safe to recycle a resource even though we still have buffered GrOps that read or write to the
     34  * the resource.
     35  *
     36  * To make this work the subclass, GrProcessor, implements addPendingIOs and pendingIOComplete. The
     37  * former adds pending reads/writes as appropriate when the processor is recorded in a GrOpList. The
     38  * latter removes them after the op list executes the operation. These calls must propagate to any
     39  * children processors. Similarly, the subclass implements a removeRefs function in order to remove
     40  * refs from resources once the processor is only owned for pending execution.
     41  */
     42 template<typename DERIVED> class GrProgramElement : public SkNoncopyable {
     43 public:
     44     virtual ~GrProgramElement() {
     45         // fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
     46         SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
     47         // Set to invalid values.
     48         SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
     49     }
     50 
     51     void ref() const {
     52         this->validate();
     53         // Once the ref cnt reaches zero it should never be ref'ed again.
     54         SkASSERT(fRefCnt > 0);
     55         ++fRefCnt;
     56         this->validate();
     57     }
     58 
     59     void unref() const {
     60         this->validate();
     61         --fRefCnt;
     62         if (0 == fRefCnt) {
     63             this->notifyRefCntIsZero();
     64             if (0 == fPendingExecutions) {
     65                 delete this;
     66                 return;
     67             } else {
     68                 static_cast<const DERIVED*>(this)->removeRefs();
     69             }
     70         }
     71         this->validate();
     72     }
     73 
     74     void validate() const {
     75 #ifdef SK_DEBUG
     76         SkASSERT(fRefCnt >= 0);
     77         SkASSERT(fPendingExecutions >= 0);
     78         SkASSERT(fRefCnt + fPendingExecutions > 0);
     79 #endif
     80     }
     81 
     82 protected:
     83     GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
     84 
     85     void addPendingExecution() const {
     86         this->validate();
     87         if (0 == fPendingExecutions) {
     88             static_cast<const DERIVED*>(this)->addPendingIOs();
     89         }
     90         ++fPendingExecutions;
     91         this->validate();
     92     }
     93 
     94     void completedExecution() const {
     95         this->validate();
     96         --fPendingExecutions;
     97         if (0 == fPendingExecutions) {
     98             if (0 == fRefCnt) {
     99                 delete this;
    100                 return;
    101             } else {
    102                 static_cast<const DERIVED*>(this)->pendingIOComplete();
    103             }
    104         }
    105         this->validate();
    106     }
    107 
    108 private:
    109     /** This will be called when the ref cnt is zero. The object may or may not have pending
    110         executions. */
    111     virtual void notifyRefCntIsZero() const = 0;
    112 
    113     mutable int32_t fRefCnt;
    114     // Count of deferred executions not yet issued to the 3D API.
    115     mutable int32_t fPendingExecutions;
    116 
    117     // Only this class can access addPendingExecution() and completedExecution().
    118     template <typename T> friend class GrPendingProgramElement;
    119     friend class GrProcessorSet;
    120 
    121     typedef SkNoncopyable INHERITED;
    122 };
    123 
    124 #endif
    125