1 /*
2  * Copyright 2016 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 #include "GrOpList.h"
9 
10 #include "GrContext.h"
11 #include "GrDeferredProxyUploader.h"
12 #include "GrMemoryPool.h"
13 #include "GrRenderTargetPriv.h"
14 #include "GrSurfaceProxy.h"
15 #include "GrTextureProxyPriv.h"
16 #include <atomic>
17 
18 uint32_t GrOpList::CreateUniqueID() {
19     static std::atomic<uint32_t> nextID{1};
20     uint32_t id;
21     do {
22         id = nextID++;
23     } while (id == SK_InvalidUniqueID);
24     return id;
25 }
26 
27 GrOpList::GrOpList(GrResourceProvider* resourceProvider, sk_sp<GrOpMemoryPool> opMemoryPool,
28                    GrSurfaceProxy* surfaceProxy, GrAuditTrail* auditTrail)
29         : fOpMemoryPool(std::move(opMemoryPool))
30         , fAuditTrail(auditTrail)
31         , fUniqueID(CreateUniqueID())
32         , fFlags(0) {
33     SkASSERT(fOpMemoryPool);
34     fTarget.setProxy(sk_ref_sp(surfaceProxy), kWrite_GrIOType);
35     fTarget.get()->setLastOpList(this);
36 
37     if (resourceProvider && !resourceProvider->explicitlyAllocateGPUResources()) {
38         // MDB TODO: remove this! We are currently moving to having all the ops that target
39         // the RT as a dest (e.g., clear, etc.) rely on the opList's 'fTarget' pointer
40         // for the IO Ref. This works well but until they are all swapped over (and none
41         // are pre-emptively instantiating proxies themselves) we need to instantiate
42         // here so that the GrSurfaces are created in an order that preserves the GrSurface
43         // re-use assumptions.
44         fTarget.get()->instantiate(resourceProvider);
45     }
46 
47     fTarget.markPendingIO();
48 }
49 
50 GrOpList::~GrOpList() {
51     if (fTarget.get() && this == fTarget.get()->getLastOpList()) {
52         // Ensure the target proxy doesn't keep hold of a dangling back pointer.
53         fTarget.get()->setLastOpList(nullptr);
54     }
55 }
56 
57 bool GrOpList::instantiate(GrResourceProvider* resourceProvider) {
58     return SkToBool(fTarget.get()->instantiate(resourceProvider));
59 }
60 
61 void GrOpList::endFlush() {
62     if (fTarget.get() && this == fTarget.get()->getLastOpList()) {
63         fTarget.get()->setLastOpList(nullptr);
64     }
65 
66     fTarget.reset();
67     fDeferredProxies.reset();
68     fAuditTrail = nullptr;
69 }
70 
71 void GrOpList::instantiateDeferredProxies(GrResourceProvider* resourceProvider) {
72     for (int i = 0; i < fDeferredProxies.count(); ++i) {
73         if (resourceProvider->explicitlyAllocateGPUResources()) {
74             SkASSERT(fDeferredProxies[i]->isInstantiated());
75         } else {
76             fDeferredProxies[i]->instantiate(resourceProvider);
77         }
78     }
79 }
80 
81 void GrOpList::prepare(GrOpFlushState* flushState) {
82     for (int i = 0; i < fDeferredProxies.count(); ++i) {
83         fDeferredProxies[i]->texPriv().scheduleUpload(flushState);
84     }
85 
86     this->onPrepare(flushState);
87 }
88 
89 // Add a GrOpList-based dependency
90 void GrOpList::addDependency(GrOpList* dependedOn) {
91     SkASSERT(!dependedOn->dependsOn(this));  // loops are bad
92 
93     if (this->dependsOn(dependedOn)) {
94         return;  // don't add duplicate dependencies
95     }
96 
97     fDependencies.push_back(dependedOn);
98     dependedOn->addDependent(this);
99 
100     SkDEBUGCODE(this->validate());
101 }
102 
103 // Convert from a GrSurface-based dependency to a GrOpList one
104 void GrOpList::addDependency(GrSurfaceProxy* dependedOn, const GrCaps& caps) {
105     if (dependedOn->getLastOpList()) {
106         // If it is still receiving dependencies, this GrOpList shouldn't be closed
107         SkASSERT(!this->isClosed());
108 
109         GrOpList* opList = dependedOn->getLastOpList();
110         if (opList == this) {
111             // self-read - presumably for dst reads. We can't make it closed in the self-read case.
112         } else {
113             this->addDependency(opList);
114 
115             // We are closing 'opList' here bc the current contents of it are what 'this' opList
116             // depends on. We need a break in 'opList' so that the usage of that state has a
117             // chance to execute.
118             opList->makeClosed(caps);
119         }
120     }
121 
122     if (GrTextureProxy* textureProxy = dependedOn->asTextureProxy()) {
123         if (textureProxy->texPriv().isDeferred()) {
124             fDeferredProxies.push_back(textureProxy);
125         }
126     }
127 }
128 
129 bool GrOpList::dependsOn(const GrOpList* dependedOn) const {
130     for (int i = 0; i < fDependencies.count(); ++i) {
131         if (fDependencies[i] == dependedOn) {
132             return true;
133         }
134     }
135 
136     return false;
137 }
138 
139 
140 void GrOpList::addDependent(GrOpList* dependent) {
141     fDependents.push_back(dependent);
142 }
143 
144 #ifdef SK_DEBUG
145 bool GrOpList::isDependedent(const GrOpList* dependent) const {
146     for (int i = 0; i < fDependents.count(); ++i) {
147         if (fDependents[i] == dependent) {
148             return true;
149         }
150     }
151 
152     return false;
153 }
154 
155 void GrOpList::validate() const {
156     // TODO: check for loops and duplicates
157 
158     for (int i = 0; i < fDependencies.count(); ++i) {
159         SkASSERT(fDependencies[i]->isDependedent(this));
160     }
161 }
162 #endif
163 
164 bool GrOpList::isInstantiated() const { return fTarget.get()->isInstantiated(); }
165 
166 void GrOpList::closeThoseWhoDependOnMe(const GrCaps& caps) {
167     for (int i = 0; i < fDependents.count(); ++i) {
168         if (!fDependents[i]->isClosed()) {
169             fDependents[i]->makeClosed(caps);
170         }
171     }
172 }
173 
174 bool GrOpList::isFullyInstantiated() const {
175     if (!this->isInstantiated()) {
176         return false;
177     }
178 
179     GrSurfaceProxy* proxy = fTarget.get();
180     bool needsStencil = proxy->asRenderTargetProxy()
181                                         ? proxy->asRenderTargetProxy()->needsStencil()
182                                         : false;
183 
184     if (needsStencil) {
185         GrRenderTarget* rt = proxy->peekRenderTarget();
186 
187         if (!rt->renderTargetPriv().getStencilAttachment()) {
188             return false;
189         }
190     }
191 
192     GrSurface* surface = proxy->peekSurface();
193     if (surface->wasDestroyed()) {
194         return false;
195     }
196 
197     return true;
198 }
199 
200 #ifdef SK_DEBUG
201 static const char* op_to_name(GrLoadOp op) {
202     return GrLoadOp::kLoad == op ? "load" : GrLoadOp::kClear == op ? "clear" : "discard";
203 }
204 
205 void GrOpList::dump(bool printDependencies) const {
206     SkDebugf("--------------------------------------------------------------\n");
207     SkDebugf("opListID: %d - proxyID: %d - surfaceID: %d\n", fUniqueID,
208              fTarget.get() ? fTarget.get()->uniqueID().asUInt() : -1,
209              fTarget.get() && fTarget.get()->peekSurface()
210                      ? fTarget.get()->peekSurface()->uniqueID().asUInt()
211                      : -1);
212     SkDebugf("ColorLoadOp: %s %x StencilLoadOp: %s\n",
213              op_to_name(fColorLoadOp),
214              GrLoadOp::kClear == fColorLoadOp ? fLoadClearColor.toBytes_RGBA() : 0x0,
215              op_to_name(fStencilLoadOp));
216 
217     if (printDependencies) {
218         SkDebugf("I rely On (%d): ", fDependencies.count());
219         for (int i = 0; i < fDependencies.count(); ++i) {
220             SkDebugf("%d, ", fDependencies[i]->fUniqueID);
221         }
222         SkDebugf("\n");
223 
224         SkDebugf("(%d) Rely On Me: ", fDependents.count());
225         for (int i = 0; i < fDependents.count(); ++i) {
226             SkDebugf("%d, ", fDependents[i]->fUniqueID);
227         }
228         SkDebugf("\n");
229     }
230 }
231 #endif
232