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