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 "gfxstream/host/Tracing.h"
20 #include "host-common/GfxstreamFatalError.h"
21
22 using TaskId = VirtioGpuTimelines::TaskId;
23 using Ring = VirtioGpuTimelines::Ring;
24 using FenceId = VirtioGpuTimelines::FenceId;
25 using emugl::ABORT_REASON_OTHER;
26 using emugl::FatalError;
27
create(FenceCompletionCallback callback)28 std::unique_ptr<VirtioGpuTimelines> VirtioGpuTimelines::create(FenceCompletionCallback callback) {
29 return std::unique_ptr<VirtioGpuTimelines>(new VirtioGpuTimelines(std::move(callback)));
30 }
31
VirtioGpuTimelines(FenceCompletionCallback callback)32 VirtioGpuTimelines::VirtioGpuTimelines(FenceCompletionCallback callback)
33 : mNextId(0), mFenceCompletionCallback(std::move(callback)) {}
34
enqueueTask(const Ring & ring)35 TaskId VirtioGpuTimelines::enqueueTask(const Ring& ring) {
36 std::lock_guard<std::mutex> lock(mTimelinesMutex);
37
38 TaskId id = mNextId++;
39
40 const uint64_t traceId = gfxstream::host::GetUniqueTracingId();
41 GFXSTREAM_TRACE_EVENT_INSTANT(GFXSTREAM_TRACE_VIRTIO_GPU_TIMELINE_CATEGORY,
42 "Queue timeline task", "Task ID", id,
43 GFXSTREAM_TRACE_FLOW(traceId));
44
45 std::shared_ptr<Task> task(new Task(id, ring, traceId), [this](Task* task) {
46 mTaskIdToTask.erase(task->mId);
47 delete task;
48 });
49 mTaskIdToTask[id] = task;
50
51 Timeline& timeline = GetOrCreateTimelineLocked(ring);
52 timeline.mQueue.emplace_back(std::move(task));
53 return id;
54 }
55
enqueueFence(const Ring & ring,FenceId fenceId)56 void VirtioGpuTimelines::enqueueFence(const Ring& ring, FenceId fenceId) {
57 std::lock_guard<std::mutex> lock(mTimelinesMutex);
58
59 Timeline& timeline = GetOrCreateTimelineLocked(ring);
60 timeline.mQueue.emplace_back(fenceId);
61
62 poll_locked(ring);
63 }
64
notifyTaskCompletion(TaskId taskId)65 void VirtioGpuTimelines::notifyTaskCompletion(TaskId taskId) {
66 std::lock_guard<std::mutex> lock(mTimelinesMutex);
67 auto iTask = mTaskIdToTask.find(taskId);
68 if (iTask == mTaskIdToTask.end()) {
69 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
70 << "Task(id = " << static_cast<uint64_t>(taskId) << ") can't be found";
71 }
72 std::shared_ptr<Task> task = iTask->second.lock();
73 if (task == nullptr) {
74 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
75 << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been destroyed";
76 }
77 if (task->mId != taskId) {
78 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
79 << "Task id mismatch. Expected " << static_cast<uint64_t>(taskId) << " Actual "
80 << static_cast<uint64_t>(task->mId);
81 }
82 if (task->mHasCompleted) {
83 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
84 << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been set to completed.";
85 }
86
87 GFXSTREAM_TRACE_EVENT_INSTANT(GFXSTREAM_TRACE_VIRTIO_GPU_TIMELINE_CATEGORY,
88 "Notify timeline task completed",
89 GFXSTREAM_TRACE_FLOW(task->mTraceId), "Task ID", task->mId);
90
91 task->mHasCompleted = true;
92
93 poll_locked(task->mRing);
94 }
95
GetOrCreateTimelineLocked(const Ring & ring)96 VirtioGpuTimelines::Timeline& VirtioGpuTimelines::GetOrCreateTimelineLocked(const Ring& ring) {
97 auto [it, inserted] =
98 mTimelineQueues.emplace(std::piecewise_construct, std::make_tuple(ring), std::make_tuple());
99 Timeline& timeline = it->second;
100 if (inserted) {
101 timeline.mTraceTrackId = gfxstream::host::GetUniqueTracingId();
102
103 const std::string timelineName = "Virtio Gpu Timeline " + to_string(ring);
104 GFXSTREAM_TRACE_NAME_TRACK(GFXSTREAM_TRACE_TRACK(timeline.mTraceTrackId), timelineName);
105
106 GFXSTREAM_TRACE_EVENT_INSTANT(GFXSTREAM_TRACE_VIRTIO_GPU_TIMELINE_CATEGORY,
107 "Create Timeline",
108 GFXSTREAM_TRACE_TRACK(timeline.mTraceTrackId));
109 }
110
111 return timeline;
112 }
113
poll()114 void VirtioGpuTimelines::poll() {
115 std::lock_guard<std::mutex> lock(mTimelinesMutex);
116 for (const auto& [ring, timeline] : mTimelineQueues) {
117 poll_locked(ring);
118 }
119 }
poll_locked(const Ring & ring)120 void VirtioGpuTimelines::poll_locked(const Ring& ring) {
121 auto timelineIt = mTimelineQueues.find(ring);
122 if (timelineIt == mTimelineQueues.end()) {
123 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
124 << "Ring(" << to_string(ring) << ") doesn't exist.";
125 }
126 Timeline& timeline = timelineIt->second;
127
128 auto& timelineQueue = timeline.mQueue;
129 auto i = timelineQueue.begin();
130 for (; i != timelineQueue.end(); i++) {
131 bool shouldStop = std::visit(
132 [&](auto& arg) {
133 using T = std::decay_t<decltype(arg)>;
134 if constexpr (std::is_same_v<T, FenceId>) {
135 auto& fenceId = arg;
136
137 GFXSTREAM_TRACE_EVENT_INSTANT(
138 GFXSTREAM_TRACE_VIRTIO_GPU_TIMELINE_CATEGORY, "Signal Virtio Gpu Fence",
139 GFXSTREAM_TRACE_TRACK(timeline.mTraceTrackId), "Fence", fenceId);
140
141 mFenceCompletionCallback(ring, fenceId);
142
143 return false;
144 } else if constexpr (std::is_same_v<T, std::shared_ptr<Task>>) {
145 auto& task = arg;
146
147 const bool completed = task->mHasCompleted;
148 if (completed) {
149 GFXSTREAM_TRACE_EVENT_INSTANT(
150 GFXSTREAM_TRACE_VIRTIO_GPU_TIMELINE_CATEGORY, "Process Task Complete",
151 GFXSTREAM_TRACE_TRACK(timeline.mTraceTrackId),
152 GFXSTREAM_TRACE_FLOW(task->mTraceId), "Task", task->mId);
153 }
154 return !completed;
155 }
156 },
157 *i);
158
159 if (shouldStop) {
160 break;
161 }
162 }
163 timelineQueue.erase(timelineQueue.begin(), i);
164 }
165