1 // Copyright 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16
17 #include "VirtioGpuTimelines.h"
18
19 #include <memory>
20
21 namespace gfxstream {
22 namespace {
23
24 using testing::ElementsAreArray;
25 using testing::Eq;
26 using testing::ElementsAreArray;
27 using testing::IsEmpty;
28 using testing::Pair;
29
30 using Ring = VirtioGpuTimelines::Ring;
31 using FenceId = VirtioGpuTimelines::FenceId;
32 using RingGlobal = VirtioGpuRingGlobal;
33 using RingContextSpecific = VirtioGpuRingContextSpecific;
34
35 const auto kGlobalRing = Ring{VirtioGpuRingGlobal{}};
36 const auto kContext2Ring = Ring{RingContextSpecific{
37 .mCtxId = 2,
38 .mRingIdx = 0,
39 }};
40 const auto kContext3Ring = Ring{RingContextSpecific{
41 .mCtxId = 3,
42 .mRingIdx = 0,
43 }};
44
TEST(VirtioGpuTimelinesTest,Init)45 TEST(VirtioGpuTimelinesTest, Init) {
46 auto noopCallback = [](const Ring&, FenceId) {};
47 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines;
48 virtioGpuTimelines = VirtioGpuTimelines::create(noopCallback);
49 virtioGpuTimelines = VirtioGpuTimelines::create(noopCallback);
50 }
51
TEST(VirtioGpuTimelinesTest,TasksShouldHaveDifferentIds)52 TEST(VirtioGpuTimelinesTest, TasksShouldHaveDifferentIds) {
53 auto noopCallback = [](const Ring&, FenceId) {};
54 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
55 VirtioGpuTimelines::create(noopCallback);
56 auto taskId1 = virtioGpuTimelines->enqueueTask(kGlobalRing);
57 auto taskId2 = virtioGpuTimelines->enqueueTask(kGlobalRing);
58 ASSERT_NE(taskId1, taskId2);
59 }
60
TEST(VirtioGpuTimelinesTest,MultipleTasksAndFencesWithAsyncCallback)61 TEST(VirtioGpuTimelinesTest, MultipleTasksAndFencesWithAsyncCallback) {
62 std::vector<std::pair<Ring, FenceId>> signaledFences;
63
64 auto fenceCallback =
65 [&](const Ring& ring, FenceId fenceId) {
66 signaledFences.push_back(std::make_pair(ring, fenceId));
67 };
68 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
69 VirtioGpuTimelines::create(fenceCallback);
70
71 FenceId fenceId = 0;
72
73 auto task1Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
74 EXPECT_THAT(signaledFences, IsEmpty());
75
76 auto fence1Id = fenceId++;
77
78 virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
79 EXPECT_THAT(signaledFences, IsEmpty());
80
81 auto task2Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
82 EXPECT_THAT(signaledFences, IsEmpty());
83
84 auto fence2Id = fenceId++;
85
86 virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
87 EXPECT_THAT(signaledFences, IsEmpty());
88
89 virtioGpuTimelines->notifyTaskCompletion(task1Id);
90 EXPECT_THAT(signaledFences,
91 ElementsAreArray({
92 Pair(Eq(kGlobalRing), Eq(fence1Id)),
93 }));
94
95 auto task3Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
96 EXPECT_THAT(signaledFences,
97 ElementsAreArray({
98 Pair(Eq(kGlobalRing), Eq(fence1Id)),
99 }));
100
101 auto fence3Id = fenceId++;
102 virtioGpuTimelines->enqueueFence(kGlobalRing, fence3Id);
103 EXPECT_THAT(signaledFences,
104 ElementsAreArray({
105 Pair(Eq(kGlobalRing), Eq(fence1Id)),
106 }));
107
108 virtioGpuTimelines->notifyTaskCompletion(task2Id);
109 EXPECT_THAT(signaledFences,
110 ElementsAreArray({
111 Pair(Eq(kGlobalRing), Eq(fence1Id)),
112 Pair(Eq(kGlobalRing), Eq(fence2Id)),
113 }));
114
115 virtioGpuTimelines->notifyTaskCompletion(task3Id);
116 EXPECT_THAT(signaledFences,
117 ElementsAreArray({
118 Pair(Eq(kGlobalRing), Eq(fence1Id)),
119 Pair(Eq(kGlobalRing), Eq(fence2Id)),
120 Pair(Eq(kGlobalRing), Eq(fence3Id)),
121 }));
122 }
123
TEST(VirtioGpuTimelinesTest,FencesWithoutPendingTasksWithAsyncCallback)124 TEST(VirtioGpuTimelinesTest, FencesWithoutPendingTasksWithAsyncCallback) {
125 std::vector<std::pair<Ring, FenceId>> signaledFences;
126
127 auto fenceCallback =
128 [&](const Ring& ring, FenceId fenceId) {
129 signaledFences.push_back(std::make_pair(ring, fenceId));
130 };
131 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
132 VirtioGpuTimelines::create(fenceCallback);
133
134 FenceId fenceId = 0;
135
136 auto fence1Id = fenceId++;
137 virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
138 EXPECT_THAT(signaledFences,
139 ElementsAreArray({
140 Pair(Eq(kGlobalRing), Eq(fence1Id)),
141 }));
142
143 auto fence2Id = fenceId++;
144 virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
145 EXPECT_THAT(signaledFences,
146 ElementsAreArray({
147 Pair(Eq(kGlobalRing), Eq(fence1Id)),
148 Pair(Eq(kGlobalRing), Eq(fence2Id)),
149 }));
150 }
151
TEST(VirtioGpuTimelinesTest,FencesSharingSamePendingTasksWithAsyncCallback)152 TEST(VirtioGpuTimelinesTest, FencesSharingSamePendingTasksWithAsyncCallback) {
153 std::vector<std::pair<Ring, FenceId>> signaledFences;
154
155 auto fenceCallback =
156 [&](const Ring& ring, FenceId fenceId) {
157 signaledFences.push_back(std::make_pair(ring, fenceId));
158 };
159 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
160 VirtioGpuTimelines::create(fenceCallback);
161
162 FenceId fenceId = 0;
163
164 auto taskId = virtioGpuTimelines->enqueueTask(kGlobalRing);
165 EXPECT_THAT(signaledFences, IsEmpty());
166
167 auto fence1Id = fenceId++;
168 virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
169 EXPECT_THAT(signaledFences, IsEmpty());
170
171 auto fence2Id = fenceId++;
172 virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
173 EXPECT_THAT(signaledFences, IsEmpty());
174
175 virtioGpuTimelines->notifyTaskCompletion(taskId);
176 EXPECT_THAT(signaledFences,
177 ElementsAreArray({
178 Pair(Eq(kGlobalRing), Eq(fence1Id)),
179 Pair(Eq(kGlobalRing), Eq(fence2Id)),
180 }));
181 }
182
TEST(VirtioGpuTimelinesTest,TasksAndFencesOnMultipleContextsWithAsyncCallback)183 TEST(VirtioGpuTimelinesTest, TasksAndFencesOnMultipleContextsWithAsyncCallback) {
184 std::vector<std::pair<Ring, FenceId>> signaledFences;
185
186 auto fenceCallback =
187 [&](const Ring& ring, FenceId fenceId) {
188 signaledFences.push_back(std::make_pair(ring, fenceId));
189 };
190 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
191 VirtioGpuTimelines::create(fenceCallback);
192
193 auto taskId2 = virtioGpuTimelines->enqueueTask(kContext2Ring);
194 EXPECT_THAT(signaledFences, IsEmpty());
195
196 auto taskId3 = virtioGpuTimelines->enqueueTask(kContext3Ring);
197 EXPECT_THAT(signaledFences, IsEmpty());
198
199 virtioGpuTimelines->enqueueFence(kGlobalRing, 1);
200 EXPECT_THAT(signaledFences,
201 ElementsAreArray({
202 Pair(Eq(kGlobalRing), Eq(1)),
203 }));
204
205 virtioGpuTimelines->enqueueFence(kContext2Ring, 2);
206 EXPECT_THAT(signaledFences,
207 ElementsAreArray({
208 Pair(Eq(kGlobalRing), Eq(1)),
209 }));
210
211 virtioGpuTimelines->enqueueFence(kContext3Ring, 3);
212 EXPECT_THAT(signaledFences,
213 ElementsAreArray({
214 Pair(Eq(kGlobalRing), Eq(1)),
215 }));
216
217 virtioGpuTimelines->notifyTaskCompletion(taskId2);
218 EXPECT_THAT(signaledFences,
219 ElementsAreArray({
220 Pair(Eq(kGlobalRing), Eq(1)),
221 Pair(Eq(kContext2Ring), Eq(2)),
222 }));
223
224 virtioGpuTimelines->notifyTaskCompletion(taskId3);
225 EXPECT_THAT(signaledFences,
226 ElementsAreArray({
227 Pair(Eq(kGlobalRing), Eq(1)),
228 Pair(Eq(kContext2Ring), Eq(2)),
229 Pair(Eq(kContext3Ring), Eq(3)),
230 }));
231 }
232
TEST(VirtioGpuTimelinesTest,TasksAndFencesOnMultipleRingsWithAsyncCallback)233 TEST(VirtioGpuTimelinesTest, TasksAndFencesOnMultipleRingsWithAsyncCallback) {
234 std::vector<std::pair<Ring, FenceId>> signaledFences;
235
236 auto fenceCallback =
237 [&](const Ring& ring, FenceId fenceId) {
238 signaledFences.push_back(std::make_pair(ring, fenceId));
239 };
240 std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
241 VirtioGpuTimelines::create(fenceCallback);
242
243 const auto kContext1Ring1 = Ring{RingContextSpecific{
244 .mCtxId = 1,
245 .mRingIdx = 1,
246 }};
247 const auto kContext1Ring2 = Ring{RingContextSpecific{
248 .mCtxId = 1,
249 .mRingIdx = 2,
250 }};
251 const auto kContext1Ring3 = Ring{RingContextSpecific{
252 .mCtxId = 1,
253 .mRingIdx = 3,
254 }};
255
256 auto taskId2 = virtioGpuTimelines->enqueueTask(kContext1Ring2);
257 auto taskId3 = virtioGpuTimelines->enqueueTask(kContext1Ring3);
258 EXPECT_THAT(signaledFences, IsEmpty());
259
260 virtioGpuTimelines->enqueueFence(kContext1Ring1, 1);
261 EXPECT_THAT(signaledFences,
262 ElementsAreArray({
263 Pair(Eq(kContext1Ring1), Eq(1)),
264 }));
265
266 virtioGpuTimelines->enqueueFence(kContext1Ring2, 2);
267 EXPECT_THAT(signaledFences,
268 ElementsAreArray({
269 Pair(Eq(kContext1Ring1), Eq(1)),
270 }));
271
272 virtioGpuTimelines->enqueueFence(kContext1Ring3, 3);
273 EXPECT_THAT(signaledFences,
274 ElementsAreArray({
275 Pair(Eq(kContext1Ring1), Eq(1)),
276 }));
277
278 virtioGpuTimelines->notifyTaskCompletion(taskId2);
279 EXPECT_THAT(signaledFences,
280 ElementsAreArray({
281 Pair(Eq(kContext1Ring1), Eq(1)),
282 Pair(Eq(kContext1Ring2), Eq(2)),
283 }));
284
285 virtioGpuTimelines->notifyTaskCompletion(taskId3);
286 EXPECT_THAT(signaledFences,
287 ElementsAreArray({
288 Pair(Eq(kContext1Ring1), Eq(1)),
289 Pair(Eq(kContext1Ring2), Eq(2)),
290 Pair(Eq(kContext1Ring3), Eq(3)),
291 }));
292 }
293
294 } // namespace
295 } // namespace gfxstream
296