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 "VirtioGpuTimelines.h"
15
16 #include <cinttypes>
17 #include <cstdio>
18
19 #include "host-common/GfxstreamFatalError.h"
20
21 using TaskId = VirtioGpuTimelines::TaskId;
22 using Ring = VirtioGpuTimelines::Ring;
23 using FenceId = VirtioGpuTimelines::FenceId;
24 using AutoLock = android::base::AutoLock;
25 using emugl::ABORT_REASON_OTHER;
26 using emugl::FatalError;
27
create(bool withAsyncCallback)28 std::unique_ptr<VirtioGpuTimelines> VirtioGpuTimelines::create(bool withAsyncCallback) {
29 return std::unique_ptr<VirtioGpuTimelines>(new VirtioGpuTimelines(withAsyncCallback));
30 }
31
VirtioGpuTimelines(bool withAsyncCallback)32 VirtioGpuTimelines::VirtioGpuTimelines(bool withAsyncCallback)
33 : mNextId(0), mWithAsyncCallback(withAsyncCallback) {}
34
enqueueTask(const Ring & ring)35 TaskId VirtioGpuTimelines::enqueueTask(const Ring& ring) {
36 AutoLock lock(mLock);
37
38 TaskId id = mNextId++;
39 std::shared_ptr<Task> task(new Task(id, ring), [this](Task* task) {
40 mTaskIdToTask.erase(task->mId);
41 delete task;
42 });
43 mTaskIdToTask[id] = task;
44 mTimelineQueues[ring].emplace_back(std::move(task));
45 return id;
46 }
47
enqueueFence(const Ring & ring,FenceId fenceId,FenceCompletionCallback fenceCompletionCallback)48 void VirtioGpuTimelines::enqueueFence(const Ring& ring, FenceId fenceId,
49 FenceCompletionCallback fenceCompletionCallback) {
50 AutoLock lock(mLock);
51
52 auto fence = std::make_unique<Fence>(fenceId, std::move(fenceCompletionCallback));
53 mTimelineQueues[ring].emplace_back(std::move(fence));
54 if (mWithAsyncCallback) {
55 poll_locked(ring);
56 }
57 }
58
notifyTaskCompletion(TaskId taskId)59 void VirtioGpuTimelines::notifyTaskCompletion(TaskId taskId) {
60 AutoLock lock(mLock);
61 auto iTask = mTaskIdToTask.find(taskId);
62 if (iTask == mTaskIdToTask.end()) {
63 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
64 << "Task(id = " << static_cast<uint64_t>(taskId) << ") can't be found";
65 }
66 std::shared_ptr<Task> task = iTask->second.lock();
67 if (task == nullptr) {
68 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
69 << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been destroyed";
70 }
71 if (task->mId != taskId) {
72 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
73 << "Task id mismatch. Expected " << static_cast<uint64_t>(taskId) << " Actual "
74 << static_cast<uint64_t>(task->mId);
75 }
76 if (task->mHasCompleted) {
77 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
78 << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been set to completed.";
79 }
80 task->mHasCompleted = true;
81 if (mWithAsyncCallback) {
82 poll_locked(task->mRing);
83 }
84 }
85
poll()86 void VirtioGpuTimelines::poll() {
87 if (mWithAsyncCallback) {
88 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
89 << "Can't call poll with async callback enabled.";
90 }
91 AutoLock lock(mLock);
92 for (const auto& [ring, timeline] : mTimelineQueues) {
93 poll_locked(ring);
94 }
95 }
poll_locked(const Ring & ring)96 void VirtioGpuTimelines::poll_locked(const Ring& ring) {
97 auto iTimelineQueue = mTimelineQueues.find(ring);
98 if (iTimelineQueue == mTimelineQueues.end()) {
99 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
100 << "Ring(" << to_string(ring) << ") doesn't exist.";
101 }
102 std::list<TimelineItem> &timelineQueue = iTimelineQueue->second;
103 auto i = timelineQueue.begin();
104 for (; i != timelineQueue.end(); i++) {
105 // This visitor will signal the fence and return whether the timeline
106 // item is an incompleted task.
107 struct {
108 bool operator()(std::unique_ptr<Fence> &fence) {
109 fence->mCompletionCallback();
110 return false;
111 }
112 bool operator()(std::shared_ptr<Task> &task) {
113 return !task->mHasCompleted;
114 }
115 } visitor;
116 if (std::visit(visitor, *i)) {
117 break;
118 }
119 }
120 timelineQueue.erase(timelineQueue.begin(), i);
121 }
122