blob: f75e7df96c4c8f84be3d6a0d07a8e1879b665623 [file] [log] [blame] [edit]
// Copyright 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "VirtioGpuTimelines.h"
#include <memory>
namespace gfxstream {
namespace {
using testing::ElementsAreArray;
using testing::Eq;
using testing::ElementsAreArray;
using testing::IsEmpty;
using testing::Pair;
using Ring = VirtioGpuTimelines::Ring;
using FenceId = VirtioGpuTimelines::FenceId;
using RingGlobal = VirtioGpuRingGlobal;
using RingContextSpecific = VirtioGpuRingContextSpecific;
const auto kGlobalRing = Ring{VirtioGpuRingGlobal{}};
const auto kContext2Ring = Ring{RingContextSpecific{
.mCtxId = 2,
.mRingIdx = 0,
}};
const auto kContext3Ring = Ring{RingContextSpecific{
.mCtxId = 3,
.mRingIdx = 0,
}};
TEST(VirtioGpuTimelinesTest, Init) {
auto noopCallback = [](const Ring&, FenceId) {};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines;
virtioGpuTimelines = VirtioGpuTimelines::create(noopCallback);
virtioGpuTimelines = VirtioGpuTimelines::create(noopCallback);
}
TEST(VirtioGpuTimelinesTest, TasksShouldHaveDifferentIds) {
auto noopCallback = [](const Ring&, FenceId) {};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(noopCallback);
auto taskId1 = virtioGpuTimelines->enqueueTask(kGlobalRing);
auto taskId2 = virtioGpuTimelines->enqueueTask(kGlobalRing);
ASSERT_NE(taskId1, taskId2);
}
TEST(VirtioGpuTimelinesTest, MultipleTasksAndFencesWithAsyncCallback) {
std::vector<std::pair<Ring, FenceId>> signaledFences;
auto fenceCallback =
[&](const Ring& ring, FenceId fenceId) {
signaledFences.push_back(std::make_pair(ring, fenceId));
};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(fenceCallback);
FenceId fenceId = 0;
auto task1Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
EXPECT_THAT(signaledFences, IsEmpty());
auto fence1Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
EXPECT_THAT(signaledFences, IsEmpty());
auto task2Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
EXPECT_THAT(signaledFences, IsEmpty());
auto fence2Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
EXPECT_THAT(signaledFences, IsEmpty());
virtioGpuTimelines->notifyTaskCompletion(task1Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
}));
auto task3Id = virtioGpuTimelines->enqueueTask(kGlobalRing);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
}));
auto fence3Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence3Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
}));
virtioGpuTimelines->notifyTaskCompletion(task2Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
Pair(Eq(kGlobalRing), Eq(fence2Id)),
}));
virtioGpuTimelines->notifyTaskCompletion(task3Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
Pair(Eq(kGlobalRing), Eq(fence2Id)),
Pair(Eq(kGlobalRing), Eq(fence3Id)),
}));
}
TEST(VirtioGpuTimelinesTest, FencesWithoutPendingTasksWithAsyncCallback) {
std::vector<std::pair<Ring, FenceId>> signaledFences;
auto fenceCallback =
[&](const Ring& ring, FenceId fenceId) {
signaledFences.push_back(std::make_pair(ring, fenceId));
};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(fenceCallback);
FenceId fenceId = 0;
auto fence1Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
}));
auto fence2Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
Pair(Eq(kGlobalRing), Eq(fence2Id)),
}));
}
TEST(VirtioGpuTimelinesTest, FencesSharingSamePendingTasksWithAsyncCallback) {
std::vector<std::pair<Ring, FenceId>> signaledFences;
auto fenceCallback =
[&](const Ring& ring, FenceId fenceId) {
signaledFences.push_back(std::make_pair(ring, fenceId));
};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(fenceCallback);
FenceId fenceId = 0;
auto taskId = virtioGpuTimelines->enqueueTask(kGlobalRing);
EXPECT_THAT(signaledFences, IsEmpty());
auto fence1Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence1Id);
EXPECT_THAT(signaledFences, IsEmpty());
auto fence2Id = fenceId++;
virtioGpuTimelines->enqueueFence(kGlobalRing, fence2Id);
EXPECT_THAT(signaledFences, IsEmpty());
virtioGpuTimelines->notifyTaskCompletion(taskId);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(fence1Id)),
Pair(Eq(kGlobalRing), Eq(fence2Id)),
}));
}
TEST(VirtioGpuTimelinesTest, TasksAndFencesOnMultipleContextsWithAsyncCallback) {
std::vector<std::pair<Ring, FenceId>> signaledFences;
auto fenceCallback =
[&](const Ring& ring, FenceId fenceId) {
signaledFences.push_back(std::make_pair(ring, fenceId));
};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(fenceCallback);
auto taskId2 = virtioGpuTimelines->enqueueTask(kContext2Ring);
EXPECT_THAT(signaledFences, IsEmpty());
auto taskId3 = virtioGpuTimelines->enqueueTask(kContext3Ring);
EXPECT_THAT(signaledFences, IsEmpty());
virtioGpuTimelines->enqueueFence(kGlobalRing, 1);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(1)),
}));
virtioGpuTimelines->enqueueFence(kContext2Ring, 2);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(1)),
}));
virtioGpuTimelines->enqueueFence(kContext3Ring, 3);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(1)),
}));
virtioGpuTimelines->notifyTaskCompletion(taskId2);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(1)),
Pair(Eq(kContext2Ring), Eq(2)),
}));
virtioGpuTimelines->notifyTaskCompletion(taskId3);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kGlobalRing), Eq(1)),
Pair(Eq(kContext2Ring), Eq(2)),
Pair(Eq(kContext3Ring), Eq(3)),
}));
}
TEST(VirtioGpuTimelinesTest, TasksAndFencesOnMultipleRingsWithAsyncCallback) {
std::vector<std::pair<Ring, FenceId>> signaledFences;
auto fenceCallback =
[&](const Ring& ring, FenceId fenceId) {
signaledFences.push_back(std::make_pair(ring, fenceId));
};
std::unique_ptr<VirtioGpuTimelines> virtioGpuTimelines =
VirtioGpuTimelines::create(fenceCallback);
const auto kContext1Ring1 = Ring{RingContextSpecific{
.mCtxId = 1,
.mRingIdx = 1,
}};
const auto kContext1Ring2 = Ring{RingContextSpecific{
.mCtxId = 1,
.mRingIdx = 2,
}};
const auto kContext1Ring3 = Ring{RingContextSpecific{
.mCtxId = 1,
.mRingIdx = 3,
}};
auto taskId2 = virtioGpuTimelines->enqueueTask(kContext1Ring2);
auto taskId3 = virtioGpuTimelines->enqueueTask(kContext1Ring3);
EXPECT_THAT(signaledFences, IsEmpty());
virtioGpuTimelines->enqueueFence(kContext1Ring1, 1);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kContext1Ring1), Eq(1)),
}));
virtioGpuTimelines->enqueueFence(kContext1Ring2, 2);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kContext1Ring1), Eq(1)),
}));
virtioGpuTimelines->enqueueFence(kContext1Ring3, 3);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kContext1Ring1), Eq(1)),
}));
virtioGpuTimelines->notifyTaskCompletion(taskId2);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kContext1Ring1), Eq(1)),
Pair(Eq(kContext1Ring2), Eq(2)),
}));
virtioGpuTimelines->notifyTaskCompletion(taskId3);
EXPECT_THAT(signaledFences,
ElementsAreArray({
Pair(Eq(kContext1Ring1), Eq(1)),
Pair(Eq(kContext1Ring2), Eq(2)),
Pair(Eq(kContext1Ring3), Eq(3)),
}));
}
} // namespace
} // namespace gfxstream