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