• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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