|  | /* | 
|  | * Copyright 2021 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "include/core/SkRefCnt.h" | 
|  | #include "include/core/SkSpan.h" | 
|  | #include "include/core/SkString.h" | 
|  | #include "include/private/base/SkTArray.h" | 
|  | #include "src/base/SkTInternalLList.h" | 
|  | #include "src/gpu/ganesh/GrRenderTask.h" | 
|  | #include "src/gpu/ganesh/GrRenderTaskCluster.h" | 
|  | #include "src/gpu/ganesh/GrSurfaceProxy.h" | 
|  | #include "src/gpu/ganesh/mock/GrMockRenderTask.h" | 
|  | #include "src/gpu/ganesh/mock/GrMockSurfaceProxy.h" | 
|  | #include "tests/Test.h" | 
|  |  | 
|  | #include <array> | 
|  | #include <cstddef> | 
|  | #include <utility> | 
|  |  | 
|  | typedef void (*CreateGraphPF)(SkTArray<sk_sp<GrMockRenderTask>>* graph, | 
|  | SkTArray<sk_sp<GrMockRenderTask>>* expected); | 
|  |  | 
|  | static void make_proxies(int count, SkTArray<sk_sp<GrSurfaceProxy>>* proxies) { | 
|  | proxies->reset(count); | 
|  | for (int i = 0; i < count; i++) { | 
|  | auto name = SkStringPrintf("%c", 'A' + i); | 
|  | proxies->at(i) = sk_make_sp<GrMockSurfaceProxy>(std::move(name), | 
|  | /*label=*/"RenderTaskClusterTest"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void make_tasks(int count, SkTArray<sk_sp<GrMockRenderTask>>* tasks) { | 
|  | tasks->reset(count); | 
|  | for (int i = 0; i < count; i++) { | 
|  | tasks->at(i) = sk_make_sp<GrMockRenderTask>(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * In:  A1 B1 A2 | 
|  | * Out: B1 A1 A2 | 
|  | */ | 
|  | static void create_graph0(SkTArray<sk_sp<GrMockRenderTask>>* graph, | 
|  | SkTArray<sk_sp<GrMockRenderTask>>* expected) { | 
|  | SkTArray<sk_sp<GrSurfaceProxy>> proxies; | 
|  | make_proxies(2, &proxies); | 
|  | make_tasks(3, graph); | 
|  |  | 
|  | graph->at(0)->addTarget(proxies[0]); | 
|  | graph->at(1)->addTarget(proxies[1]); | 
|  | graph->at(2)->addTarget(proxies[0]); | 
|  | graph->at(2)->addDependency(graph->at(1).get()); | 
|  |  | 
|  | expected->push_back(graph->at(1)); | 
|  | expected->push_back(graph->at(0)); | 
|  | expected->push_back(graph->at(2)); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * In:  A1 B1 A2 C1 A3 | 
|  | * Out: B1 C1 A1 A2 A3 | 
|  | */ | 
|  | static void create_graph1(SkTArray<sk_sp<GrMockRenderTask>>* graph, | 
|  | SkTArray<sk_sp<GrMockRenderTask>>* expected) { | 
|  | SkTArray<sk_sp<GrSurfaceProxy>> proxies; | 
|  | make_proxies(3, &proxies); | 
|  | make_tasks(5, graph); | 
|  |  | 
|  | graph->at(0)->addTarget(proxies[0]); | 
|  | graph->at(1)->addTarget(proxies[1]); | 
|  | graph->at(2)->addTarget(proxies[0]); | 
|  | graph->at(3)->addTarget(proxies[2]); | 
|  | graph->at(4)->addTarget(proxies[0]); | 
|  |  | 
|  | expected->push_back(graph->at(1)); | 
|  | expected->push_back(graph->at(3)); | 
|  | expected->push_back(graph->at(0)); | 
|  | expected->push_back(graph->at(2)); | 
|  | expected->push_back(graph->at(4)); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * In:   A1 B1 A2. | 
|  | * Srcs: A1->B1, B1->A2. | 
|  | * Out:  A1 B1 A2. Can't reorder. | 
|  | */ | 
|  | static void create_graph2(SkTArray<sk_sp<GrMockRenderTask>>* graph, | 
|  | SkTArray<sk_sp<GrMockRenderTask>>* expected) { | 
|  | SkTArray<sk_sp<GrSurfaceProxy>> proxies; | 
|  | make_proxies(2, &proxies); | 
|  | make_tasks(3, graph); | 
|  |  | 
|  | graph->at(0)->addTarget(proxies[0]); | 
|  | graph->at(1)->addTarget(proxies[1]); | 
|  | graph->at(2)->addTarget(proxies[0]); | 
|  |  | 
|  | graph->at(1)->addDependency(graph->at(0).get()); | 
|  | graph->at(2)->addDependency(graph->at(1).get()); | 
|  |  | 
|  | // expected is empty. Can't reorder. | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Write-after-read case. | 
|  | * In:   A1 B1 A2 B2 | 
|  | * Srcs: A1->B1, A2->B2 | 
|  | * Used: B1(A), B2(A) | 
|  | * Out:  Can't reorder. | 
|  | */ | 
|  | static void create_graph3(SkTArray<sk_sp<GrMockRenderTask>>* graph, | 
|  | SkTArray<sk_sp<GrMockRenderTask>>* expected) { | 
|  | SkTArray<sk_sp<GrSurfaceProxy>> proxies; | 
|  | make_proxies(2, &proxies); | 
|  | make_tasks(4, graph); | 
|  |  | 
|  | graph->at(0)->addTarget(proxies[0]); | 
|  | graph->at(1)->addTarget(proxies[1]); | 
|  | graph->at(2)->addTarget(proxies[0]); | 
|  | graph->at(3)->addTarget(proxies[1]); | 
|  |  | 
|  | graph->at(1)->addDependency(graph->at(0).get()); | 
|  | graph->at(3)->addDependency(graph->at(2).get()); | 
|  |  | 
|  | graph->at(1)->addUsed(proxies[0]); | 
|  | graph->at(3)->addUsed(proxies[0]); | 
|  |  | 
|  | // expected is empty. Can't reorder. | 
|  | } | 
|  |  | 
|  | DEF_TEST(GrRenderTaskCluster, reporter) { | 
|  | CreateGraphPF tests[] = { | 
|  | create_graph0, | 
|  | create_graph1, | 
|  | create_graph2, | 
|  | create_graph3 | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < std::size(tests); ++i) { | 
|  | SkTArray<sk_sp<GrMockRenderTask>> graph; | 
|  | SkTArray<sk_sp<GrMockRenderTask>> expectedOutput; | 
|  |  | 
|  | (tests[i])(&graph, &expectedOutput); | 
|  |  | 
|  | SkTInternalLList<GrRenderTask> llist; | 
|  | // TODO: Why does Span not want to convert from sk_sp<GrMockRenderTask> to | 
|  | // `const sk_sp<GrRenderTask>`? | 
|  | SkSpan<const sk_sp<GrRenderTask>> graphSpan( | 
|  | reinterpret_cast<sk_sp<GrRenderTask>*>(graph.data()), graph.size()); | 
|  | bool actualResult = GrClusterRenderTasks(graphSpan, &llist); | 
|  |  | 
|  | if (expectedOutput.empty()) { | 
|  | REPORTER_ASSERT(reporter, !actualResult); | 
|  | size_t newCount = 0; | 
|  | for (const GrRenderTask* t : llist) { | 
|  | REPORTER_ASSERT(reporter, newCount < graphSpan.size() && | 
|  | t == graph[newCount].get()); | 
|  | ++newCount; | 
|  | } | 
|  | REPORTER_ASSERT(reporter, newCount == graphSpan.size()); | 
|  | } else { | 
|  | REPORTER_ASSERT(reporter, actualResult); | 
|  | // SkTInternalLList::countEntries is debug-only and these tests run in release. | 
|  | int newCount = 0; | 
|  | for ([[maybe_unused]] GrRenderTask* t : llist) { | 
|  | newCount++; | 
|  | } | 
|  | REPORTER_ASSERT(reporter, newCount == expectedOutput.size()); | 
|  |  | 
|  | int j = 0; | 
|  | for (GrRenderTask* n : llist) { | 
|  | REPORTER_ASSERT(reporter, n == expectedOutput[j++].get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | //SkDEBUGCODE(print(graph);) | 
|  | } | 
|  | } |