blob: 8305c5027b0f17a3decb86049169b896583ba8fe [file] [log] [blame]
bsalomon95740982014-09-04 13:12:37 -07001/*
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 "SkRefCnt.h"
12#include "SkTArray.h"
13
bsalomonf96ba022014-09-17 08:05:40 -070014class GrGpuResourceRef;
bsalomon95740982014-09-04 13:12:37 -070015
16/**
bsalomon42048002015-08-27 16:43:48 -070017 * 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.
bsalomon95740982014-09-04 13:12:37 -070022 *
bsalomon42048002015-08-27 16:43:48 -070023 * 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.
bsalomon95740982014-09-04 13:12:37 -070043 */
44class GrProgramElement : public SkNoncopyable {
45public:
bsalomon95740982014-09-04 13:12:37 -070046 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 {
bsalomonae59b772014-11-19 08:23:49 -080054 this->validate();
bsalomon95740982014-09-04 13:12:37 -070055 // Once the ref cnt reaches zero it should never be ref'ed again.
56 SkASSERT(fRefCnt > 0);
bsalomon95740982014-09-04 13:12:37 -070057 ++fRefCnt;
bsalomonae59b772014-11-19 08:23:49 -080058 this->validate();
bsalomon95740982014-09-04 13:12:37 -070059 }
60
61 void unref() const {
62 this->validate();
63 --fRefCnt;
bsalomond0128772014-10-03 05:31:41 -070064 if (0 == fRefCnt) {
bsalomon42048002015-08-27 16:43:48 -070065 this->notifyRefCntIsZero();
bsalomond0128772014-10-03 05:31:41 -070066 if (0 == fPendingExecutions) {
halcanary385fe4d2015-08-26 13:07:48 -070067 delete this;
bsalomonae59b772014-11-19 08:23:49 -080068 return;
bsalomond0128772014-10-03 05:31:41 -070069 } else {
70 this->removeRefs();
71 }
bsalomon95740982014-09-04 13:12:37 -070072 }
bsalomonae59b772014-11-19 08:23:49 -080073 this->validate();
bsalomon95740982014-09-04 13:12:37 -070074 }
75
bsalomon52e9d632014-09-05 12:23:12 -070076 /**
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
bsalomon95740982014-09-04 13:12:37 -070081 void validate() const {
82#ifdef SK_DEBUG
83 SkASSERT(fRefCnt >= 0);
84 SkASSERT(fPendingExecutions >= 0);
85 SkASSERT(fRefCnt + fPendingExecutions > 0);
86#endif
87 }
88
89protected:
bsalomon52e9d632014-09-05 12:23:12 -070090 GrProgramElement() : fRefCnt(1), fPendingExecutions(0), fUniqueID(CreateUniqueID()) {}
bsalomon95740982014-09-04 13:12:37 -070091
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
bsalomonf96ba022014-09-17 08:05:40 -070094 GrGpuResourceRef is registered its setResource must not be called.
bsalomon95740982014-09-04 13:12:37 -070095 */
bsalomonf96ba022014-09-17 08:05:40 -070096 void addGpuResource(const GrGpuResourceRef* res) {
97 fGpuResources.push_back(res);
bsalomon95740982014-09-04 13:12:37 -070098 }
99
bsalomonae59b772014-11-19 08:23:49 -0800100 void addPendingExecution() const {
101 this->validate();
102 SkASSERT(fRefCnt > 0);
103 if (0 == fPendingExecutions) {
104 this->addPendingIOs();
105 }
106 ++fPendingExecutions;
107 this->validate();
108 }
bsalomon95740982014-09-04 13:12:37 -0700109
bsalomonae59b772014-11-19 08:23:49 -0800110 void completedExecution() const {
111 this->validate();
112 --fPendingExecutions;
113 if (0 == fPendingExecutions) {
114 if (0 == fRefCnt) {
halcanary385fe4d2015-08-26 13:07:48 -0700115 delete this;
bsalomonae59b772014-11-19 08:23:49 -0800116 return;
117 } else {
118 this->pendingIOComplete();
119 }
120 }
121 this->validate();
122 }
bsalomon95740982014-09-04 13:12:37 -0700123
bsalomon42048002015-08-27 16:43:48 -0700124private:
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
bsalomond0128772014-10-03 05:31:41 -0700131 void removeRefs() const;
bsalomonae59b772014-11-19 08:23:49 -0800132 void addPendingIOs() const;
133 void pendingIOComplete() const;
bsalomond0128772014-10-03 05:31:41 -0700134
bsalomon95740982014-09-04 13:12:37 -0700135 mutable int32_t fRefCnt;
136 // Count of deferred executions not yet issued to the 3D API.
137 mutable int32_t fPendingExecutions;
bsalomon52e9d632014-09-05 12:23:12 -0700138 uint32_t fUniqueID;
bsalomon95740982014-09-04 13:12:37 -0700139
bsalomonf96ba022014-09-17 08:05:40 -0700140 SkSTArray<4, const GrGpuResourceRef*, true> fGpuResources;
bsalomon95740982014-09-04 13:12:37 -0700141
bsalomonae59b772014-11-19 08:23:49 -0800142 // Only this class can access addPendingExecution() and completedExecution().
143 template <typename T> friend class GrPendingProgramElement;
bsalomon95740982014-09-04 13:12:37 -0700144
145 typedef SkNoncopyable INHERITED;
146};
147
148#endif