Merge adjacent GrOpsTasks with same target together
This allows the ops tasks to make one render pass instead of multiple.
The only case where this merging is needed is as a result of
reordering (reduceOpsTaskSplitting).
Bug: skia:10877
Change-Id: Ia967ead6efc43f7d2c1da58f770d3987da690cda
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353656
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Adlai Holler <adlai@google.com>
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 5c1b9b5..1f2ab64 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -424,17 +424,20 @@
}
// Reorder the array to match the llist without reffing & unreffing sk_sp's.
-// Both args must contain the same objects.
+// The llist must contain a subset of the entries in the array.
// This is basically a shim because clustering uses LList but the rest of drawmgr uses array.
+// Pointers in the array are not dereferenced.
template <typename T>
static void reorder_array_by_llist(const SkTInternalLList<T>& llist, SkTArray<sk_sp<T>>* array) {
+ for (sk_sp<T>& t : *array) {
+ [[maybe_unused]] T* old = t.release();
+ }
int i = 0;
for (T* t : llist) {
- // Release the pointer that used to live here so it doesn't get unreffed.
- [[maybe_unused]] T* old = array->at(i).release();
array->at(i++).reset(t);
}
- SkASSERT(i == array->count());
+ SkASSERT(i <= array->count());
+ array->resize_back(i);
}
void GrDrawingManager::reorderTasks() {
@@ -446,6 +449,30 @@
}
// TODO: Handle case where proposed order would blow our memory budget.
// Such cases are currently pathological, so we could just return here and keep current order.
+
+ // Merge adjacent ops tasks. Note: We remove (future) tasks from the list during iteration.
+ // This works out, however, because when we access the next element in llist it will be valid.
+ for (auto task : llist) {
+ auto opsTask = task->asOpsTask();
+ if (!opsTask) {
+ continue;
+ }
+
+ int removedCount = opsTask->mergeFromLList();
+ auto removedTask = opsTask->fNext;
+ for (int i = 0; i < removedCount; i++) {
+ auto next = removedTask->fNext;
+ llist.remove(removedTask);
+
+ // After this unref, there will be a dangling sk_sp to this task in fDAG somewhere.
+ // That dangling pointer will be removed in reorder_array_by_llist.
+ removedTask->disown(this);
+ removedTask->unref();
+
+ removedTask = next;
+ }
+ }
+
reorder_array_by_llist(llist, &fDAG);
}