| /* | |
| * 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> | |
| using namespace skia_private; | |
| typedef void (*CreateGraphPF)(TArray<sk_sp<GrMockRenderTask>>* graph, | |
| TArray<sk_sp<GrMockRenderTask>>* expected); | |
| static void make_proxies(int count, TArray<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, TArray<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(TArray<sk_sp<GrMockRenderTask>>* graph, | |
| TArray<sk_sp<GrMockRenderTask>>* expected) { | |
| TArray<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(TArray<sk_sp<GrMockRenderTask>>* graph, | |
| TArray<sk_sp<GrMockRenderTask>>* expected) { | |
| TArray<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(TArray<sk_sp<GrMockRenderTask>>* graph, | |
| TArray<sk_sp<GrMockRenderTask>>* expected) { | |
| TArray<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(TArray<sk_sp<GrMockRenderTask>>* graph, | |
| TArray<sk_sp<GrMockRenderTask>>* expected) { | |
| TArray<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) { | |
| TArray<sk_sp<GrMockRenderTask>> graph; | |
| TArray<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);) | |
| } | |
| } |