1 /*
2  * Copyright 2019 Google LLC
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 "src/gpu/GrRenderTask.h"
9 
10 #include "src/gpu/GrAttachment.h"
11 #include "src/gpu/GrRenderTarget.h"
12 #include "src/gpu/GrTextureProxyPriv.h"
13 #include "src/gpu/GrTextureResolveRenderTask.h"
14 
CreateUniqueID()15 uint32_t GrRenderTask::CreateUniqueID() {
16     static std::atomic<uint32_t> nextID{1};
17     uint32_t id;
18     do {
19         id = nextID.fetch_add(1, std::memory_order_relaxed);
20     } while (id == SK_InvalidUniqueID);
21     return id;
22 }
23 
GrRenderTask()24 GrRenderTask::GrRenderTask()
25         : fUniqueID(CreateUniqueID())
26         , fFlags(0) {
27 }
28 
disown(GrDrawingManager * drawingMgr)29 void GrRenderTask::disown(GrDrawingManager* drawingMgr) {
30     SkASSERT(!fDrawingMgr || drawingMgr == fDrawingMgr);
31     SkASSERT(this->isClosed());
32     if (this->isSetFlag(kDisowned_Flag)) {
33         return;
34     }
35     SkDEBUGCODE(fDrawingMgr = nullptr);
36     this->setFlag(kDisowned_Flag);
37 
38     for (const sk_sp<GrSurfaceProxy>& target : fTargets) {
39         if (this == drawingMgr->getLastRenderTask(target.get())) {
40             drawingMgr->setLastRenderTask(target.get(), nullptr);
41         }
42     }
43 }
44 
makeSkippable()45 void GrRenderTask::makeSkippable() {
46     SkASSERT(this->isClosed());
47     if (!this->isSkippable()) {
48         this->setFlag(kSkippable_Flag);
49         this->onMakeSkippable();
50     }
51 }
52 
53 #ifdef SK_DEBUG
~GrRenderTask()54 GrRenderTask::~GrRenderTask() {
55     SkASSERT(this->isSetFlag(kDisowned_Flag));
56 }
57 
deferredProxiesAreInstantiated() const58 bool GrRenderTask::deferredProxiesAreInstantiated() const {
59     for (int i = 0; i < fDeferredProxies.count(); ++i) {
60         if (!fDeferredProxies[i]->isInstantiated()) {
61             return false;
62         }
63     }
64 
65     return true;
66 }
67 #endif
68 
makeClosed(const GrCaps & caps)69 void GrRenderTask::makeClosed(const GrCaps& caps) {
70     if (this->isClosed()) {
71         return;
72     }
73 
74     SkIRect targetUpdateBounds;
75     if (ExpectedOutcome::kTargetDirty == this->onMakeClosed(caps, &targetUpdateBounds)) {
76         GrSurfaceProxy* proxy = this->target(0);
77         if (proxy->requiresManualMSAAResolve()) {
78             SkASSERT(this->target(0)->asRenderTargetProxy());
79             this->target(0)->asRenderTargetProxy()->markMSAADirty(targetUpdateBounds);
80         }
81         GrTextureProxy* textureProxy = this->target(0)->asTextureProxy();
82         if (textureProxy && GrMipmapped::kYes == textureProxy->mipmapped()) {
83             textureProxy->markMipmapsDirty();
84         }
85     }
86 
87     if (fTextureResolveTask) {
88         this->addDependency(fTextureResolveTask);
89         fTextureResolveTask->makeClosed(caps);
90         fTextureResolveTask = nullptr;
91     }
92 
93     this->setFlag(kClosed_Flag);
94 }
95 
prepare(GrOpFlushState * flushState)96 void GrRenderTask::prepare(GrOpFlushState* flushState) {
97     for (int i = 0; i < fDeferredProxies.count(); ++i) {
98         fDeferredProxies[i]->texPriv().scheduleUpload(flushState);
99     }
100 
101     this->onPrepare(flushState);
102 }
103 
104 // Add a GrRenderTask-based dependency
addDependency(GrRenderTask * dependedOn)105 void GrRenderTask::addDependency(GrRenderTask* dependedOn) {
106     SkASSERT(!dependedOn->dependsOn(this));  // loops are bad
107     SkASSERT(!this->dependsOn(dependedOn));  // caller should weed out duplicates
108 
109     fDependencies.push_back(dependedOn);
110     dependedOn->addDependent(this);
111 
112     SkDEBUGCODE(this->validate());
113 }
114 
addDependenciesFromOtherTask(GrRenderTask * otherTask)115 void GrRenderTask::addDependenciesFromOtherTask(GrRenderTask* otherTask) {
116     SkASSERT(otherTask);
117     for (GrRenderTask* task : otherTask->fDependencies) {
118         // The task should not be adding a dependency to itself.
119         SkASSERT(task != this);
120         if (!this->dependsOn(task)) {
121             this->addDependency(task);
122         }
123     }
124 }
125 
126 // Convert from a GrSurface-based dependency to a GrRenderTask one
addDependency(GrDrawingManager * drawingMgr,GrSurfaceProxy * dependedOn,GrMipmapped mipMapped,GrTextureResolveManager textureResolveManager,const GrCaps & caps)127 void GrRenderTask::addDependency(GrDrawingManager* drawingMgr, GrSurfaceProxy* dependedOn,
128                                  GrMipmapped mipMapped,
129                                  GrTextureResolveManager textureResolveManager,
130                                  const GrCaps& caps) {
131     // If it is still receiving dependencies, this GrRenderTask shouldn't be closed
132     SkASSERT(!this->isClosed());
133 
134     GrRenderTask* dependedOnTask = drawingMgr->getLastRenderTask(dependedOn);
135 
136     if (dependedOnTask == this) {
137         // self-read - presumably for dst reads. We don't need to do anything in this case. The
138         // XferProcessor will detect what is happening and insert a texture barrier.
139         SkASSERT(GrMipmapped::kNo == mipMapped);
140         // We should never attempt a self-read on a surface that has a separate MSAA renderbuffer.
141         SkASSERT(!dependedOn->requiresManualMSAAResolve());
142         SkASSERT(!dependedOn->asTextureProxy() ||
143                  !dependedOn->asTextureProxy()->texPriv().isDeferred());
144         return;
145     }
146 
147     if (dependedOnTask) {
148         if (this->dependsOn(dependedOnTask) || fTextureResolveTask == dependedOnTask) {
149             return;  // don't add duplicate dependencies
150         }
151 
152         // We are closing 'dependedOnTask' here bc the current contents of it are what 'this'
153         // renderTask depends on. We need a break in 'dependedOnTask' so that the usage of
154         // that state has a chance to execute.
155         dependedOnTask->makeClosed(caps);
156     }
157 
158     auto resolveFlags = GrSurfaceProxy::ResolveFlags::kNone;
159 
160     if (dependedOn->requiresManualMSAAResolve()) {
161         auto* renderTargetProxy = dependedOn->asRenderTargetProxy();
162         SkASSERT(renderTargetProxy);
163         if (renderTargetProxy->isMSAADirty()) {
164             resolveFlags |= GrSurfaceProxy::ResolveFlags::kMSAA;
165         }
166     }
167 
168     GrTextureProxy* textureProxy = dependedOn->asTextureProxy();
169     if (GrMipmapped::kYes == mipMapped) {
170         SkASSERT(textureProxy);
171         if (GrMipmapped::kYes != textureProxy->mipmapped()) {
172             // There are some cases where we might be given a non-mipmapped texture with a mipmap
173             // filter. See skbug.com/7094.
174             mipMapped = GrMipmapped::kNo;
175         } else if (textureProxy->mipmapsAreDirty()) {
176             resolveFlags |= GrSurfaceProxy::ResolveFlags::kMipMaps;
177         }
178     }
179 
180     // Does this proxy have msaa to resolve and/or mipmaps to regenerate?
181     if (GrSurfaceProxy::ResolveFlags::kNone != resolveFlags) {
182         if (!fTextureResolveTask) {
183             fTextureResolveTask = textureResolveManager.newTextureResolveRenderTask(caps);
184         }
185         fTextureResolveTask->addProxy(drawingMgr, sk_ref_sp(dependedOn), resolveFlags, caps);
186 
187         // addProxy() should have closed the texture proxy's previous task.
188         SkASSERT(!dependedOnTask || dependedOnTask->isClosed());
189         SkASSERT(drawingMgr->getLastRenderTask(dependedOn) == fTextureResolveTask);
190 
191 #ifdef SK_DEBUG
192         // addProxy() should have called addDependency (in this instance, recursively) on
193         // fTextureResolveTask.
194         if (dependedOnTask) {
195             SkASSERT(fTextureResolveTask->dependsOn(dependedOnTask));
196         }
197         if (textureProxy && textureProxy->texPriv().isDeferred()) {
198             SkASSERT(fTextureResolveTask->fDeferredProxies.back() == textureProxy);
199         }
200 
201         // The GrTextureResolveRenderTask factory should have also marked the proxy clean, set the
202         // last renderTask on the textureProxy to textureResolveTask, and closed textureResolveTask.
203         if (GrRenderTargetProxy* renderTargetProxy = dependedOn->asRenderTargetProxy()) {
204             SkASSERT(!renderTargetProxy->isMSAADirty());
205         }
206         if (textureProxy) {
207             SkASSERT(!textureProxy->mipmapsAreDirty());
208         }
209         SkASSERT(drawingMgr->getLastRenderTask(dependedOn) == fTextureResolveTask);
210 #endif
211         return;
212     }
213 
214     if (textureProxy && textureProxy->texPriv().isDeferred()) {
215         fDeferredProxies.push_back(textureProxy);
216     }
217 
218     if (dependedOnTask) {
219         this->addDependency(dependedOnTask);
220     }
221 }
222 
replaceDependency(const GrRenderTask * toReplace,GrRenderTask * replaceWith)223 void GrRenderTask::replaceDependency(const GrRenderTask* toReplace, GrRenderTask* replaceWith) {
224     for (auto& target : fDependencies) {
225         if (target == toReplace) {
226             target = replaceWith;
227             replaceWith->fDependents.push_back(this);
228             break;
229         }
230     }
231 }
232 
replaceDependent(const GrRenderTask * toReplace,GrRenderTask * replaceWith)233 void GrRenderTask::replaceDependent(const GrRenderTask* toReplace, GrRenderTask* replaceWith) {
234     for (auto& target : fDependents) {
235         if (target == toReplace) {
236             target = replaceWith;
237             replaceWith->fDependencies.push_back(this);
238             break;
239         }
240     }
241 }
242 
dependsOn(const GrRenderTask * dependedOn) const243 bool GrRenderTask::dependsOn(const GrRenderTask* dependedOn) const {
244     for (int i = 0; i < fDependencies.count(); ++i) {
245         if (fDependencies[i] == dependedOn) {
246             return true;
247         }
248     }
249 
250     return false;
251 }
252 
253 
addDependent(GrRenderTask * dependent)254 void GrRenderTask::addDependent(GrRenderTask* dependent) {
255     fDependents.push_back(dependent);
256 }
257 
258 #ifdef SK_DEBUG
isDependent(const GrRenderTask * dependent) const259 bool GrRenderTask::isDependent(const GrRenderTask* dependent) const {
260     for (int i = 0; i < fDependents.count(); ++i) {
261         if (fDependents[i] == dependent) {
262             return true;
263         }
264     }
265 
266     return false;
267 }
268 
validate() const269 void GrRenderTask::validate() const {
270     // TODO: check for loops and duplicates
271 
272     for (int i = 0; i < fDependencies.count(); ++i) {
273         SkASSERT(fDependencies[i]->isDependent(this));
274     }
275 }
276 #endif
277 
closeThoseWhoDependOnMe(const GrCaps & caps)278 void GrRenderTask::closeThoseWhoDependOnMe(const GrCaps& caps) {
279     for (int i = 0; i < fDependents.count(); ++i) {
280         if (!fDependents[i]->isClosed()) {
281             fDependents[i]->makeClosed(caps);
282         }
283     }
284 }
285 
isInstantiated() const286 bool GrRenderTask::isInstantiated() const {
287     for (const sk_sp<GrSurfaceProxy>& target : fTargets) {
288         GrSurfaceProxy* proxy = target.get();
289         if (!proxy->isInstantiated()) {
290             return false;
291         }
292 
293         GrSurface* surface = proxy->peekSurface();
294         if (surface->wasDestroyed()) {
295             return false;
296         }
297     }
298 
299     return true;
300 }
301 
addTarget(GrDrawingManager * drawingMgr,sk_sp<GrSurfaceProxy> proxy)302 void GrRenderTask::addTarget(GrDrawingManager* drawingMgr, sk_sp<GrSurfaceProxy> proxy) {
303     SkASSERT(proxy);
304     SkASSERT(!this->isClosed());
305     SkASSERT(!fDrawingMgr || drawingMgr == fDrawingMgr);
306     SkDEBUGCODE(fDrawingMgr = drawingMgr);
307     drawingMgr->setLastRenderTask(proxy.get(), this);
308     proxy->isUsedAsTaskTarget();
309     fTargets.emplace_back(std::move(proxy));
310 }
311 
312 #if GR_TEST_UTILS
dump(const SkString & label,SkString indent,bool printDependencies,bool close) const313 void GrRenderTask::dump(const SkString& label,
314                         SkString indent,
315                         bool printDependencies,
316                         bool close) const {
317     SkDebugf("%s%s --------------------------------------------------------------\n",
318              indent.c_str(),
319              label.c_str());
320     SkDebugf("%s%s task - renderTaskID: %d\n", indent.c_str(), this->name(), fUniqueID);
321 
322     if (!fTargets.empty()) {
323         SkDebugf("%sTargets: \n", indent.c_str());
324         for (const sk_sp<GrSurfaceProxy>& target : fTargets) {
325             SkASSERT(target);
326             SkString proxyStr = target->dump();
327             SkDebugf("%s%s\n", indent.c_str(), proxyStr.c_str());
328         }
329     }
330 
331     if (printDependencies) {
332         SkDebugf("%sI rely On (%d): ", indent.c_str(), fDependencies.count());
333         for (int i = 0; i < fDependencies.count(); ++i) {
334             SkDebugf("%d, ", fDependencies[i]->fUniqueID);
335         }
336         SkDebugf("\n");
337 
338         SkDebugf("%s(%d) Rely On Me: ", indent.c_str(), fDependents.count());
339         for (int i = 0; i < fDependents.count(); ++i) {
340             SkDebugf("%d, ", fDependents[i]->fUniqueID);
341         }
342         SkDebugf("\n");
343     }
344 
345     if (close) {
346         SkDebugf("%s--------------------------------------------------------------\n\n",
347                  indent.c_str());
348     }
349 }
350 #endif
351