1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTaskCluster.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkTHash.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTask.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci// Uncomment to get lots of logging. 14cb93a386Sopenharmony_ci#define CLUSTER_DEBUGF(...) //SkDebugf(__VA_ARGS__) 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistatic GrSurfaceProxy* first_target(GrRenderTask* task) { return task->target(0); } 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci#ifdef SK_DEBUG 19cb93a386Sopenharmony_ci[[maybe_unused]] static SkString describe_task(GrRenderTask* t) { 20cb93a386Sopenharmony_ci if (GrSurfaceProxy* target = first_target(t)) { 21cb93a386Sopenharmony_ci return SkStringPrintf("%s(%d)", target->getDebugName().c_str(), t->uniqueID()); 22cb93a386Sopenharmony_ci } else { 23cb93a386Sopenharmony_ci return SkStringPrintf("%d", t->uniqueID()); 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci} 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci[[maybe_unused]] static SkString describe_tasks(SkSpan<const sk_sp<GrRenderTask>> collection) { 28cb93a386Sopenharmony_ci SkString s; 29cb93a386Sopenharmony_ci for (const sk_sp<GrRenderTask>& t : collection) { 30cb93a386Sopenharmony_ci s.appendf("%s ", describe_task(t.get()).c_str()); 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci return s; 33cb93a386Sopenharmony_ci} 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci[[maybe_unused]] static SkString describe_tasks(const SkTInternalLList<GrRenderTask>& collection) { 36cb93a386Sopenharmony_ci SkString s; 37cb93a386Sopenharmony_ci for (GrRenderTask* t : collection) { 38cb93a386Sopenharmony_ci s.appendf("%s ", describe_task(t).c_str()); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci return s; 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistatic void validate(SkSpan<const sk_sp<GrRenderTask>> input, 44cb93a386Sopenharmony_ci const SkTInternalLList<GrRenderTask>& llist) { 45cb93a386Sopenharmony_ci // Check that we didn't break dependencies. 46cb93a386Sopenharmony_ci SkTHashSet<GrRenderTask*> seen; 47cb93a386Sopenharmony_ci for (GrRenderTask* t : llist) { 48cb93a386Sopenharmony_ci seen.add(t); 49cb93a386Sopenharmony_ci for (GrRenderTask* dep : t->dependencies()) { 50cb93a386Sopenharmony_ci SkASSERTF(seen.contains(dep), 51cb93a386Sopenharmony_ci "%s came before dependency %s", 52cb93a386Sopenharmony_ci describe_task(t).c_str(), 53cb93a386Sopenharmony_ci describe_task(dep).c_str()); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci // Check that llist has the same entries as the input. 57cb93a386Sopenharmony_ci for (const auto& orig : input) { 58cb93a386Sopenharmony_ci seen.remove(orig.get()); 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci SkASSERT(seen.empty()); 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci#endif // SK_DEBUG 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci// Returns whether `dependee` is a formal dependent or if it uses a surface `depender` targets. 66cb93a386Sopenharmony_cistatic bool depends_on(GrRenderTask* depender, GrRenderTask* dependee) { 67cb93a386Sopenharmony_ci // Check if depender writes to something dependee reads. 68cb93a386Sopenharmony_ci // TODO: Establish real DAG dependencies for this during recording? E.g. when a task adds a 69cb93a386Sopenharmony_ci // target, search backward for the last task that uses the target and add a dep. 70cb93a386Sopenharmony_ci for (int i = 0; i < depender->numTargets(); i++) { 71cb93a386Sopenharmony_ci if (dependee->isUsed(depender->target(i))) { 72cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Bail, %s can't write before %s reads from %s.\n", 73cb93a386Sopenharmony_ci describe_task(depender).c_str(), 74cb93a386Sopenharmony_ci describe_task(dependee).c_str(), 75cb93a386Sopenharmony_ci depender->target(i)->getDebugName().c_str()); 76cb93a386Sopenharmony_ci return true; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci // Check for a formal dependency. 80cb93a386Sopenharmony_ci if (depender->dependsOn(dependee)) { 81cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Bail, %s depends on %s.\n", 82cb93a386Sopenharmony_ci describe_task(depender).c_str(), 83cb93a386Sopenharmony_ci describe_task(dependee).c_str()); 84cb93a386Sopenharmony_ci return true; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci return false; 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci// Returns whether reordering occurred. 90cb93a386Sopenharmony_cistatic bool task_cluster_visit(GrRenderTask* task, SkTInternalLList<GrRenderTask>* llist, 91cb93a386Sopenharmony_ci SkTHashMap<GrSurfaceProxy*, GrRenderTask*>* lastTaskMap) { 92cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: ***Step***\nLooking at %s\n", 93cb93a386Sopenharmony_ci describe_task(task).c_str()); 94cb93a386Sopenharmony_ci if (task->numTargets() != 1) { 95cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: %d targets. Emitting barriers.\n", task->numTargets()); 96cb93a386Sopenharmony_ci // Tasks with 0 or multiple targets are treated as full barriers 97cb93a386Sopenharmony_ci // for all their targets. 98cb93a386Sopenharmony_ci for (int j = 0; j < task->numTargets(); j++) { 99cb93a386Sopenharmony_ci if (lastTaskMap->find(task->target(0))) { 100cb93a386Sopenharmony_ci lastTaskMap->remove(task->target(0)); 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci return false; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci GrSurfaceProxy* target = first_target(task); 107cb93a386Sopenharmony_ci GrRenderTask* clusterTail = (lastTaskMap->find(target) ? *lastTaskMap->find(target) : nullptr); 108cb93a386Sopenharmony_ci lastTaskMap->set(target, task); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci if (!clusterTail) { 111cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Bail, no cluster to extend.\n"); 112cb93a386Sopenharmony_ci return false; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: clusterTail is %s.\n", describe_task(clusterTail).c_str()); 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci if (clusterTail == llist->tail()) { 118cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Bail, cluster is already tail.\n"); 119cb93a386Sopenharmony_ci return false; 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci GrRenderTask* movedHead = clusterTail->fNext; 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci // Now, let's refer to the "cluster" as the chain of tasks with the same target, that we're 124cb93a386Sopenharmony_ci // hoping to extend by reordering. Let "moved tasks" be the ones we want to move to extend the 125cb93a386Sopenharmony_ci // cluster. 126cb93a386Sopenharmony_ci GrRenderTask* clusterHead = clusterTail; 127cb93a386Sopenharmony_ci while (clusterHead->fPrev 128cb93a386Sopenharmony_ci && 1 == clusterHead->fPrev->numTargets() 129cb93a386Sopenharmony_ci && target == first_target(clusterHead->fPrev)) { 130cb93a386Sopenharmony_ci clusterHead = clusterHead->fPrev; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // We can't reorder if any moved task depends on anything in the cluster. 134cb93a386Sopenharmony_ci // Time complexity here is high, but making a hash set is worse in profiling. 135cb93a386Sopenharmony_ci for (GrRenderTask* moved = movedHead; moved; moved = moved->fNext) { 136cb93a386Sopenharmony_ci for (GrRenderTask* passed = clusterHead; passed != movedHead; passed = passed->fNext) { 137cb93a386Sopenharmony_ci if (depends_on(moved, passed)) { 138cb93a386Sopenharmony_ci return false; 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci // Grab the moved tasks and pull them before clusterHead. 144cb93a386Sopenharmony_ci for (GrRenderTask* moved = movedHead; moved;) { 145cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Reorder %s behind %s.\n", 146cb93a386Sopenharmony_ci describe_task(moved).c_str(), 147cb93a386Sopenharmony_ci describe_task(clusterHead).c_str()); 148cb93a386Sopenharmony_ci // Be careful to save fNext before each move. 149cb93a386Sopenharmony_ci GrRenderTask* nextMoved = moved->fNext; 150cb93a386Sopenharmony_ci llist->remove(moved); 151cb93a386Sopenharmony_ci llist->addBefore(moved, clusterHead); 152cb93a386Sopenharmony_ci moved = nextMoved; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci return true; 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_cibool GrClusterRenderTasks(SkSpan<const sk_sp<GrRenderTask>> input, 158cb93a386Sopenharmony_ci SkTInternalLList<GrRenderTask>* llist) { 159cb93a386Sopenharmony_ci SkASSERT(llist->isEmpty()); 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci if (input.size() < 3) { 162cb93a386Sopenharmony_ci return false; 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Original order is %s\n", describe_tasks(input).c_str()); 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci SkTHashMap<GrSurfaceProxy*, GrRenderTask*> lastTaskMap; 168cb93a386Sopenharmony_ci bool didReorder = false; 169cb93a386Sopenharmony_ci for (const auto& t : input) { 170cb93a386Sopenharmony_ci didReorder |= task_cluster_visit(t.get(), llist, &lastTaskMap); 171cb93a386Sopenharmony_ci llist->addToTail(t.get()); 172cb93a386Sopenharmony_ci CLUSTER_DEBUGF("Cluster: Output order is now: %s\n", describe_tasks(*llist).c_str()); 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci#ifdef SK_DEBUG 176cb93a386Sopenharmony_ci if (didReorder) { 177cb93a386Sopenharmony_ci validate(input, *llist); 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci#endif 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci return didReorder; 182cb93a386Sopenharmony_ci} 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci#undef CLUSTER_DEBUGF 185