blob: 71905ac5ad7c3359549a81b0865a8761641a136b [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
bungemanbf521ff2016-02-17 13:13:44 -080011#include "../private/SkTArray.h"
bsalomon95740982014-09-04 13:12:37 -070012#include "SkRefCnt.h"
bsalomon95740982014-09-04 13:12:37 -070013
bsalomonf96ba022014-09-17 08:05:40 -070014class GrGpuResourceRef;
bsalomon95740982014-09-04 13:12:37 -070015
16/**
Brian Salomone57194f2017-01-09 15:30:02 -050017 * Note: We are converting GrProcessor from ref counting to a single owner model using move
18 * semantics. This class will be removed.
19 *
bsalomon42048002015-08-27 16:43:48 -070020 * 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.
bsalomon95740982014-09-04 13:12:37 -070025 *
bsalomon42048002015-08-27 16:43:48 -070026 * 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
Brian Salomon09d994e2016-12-21 11:14:46 -050033 * safe to recycle a resource even though we still have buffered GrOps that read or write to the
bsalomon42048002015-08-27 16:43:48 -070034 * the resource.
35 *
Brian Salomone57194f2017-01-09 15:30:02 -050036 * 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.
bsalomon95740982014-09-04 13:12:37 -070041 */
Brian Salomone57194f2017-01-09 15:30:02 -050042template<typename DERIVED> class GrProgramElement : public SkNoncopyable {
bsalomon95740982014-09-04 13:12:37 -070043public:
bsalomon95740982014-09-04 13:12:37 -070044 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 {
bsalomonae59b772014-11-19 08:23:49 -080052 this->validate();
bsalomon95740982014-09-04 13:12:37 -070053 // Once the ref cnt reaches zero it should never be ref'ed again.
54 SkASSERT(fRefCnt > 0);
bsalomon95740982014-09-04 13:12:37 -070055 ++fRefCnt;
bsalomonae59b772014-11-19 08:23:49 -080056 this->validate();
bsalomon95740982014-09-04 13:12:37 -070057 }
58
59 void unref() const {
60 this->validate();
61 --fRefCnt;
bsalomond0128772014-10-03 05:31:41 -070062 if (0 == fRefCnt) {
bsalomon42048002015-08-27 16:43:48 -070063 this->notifyRefCntIsZero();
bsalomond0128772014-10-03 05:31:41 -070064 if (0 == fPendingExecutions) {
halcanary385fe4d2015-08-26 13:07:48 -070065 delete this;
bsalomonae59b772014-11-19 08:23:49 -080066 return;
bsalomond0128772014-10-03 05:31:41 -070067 } else {
Brian Salomone57194f2017-01-09 15:30:02 -050068 static_cast<const DERIVED*>(this)->removeRefs();
bsalomond0128772014-10-03 05:31:41 -070069 }
bsalomon95740982014-09-04 13:12:37 -070070 }
bsalomonae59b772014-11-19 08:23:49 -080071 this->validate();
bsalomon95740982014-09-04 13:12:37 -070072 }
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
82protected:
Brian Salomon19ae1382017-01-09 10:14:34 -050083 GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
bsalomon95740982014-09-04 13:12:37 -070084
bsalomonae59b772014-11-19 08:23:49 -080085 void addPendingExecution() const {
86 this->validate();
87 SkASSERT(fRefCnt > 0);
88 if (0 == fPendingExecutions) {
Brian Salomone57194f2017-01-09 15:30:02 -050089 static_cast<const DERIVED*>(this)->addPendingIOs();
bsalomonae59b772014-11-19 08:23:49 -080090 }
91 ++fPendingExecutions;
92 this->validate();
93 }
bsalomon95740982014-09-04 13:12:37 -070094
bsalomonae59b772014-11-19 08:23:49 -080095 void completedExecution() const {
96 this->validate();
97 --fPendingExecutions;
98 if (0 == fPendingExecutions) {
99 if (0 == fRefCnt) {
halcanary385fe4d2015-08-26 13:07:48 -0700100 delete this;
bsalomonae59b772014-11-19 08:23:49 -0800101 return;
102 } else {
Brian Salomone57194f2017-01-09 15:30:02 -0500103 static_cast<const DERIVED*>(this)->pendingIOComplete();
bsalomonae59b772014-11-19 08:23:49 -0800104 }
105 }
106 this->validate();
107 }
bsalomon95740982014-09-04 13:12:37 -0700108
bsalomon42048002015-08-27 16:43:48 -0700109private:
110 /** This will be called when the ref cnt is zero. The object may or may not have pending
111 executions. */
112 virtual void notifyRefCntIsZero() const = 0;
113
bsalomon95740982014-09-04 13:12:37 -0700114 mutable int32_t fRefCnt;
115 // Count of deferred executions not yet issued to the 3D API.
116 mutable int32_t fPendingExecutions;
bsalomon95740982014-09-04 13:12:37 -0700117
bsalomonae59b772014-11-19 08:23:49 -0800118 // Only this class can access addPendingExecution() and completedExecution().
119 template <typename T> friend class GrPendingProgramElement;
bsalomon95740982014-09-04 13:12:37 -0700120
121 typedef SkNoncopyable INHERITED;
122};
123
124#endif