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