Remove intermediary RenderTaskDAG class

This thing is a leaky abstraction ("rawRemove" fn) and it doesn't
actually do much encapsulation. Almost all the code is just views into
the underlying array and wrappers that could be replaced by

std::algorithm routines (and in this CL, are). It's more trouble than
it's worth – maybe in the past that wasn't so.
Change-Id: I81f3aa6874525f8f2ed1315f50e084030e34865e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332718
Commit-Queue: Adlai Holler <adlai@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 0b8f3ab..68b4690 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -44,100 +44,6 @@
 #include "src/gpu/text/GrSDFTOptions.h"
 #include "src/image/SkSurface_Gpu.h"
 
-void GrDrawingManager::RenderTaskDAG::gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const {
-    idArray->reset(fRenderTasks.count());
-    for (int i = 0; i < fRenderTasks.count(); ++i) {
-        if (fRenderTasks[i]) {
-            (*idArray)[i] = fRenderTasks[i]->uniqueID();
-        }
-    }
-}
-
-void GrDrawingManager::RenderTaskDAG::reset() {
-    fRenderTasks.reset();
-}
-
-void GrDrawingManager::RenderTaskDAG::rawRemoveRenderTasks(int startIndex, int stopIndex) {
-    for (int i = startIndex; i < stopIndex; ++i) {
-        fRenderTasks[i] = nullptr;
-    }
-}
-
-bool GrDrawingManager::RenderTaskDAG::isUsed(GrSurfaceProxy* proxy) const {
-    for (const auto& task : fRenderTasks) {
-        if (task && task->isUsed(proxy)) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-GrRenderTask* GrDrawingManager::RenderTaskDAG::add(sk_sp<GrRenderTask> renderTask) {
-    if (renderTask) {
-        return fRenderTasks.emplace_back(std::move(renderTask)).get();
-    }
-    return nullptr;
-}
-
-GrRenderTask* GrDrawingManager::RenderTaskDAG::addBeforeLast(sk_sp<GrRenderTask> renderTask) {
-    SkASSERT(!fRenderTasks.empty());
-    if (renderTask) {
-        // Release 'fRenderTasks.back()' and grab the raw pointer, in case the SkTArray grows
-        // and reallocates during emplace_back.
-        fRenderTasks.emplace_back(fRenderTasks.back().release());
-        return (fRenderTasks[fRenderTasks.count() - 2] = std::move(renderTask)).get();
-    }
-    return nullptr;
-}
-
-void GrDrawingManager::RenderTaskDAG::add(const SkTArray<sk_sp<GrRenderTask>>& renderTasks) {
-#ifdef SK_DEBUG
-    for (auto& renderTask : renderTasks) {
-        SkASSERT(renderTask->unique());
-    }
-#endif
-
-    fRenderTasks.push_back_n(renderTasks.count(), renderTasks.begin());
-}
-
-void GrDrawingManager::RenderTaskDAG::swap(SkTArray<sk_sp<GrRenderTask>>* renderTasks) {
-    SkASSERT(renderTasks->empty());
-    renderTasks->swap(fRenderTasks);
-}
-
-void GrDrawingManager::RenderTaskDAG::prepForFlush() {
-    if (!SkTTopoSort<GrRenderTask, GrRenderTask::TopoSortTraits>(&fRenderTasks)) {
-        SkDEBUGFAIL("Render task topo sort failed.");
-        return;
-    }
-
-#ifdef SK_DEBUG
-    // This block checks for any unnecessary splits in the opsTasks. If two sequential opsTasks
-    // share the same backing GrSurfaceProxy it means the opsTask was artificially split.
-    if (fRenderTasks.count()) {
-        GrOpsTask* prevOpsTask = fRenderTasks[0]->asOpsTask();
-        for (int i = 1; i < fRenderTasks.count(); ++i) {
-            GrOpsTask* curOpsTask = fRenderTasks[i]->asOpsTask();
-
-            if (prevOpsTask && curOpsTask) {
-                SkASSERT(prevOpsTask->target(0).proxy() != curOpsTask->target(0).proxy());
-            }
-
-            prevOpsTask = curOpsTask;
-        }
-    }
-#endif
-}
-
-void GrDrawingManager::RenderTaskDAG::closeAll(const GrCaps* caps) {
-    for (auto& task : fRenderTasks) {
-        if (task) {
-            task->makeClosed(*caps);
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 GrDrawingManager::GrDrawingManager(GrRecordingContext* context,
                                    const GrPathRendererChain::Options& optionsForPathRendererChain,
@@ -150,8 +56,8 @@
         , fReduceOpsTaskSplitting(reduceOpsTaskSplitting) { }
 
 GrDrawingManager::~GrDrawingManager() {
-    fDAG.closeAll(fContext->priv().caps());
-    this->removeRenderTasks(0, fDAG.numRenderTasks());
+    this->closeAllTasks();
+    this->removeRenderTasks(0, fDAG.count());
 }
 
 bool GrDrawingManager::wasAbandoned() const {
@@ -195,7 +101,10 @@
     if (!proxies.empty() && !info.fNumSemaphores && !info.fFinishedProc &&
         access == SkSurface::BackendSurfaceAccess::kNoAccess && !newState) {
         bool allUnused = std::all_of(proxies.begin(), proxies.end(), [&](GrSurfaceProxy* proxy) {
-            return !fDAG.isUsed(proxy) && !this->isDDLTarget(proxy);
+            bool used = std::any_of(fDAG.begin(), fDAG.end(), [&](auto& task) {
+                return task && task->isUsed(proxy);
+            });
+            return !used && !this->isDDLTarget(proxy);
         });
         if (allUnused) {
             if (info.fSubmittedProc) {
@@ -222,10 +131,10 @@
     // to flush mid-draw. In that case, the SkGpuDevice's opsTasks won't be closed but need to be
     // flushed anyway. Closing such opsTasks here will mean new ones will be created to replace them
     // if the SkGpuDevice(s) write to them again.
-    fDAG.closeAll(fContext->priv().caps());
+    this->closeAllTasks();
     fActiveOpsTask = nullptr;
 
-    fDAG.prepForFlush();
+    this->sortTasks();
     if (!fCpuBufferCache) {
         // We cache more buffers when the backend is using client side arrays. Otherwise, we
         // expect each pool will use a CPU buffer as a staging buffer before uploading to a GPU
@@ -240,7 +149,12 @@
 
     // Prepare any onFlush op lists (e.g. atlases).
     if (!fOnFlushCBObjects.empty()) {
-        fDAG.gatherIDs(&fFlushingRenderTaskIDs);
+        fFlushingRenderTaskIDs.reset(fDAG.count());
+        for (int i = 0; i < fDAG.count(); i++) {
+            if (fDAG[i]) {
+                fFlushingRenderTaskIDs[i] = fDAG[i]->uniqueID();
+            }
+        }
 
         for (GrOnFlushCallbackObject* onFlushCBObject : fOnFlushCBObjects) {
             onFlushCBObject->preFlush(&onFlushProvider, fFlushingRenderTaskIDs);
@@ -274,9 +188,9 @@
     for (const auto& onFlushRenderTask : fOnFlushRenderTasks) {
         SkDEBUGCODE(onFlushRenderTask->dump(/* printDependencies */ true);)
     }
-    SkDEBUGCODE(SkDebugf("Normal renderTasks (%d):\n", fDAG.numRenderTasks()));
-    for (int i = 0; i < fDAG.numRenderTasks(); ++i) {
-        SkDEBUGCODE(fDAG.renderTask(i)->dump(/* printDependencies */ true);)
+    SkDEBUGCODE(SkDebugf("Normal renderTasks (%d):\n", fDAG.count()));
+    for (const auto& task : fDAG) {
+        SkDEBUGCODE(task->dump(/* printDependencies */ true);)
     }
 #endif
 
@@ -284,10 +198,10 @@
     bool flushed = false;
 
     {
-        GrResourceAllocator alloc(resourceProvider SkDEBUGCODE(, fDAG.numRenderTasks()));
-        for (int i = 0; i < fDAG.numRenderTasks(); ++i) {
-            if (fDAG.renderTask(i)) {
-                fDAG.renderTask(i)->gatherProxyIntervals(&alloc);
+        GrResourceAllocator alloc(resourceProvider SkDEBUGCODE(, fDAG.count()));
+        for (int i = 0; i < fDAG.count(); ++i) {
+            if (fDAG[i]) {
+                fDAG[i]->gatherProxyIntervals(&alloc);
             }
             alloc.markEndOfOpsTask(i);
         }
@@ -298,7 +212,7 @@
         while (alloc.assign(&startIndex, &stopIndex, &error)) {
             if (GrResourceAllocator::AssignError::kFailedProxyInstantiation == error) {
                 for (int i = startIndex; i < stopIndex; ++i) {
-                    GrRenderTask* renderTask = fDAG.renderTask(i);
+                    GrRenderTask* renderTask = fDAG[i].get();
                     if (!renderTask) {
                         continue;
                     }
@@ -321,10 +235,10 @@
     }
 
 #ifdef SK_DEBUG
-    for (int i = 0; i < fDAG.numRenderTasks(); ++i) {
+    for (const auto& task : fDAG) {
         // All render tasks should have been cleared out by now – we only reset the array below to
         // reclaim storage.
-        SkASSERT(!fDAG.renderTask(i));
+        SkASSERT(!task);
     }
 #endif
     fLastRenderTasks.reset();
@@ -375,14 +289,14 @@
 
 bool GrDrawingManager::executeRenderTasks(int startIndex, int stopIndex, GrOpFlushState* flushState,
                                           int* numRenderTasksExecuted) {
-    SkASSERT(startIndex <= stopIndex && stopIndex <= fDAG.numRenderTasks());
+    SkASSERT(startIndex <= stopIndex && stopIndex <= fDAG.count());
 
 #if GR_FLUSH_TIME_OP_SPEW
     SkDebugf("Flushing opsTask: %d to %d out of [%d, %d]\n",
-                            startIndex, stopIndex, 0, fDAG.numRenderTasks());
+                            startIndex, stopIndex, 0, fDAG.count());
     for (int i = startIndex; i < stopIndex; ++i) {
-        if (fDAG.renderTask(i)) {
-            fDAG.renderTask(i)->dump(true);
+        if (fDAG[i]) {
+            fDAG[i]->dump(true);
         }
     }
 #endif
@@ -390,7 +304,7 @@
     bool anyRenderTasksExecuted = false;
 
     for (int i = startIndex; i < stopIndex; ++i) {
-        GrRenderTask* renderTask = fDAG.renderTask(i);
+        GrRenderTask* renderTask = fDAG[i].get();
         if (!renderTask || !renderTask->isInstantiated()) {
              continue;
         }
@@ -428,7 +342,7 @@
 
     // Execute the normal op lists.
     for (int i = startIndex; i < stopIndex; ++i) {
-        GrRenderTask* renderTask = fDAG.renderTask(i);
+        GrRenderTask* renderTask = fDAG[i].get();
         if (!renderTask || !renderTask->isInstantiated()) {
             continue;
         }
@@ -458,7 +372,7 @@
 
 void GrDrawingManager::removeRenderTasks(int startIndex, int stopIndex) {
     for (int i = startIndex; i < stopIndex; ++i) {
-        GrRenderTask* task = fDAG.renderTask(i);
+        GrRenderTask* task = fDAG[i].get();
         if (!task) {
             continue;
         }
@@ -467,8 +381,74 @@
             task->endFlush(this);
         }
         task->disown(this);
+
+        // This doesn't cleanup any referring pointers (e.g. dependency pointers in the DAG).
+        // It works right now bc this is only called after the topological sort is complete
+        // (so the dangling pointers aren't used).
+        fDAG[i] = nullptr;
     }
-    fDAG.rawRemoveRenderTasks(startIndex, stopIndex);
+}
+
+void GrDrawingManager::sortTasks() {
+    if (!SkTTopoSort<GrRenderTask, GrRenderTask::TopoSortTraits>(&fDAG)) {
+        SkDEBUGFAIL("Render task topo sort failed.");
+        return;
+    }
+
+#ifdef SK_DEBUG
+    // This block checks for any unnecessary splits in the opsTasks. If two sequential opsTasks
+    // share the same backing GrSurfaceProxy it means the opsTask was artificially split.
+    if (!fDAG.empty()) {
+        GrOpsTask* prevOpsTask = fDAG[0]->asOpsTask();
+        for (int i = 1; i < fDAG.count(); ++i) {
+            GrOpsTask* curOpsTask = fDAG[i]->asOpsTask();
+
+            if (prevOpsTask && curOpsTask) {
+                SkASSERT(prevOpsTask->target(0).proxy() != curOpsTask->target(0).proxy());
+            }
+
+            prevOpsTask = curOpsTask;
+        }
+    }
+#endif
+}
+
+void GrDrawingManager::closeAllTasks() {
+    const GrCaps& caps = *fContext->priv().caps();
+    for (auto& task : fDAG) {
+        if (task) {
+            task->makeClosed(caps);
+        }
+    }
+}
+
+GrRenderTask* GrDrawingManager::insertTaskBeforeLast(sk_sp<GrRenderTask> task) {
+    SkASSERT(!fDAG.empty());
+    if (!task) {
+        return nullptr;
+    }
+    // Release 'fDAG.back()' and grab the raw pointer, in case the SkTArray grows
+    // and reallocates during emplace_back.
+    // TODO: Either use std::vector that can do this for us, or use SkSTArray to get the
+    // perf win.
+    fDAG.emplace_back(fDAG.back().release());
+    return (fDAG[fDAG.count() - 2] = std::move(task)).get();
+}
+
+GrRenderTask* GrDrawingManager::appendTask(sk_sp<GrRenderTask> task) {
+    if (!task) {
+        return nullptr;
+    }
+    return fDAG.push_back(std::move(task)).get();
+}
+
+void GrDrawingManager::appendTasks(SkSpan<const sk_sp<GrRenderTask>> tasks) {
+#ifdef SK_DEBUG
+    for (const auto& task : tasks) {
+        SkASSERT(task && task->unique());
+    }
+#endif
+    fDAG.push_back_n(tasks.count(), tasks.begin());
 }
 
 static void resolve_and_mipmap(GrGpu* gpu, GrSurfaceProxy* proxy) {
@@ -582,11 +562,11 @@
     SkDEBUGCODE(this->validate());
 
     // no renderTask should receive a new command after this
-    fDAG.closeAll(fContext->priv().caps());
+    this->closeAllTasks();
     fActiveOpsTask = nullptr;
 
-    fDAG.swap(&ddl->fRenderTasks);
-    SkASSERT(!fDAG.numRenderTasks());
+    fDAG.swap(ddl->fRenderTasks);
+    SkASSERT(fDAG.empty());
 
     for (auto& renderTask : ddl->fRenderTasks) {
         renderTask->disown(this);
@@ -641,10 +621,10 @@
         ccpr->mergePendingPaths(ddl->fPendingPaths);
     }
 
-    fDAG.add(ddl->fRenderTasks);
+    this->appendTasks(ddl->fRenderTasks);
 
     // Add a task to unref the DDL after flush.
-    GrRenderTask* unrefTask = fDAG.add(sk_make_sp<GrUnrefDDLTask>(std::move(ddl)));
+    GrRenderTask* unrefTask = this->appendTask(sk_make_sp<GrUnrefDDLTask>(std::move(ddl)));
     unrefTask->makeClosed(*fContext->priv().caps());
 
     SkDEBUGCODE(this->validate());
@@ -658,21 +638,21 @@
         if (fActiveOpsTask) {
             SkASSERT(!fDAG.empty());
             SkASSERT(!fActiveOpsTask->isClosed());
-            SkASSERT(fActiveOpsTask == fDAG.back());
+            SkASSERT(fActiveOpsTask == fDAG.back().get());
         }
 
-        for (int i = 0; i < fDAG.numRenderTasks(); ++i) {
-            if (fActiveOpsTask != fDAG.renderTask(i)) {
+        for (int i = 0; i < fDAG.count(); ++i) {
+            if (fActiveOpsTask != fDAG[i].get()) {
                 // The resolveTask associated with the activeTask remains open for as long as the
                 // activeTask does.
                 bool isActiveResolveTask =
-                        fActiveOpsTask && fActiveOpsTask->fTextureResolveTask == fDAG.renderTask(i);
-                SkASSERT(isActiveResolveTask || fDAG.renderTask(i)->isClosed());
+                    fActiveOpsTask && fActiveOpsTask->fTextureResolveTask == fDAG[i].get();
+                SkASSERT(isActiveResolveTask || fDAG[i]->isClosed());
             }
         }
 
         if (!fDAG.empty() && !fDAG.back()->isClosed()) {
-            SkASSERT(fActiveOpsTask == fDAG.back());
+            SkASSERT(fActiveOpsTask == fDAG.back().get());
         }
     }
 }
@@ -712,7 +692,7 @@
     SkASSERT(this->getLastRenderTask(proxy) == opsTask.get());
 
     if (managedOpsTask) {
-        fDAG.add(opsTask);
+        this->appendTask(opsTask);
 
         if (!fReduceOpsTaskSplitting) {
             fActiveOpsTask = opsTask.get();
@@ -733,8 +713,8 @@
     // Add the new textureResolveTask before the fActiveOpsTask (if not in
     // sorting/opsTask-splitting-reduction mode) because it will depend upon this resolve task.
     // NOTE: Putting it here will also reduce the amount of work required by the topological sort.
-    return static_cast<GrTextureResolveRenderTask*>(fDAG.addBeforeLast(
-            sk_make_sp<GrTextureResolveRenderTask>()));
+    GrRenderTask* task = this->insertTaskBeforeLast(sk_make_sp<GrTextureResolveRenderTask>());
+    return static_cast<GrTextureResolveRenderTask*>(task);
 }
 
 void GrDrawingManager::newWaitRenderTask(sk_sp<GrSurfaceProxy> proxy,
@@ -775,11 +755,11 @@
             }
             this->setLastRenderTask(proxy.get(), waitTask.get());
         }
-        fDAG.add(waitTask);
+        this->appendTask(waitTask);
     } else {
         if (fActiveOpsTask && (fActiveOpsTask->target(0).proxy() == proxy.get())) {
             SkASSERT(this->getLastRenderTask(proxy.get()) == fActiveOpsTask);
-            fDAG.addBeforeLast(waitTask);
+            this->insertTaskBeforeLast(waitTask);
             // In this case we keep the current renderTask open but just insert the new waitTask
             // before it in the list. The waitTask will never need to trigger any resolves or mip
             // map generation which is the main advantage of going through the proxy version.
@@ -805,7 +785,7 @@
             }
             this->setLastRenderTask(proxy.get(), waitTask.get());
             this->closeRenderTasksForNewRenderTask(proxy.get());
-            fDAG.add(waitTask);
+            this->appendTask(waitTask);
         }
     }
     waitTask->makeClosed(caps);
@@ -824,7 +804,7 @@
     // This copies from srcProxy to dstBuffer so it doesn't have a real target.
     this->closeRenderTasksForNewRenderTask(nullptr);
 
-    GrRenderTask* task = fDAG.add(sk_make_sp<GrTransferFromRenderTask>(
+    GrRenderTask* task = this->appendTask(sk_make_sp<GrTransferFromRenderTask>(
             srcProxy, srcRect, surfaceColorType, dstColorType,
             std::move(dstBuffer), dstOffset));
 
@@ -855,8 +835,8 @@
     GrSurfaceProxy* srcProxy = srcView.proxy();
 
     GrRenderTask* task =
-            fDAG.add(GrCopyRenderTask::Make(this, std::move(srcView), srcRect, std::move(dstView),
-                                            dstPoint, &caps));
+            this->appendTask(GrCopyRenderTask::Make(this, std::move(srcView), srcRect,
+                                                    std::move(dstView), dstPoint, &caps));
     if (!task) {
         return false;
     }