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 | |
15 | uint32_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 | |
24 | GrRenderTask::GrRenderTask() |
25 | : fUniqueID(CreateUniqueID()) |
26 | , fFlags(0) { |
27 | } |
28 | |
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 GrSurfaceProxyView& target : fTargets) { |
39 | if (this == drawingMgr->getLastRenderTask(target.proxy())) { |
40 | drawingMgr->setLastRenderTask(target.proxy(), nullptr); |
41 | } |
42 | } |
43 | } |
44 | |
45 | #ifdef SK_DEBUG |
46 | GrRenderTask::~GrRenderTask() { |
47 | SkASSERT(this->isSetFlag(kDisowned_Flag)); |
48 | } |
49 | |
50 | bool 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 | |
61 | void 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 | |
89 | void 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 |
98 | void 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 | |
108 | void 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 |
120 | void 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 | |
216 | bool 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 | |
227 | void GrRenderTask::addDependent(GrRenderTask* dependent) { |
228 | fDependents.push_back(dependent); |
229 | } |
230 | |
231 | #ifdef SK_DEBUG |
232 | bool 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 | |
242 | void 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 | |
251 | void 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 | |
259 | bool 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 | |
278 | void 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 |
288 | void 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 | |