Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 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 | |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 19 | #include "host-common/GfxstreamFatalError.h" |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 20 | |
| 21 | using TaskId = VirtioGpuTimelines::TaskId; |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 22 | using Ring = VirtioGpuTimelines::Ring; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 23 | using FenceId = VirtioGpuTimelines::FenceId; |
| 24 | using AutoLock = android::base::AutoLock; |
Kaiyi Li | 4935d31 | 2022-01-12 16:57:24 -0800 | [diff] [blame] | 25 | using emugl::ABORT_REASON_OTHER; |
| 26 | using emugl::FatalError; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 27 | |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 28 | std::unique_ptr<VirtioGpuTimelines> VirtioGpuTimelines::create(bool withAsyncCallback) { |
| 29 | return std::unique_ptr<VirtioGpuTimelines>(new VirtioGpuTimelines(withAsyncCallback)); |
| 30 | } |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 31 | |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 32 | VirtioGpuTimelines::VirtioGpuTimelines(bool withAsyncCallback) |
| 33 | : mNextId(0), mWithAsyncCallback(withAsyncCallback) {} |
| 34 | |
| 35 | TaskId VirtioGpuTimelines::enqueueTask(const Ring& ring) { |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 36 | AutoLock lock(mLock); |
| 37 | |
| 38 | TaskId id = mNextId++; |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 39 | std::shared_ptr<Task> task(new Task(id, ring), [this](Task* task) { |
Kaiyi Li | 61ebb7e | 2021-09-08 09:02:05 -0700 | [diff] [blame] | 40 | mTaskIdToTask.erase(task->mId); |
| 41 | delete task; |
| 42 | }); |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 43 | mTaskIdToTask[id] = task; |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 44 | mTimelineQueues[ring].emplace_back(std::move(task)); |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 45 | return id; |
| 46 | } |
| 47 | |
Jason Macnak | 96de4eb | 2023-05-10 12:45:16 -0700 | [diff] [blame] | 48 | void VirtioGpuTimelines::enqueueFence(const Ring& ring, FenceId fenceId, |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 49 | FenceCompletionCallback fenceCompletionCallback) { |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 50 | AutoLock lock(mLock); |
| 51 | |
Jason Macnak | fdecd45 | 2023-05-12 15:43:31 -0700 | [diff] [blame] | 52 | auto fence = std::make_unique<Fence>(fenceId, std::move(fenceCompletionCallback)); |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 53 | mTimelineQueues[ring].emplace_back(std::move(fence)); |
| 54 | if (mWithAsyncCallback) { |
| 55 | poll_locked(ring); |
| 56 | } |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | void VirtioGpuTimelines::notifyTaskCompletion(TaskId taskId) { |
| 60 | AutoLock lock(mLock); |
| 61 | auto iTask = mTaskIdToTask.find(taskId); |
| 62 | if (iTask == mTaskIdToTask.end()) { |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 63 | GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| 64 | << "Task(id = " << static_cast<uint64_t>(taskId) << ") can't be found"; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 65 | } |
| 66 | std::shared_ptr<Task> task = iTask->second.lock(); |
| 67 | if (task == nullptr) { |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 68 | GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| 69 | << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been destroyed"; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 70 | } |
| 71 | if (task->mId != taskId) { |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 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); |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 75 | } |
| 76 | if (task->mHasCompleted) { |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 77 | GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| 78 | << "Task(id = " << static_cast<uint64_t>(taskId) << ") has been set to completed."; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 79 | } |
| 80 | task->mHasCompleted = true; |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 81 | if (mWithAsyncCallback) { |
| 82 | poll_locked(task->mRing); |
| 83 | } |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 84 | } |
| 85 | |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 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 | } |
| 96 | void VirtioGpuTimelines::poll_locked(const Ring& ring) { |
| 97 | auto iTimelineQueue = mTimelineQueues.find(ring); |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 98 | if (iTimelineQueue == mTimelineQueues.end()) { |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 99 | GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
Kaiyi Li | 1fdd22e | 2022-03-31 10:17:23 -0700 | [diff] [blame] | 100 | << "Ring(" << to_string(ring) << ") doesn't exist."; |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 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) { |
Jason Macnak | fdecd45 | 2023-05-12 15:43:31 -0700 | [diff] [blame] | 109 | fence->mCompletionCallback(); |
Kaiyi Li | fab5100 | 2021-08-21 15:12:02 -0700 | [diff] [blame] | 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); |
Doug Horn | 0c2ea5a | 2021-10-29 17:30:16 -0700 | [diff] [blame] | 121 | } |