• 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 #ifndef VIRTIO_GPU_TIMELINES_H
15 #define VIRTIO_GPU_TIMELINES_H
16 
17 #include <atomic>
18 #include <functional>
19 #include <list>
20 #include <memory>
21 #include <mutex>
22 #include <sstream>
23 #include <string>
24 #include <unordered_map>
25 #include <variant>
26 
27 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
28 #include "VirtioGpuTimelinesSnapshot.pb.h"
29 #endif  // GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
30 #include "aemu/base/ThreadAnnotations.h"
31 #include "gfxstream/virtio-gpu-gfxstream-renderer.h"
32 
33 typedef uint32_t VirtioGpuCtxId;
34 typedef uint8_t VirtioGpuRingIdx;
35 
36 struct VirtioGpuRingGlobal {};
37 struct VirtioGpuRingContextSpecific {
38     VirtioGpuCtxId mCtxId;
39     VirtioGpuRingIdx mRingIdx;
40 };
41 using VirtioGpuRing = std::variant<VirtioGpuRingGlobal, VirtioGpuRingContextSpecific>;
42 
43 template <>
44 struct std::hash<VirtioGpuRingGlobal> {
45     std::size_t operator()(VirtioGpuRingGlobal const&) const noexcept { return 0; }
46 };
47 
48 inline bool operator==(const VirtioGpuRingGlobal&, const VirtioGpuRingGlobal&) { return true; }
49 
50 template <>
51 struct std::hash<VirtioGpuRingContextSpecific> {
52     std::size_t operator()(VirtioGpuRingContextSpecific const& ringContextSpecific) const noexcept {
53         std::size_t ctxHash = std::hash<VirtioGpuCtxId>{}(ringContextSpecific.mCtxId);
54         std::size_t ringHash = std::hash<VirtioGpuRingIdx>{}(ringContextSpecific.mRingIdx);
55         // Use the hash_combine from
56         // https://www.boost.org/doc/libs/1_78_0/boost/container_hash/hash.hpp.
57         std::size_t res = ctxHash;
58         res ^= ringHash + 0x9e3779b9 + (res << 6) + (res >> 2);
59         return res;
60     }
61 };
62 
63 inline bool operator==(const VirtioGpuRingContextSpecific& lhs,
64                        const VirtioGpuRingContextSpecific& rhs) {
65     return lhs.mCtxId == rhs.mCtxId && lhs.mRingIdx == rhs.mRingIdx;
66 }
67 
68 inline std::string to_string(const VirtioGpuRing& ring) {
69     struct {
70         std::string operator()(const VirtioGpuRingGlobal&) { return "global"; }
71         std::string operator()(const VirtioGpuRingContextSpecific& ring) {
72             std::stringstream ss;
73             ss << "context specific {ctx = " << ring.mCtxId << ", ring = " << (int)ring.mRingIdx
74                << "}";
75             return ss.str();
76         }
77     } visitor;
78     return std::visit(visitor, ring);
79 }
80 
81 class VirtioGpuTimelines {
82    public:
83     using FenceId = uint64_t;
84     using Ring = VirtioGpuRing;
85     using TaskId = uint64_t;
86     using FenceCompletionCallback = std::function<void(const Ring&, FenceId)>;
87 
88     static std::unique_ptr<VirtioGpuTimelines> create(FenceCompletionCallback callback);
89 
90     TaskId enqueueTask(const Ring&);
91     void enqueueFence(const Ring&, FenceId);
92     void notifyTaskCompletion(TaskId);
93     void poll();
94 
95 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
96     std::optional<gfxstream::host::snapshot::VirtioGpuTimelinesSnapshot> Snapshot() const;
97 
98     static std::unique_ptr<VirtioGpuTimelines> Restore(
99         FenceCompletionCallback callback,
100         const gfxstream::host::snapshot::VirtioGpuTimelinesSnapshot& snapshot);
101 #endif
102 
103    private:
104     VirtioGpuTimelines(FenceCompletionCallback callback);
105 
106     struct Task {
107         Task(TaskId id, const Ring& ring, uint64_t traceId)
108             : mId(id), mRing(ring), mTraceId(traceId), mHasCompleted(false) {}
109 
110         // LINT.IfChange(virtio_gpu_timeline_task)
111         TaskId mId;
112         Ring mRing;
113         uint64_t mTraceId;
114         std::atomic_bool mHasCompleted;
115         // LINT.ThenChange(VirtioGpuTimelinesSnapshot.proto:virtio_gpu_timeline_task)
116     };
117 
118     // LINT.IfChange(virtio_gpu_timeline_item)
119     using TimelineItem = std::variant<FenceId, std::shared_ptr<Task>>;
120     // LINT.ThenChange(VirtioGpuTimelinesSnapshot.proto:virtio_gpu_timeline_item)
121 
122 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
123     static std::optional<gfxstream::host::snapshot::VirtioGpuTimelineItem> SnapshotTimelineItem(
124         const TimelineItem& timelineItem);
125 
126     static std::optional<TimelineItem> RestoreTimelineItem(
127         const gfxstream::host::snapshot::VirtioGpuTimelineItem& snapshot);
128 #endif
129 
130     struct Timeline {
131         // LINT.IfChange(virtio_gpu_timeline)
132         uint64_t mTraceTrackId;
133         std::list<TimelineItem> mQueue;
134         // LINT.ThenChange(VirtioGpuTimelinesSnapshot.proto:virtio_gpu_timeline)
135 
136 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
137         std::optional<gfxstream::host::snapshot::VirtioGpuTimeline> Snapshot() const;
138 
139         static std::optional<Timeline> Restore(
140             const gfxstream::host::snapshot::VirtioGpuTimeline& snapshot);
141 #endif
142     };
143 
144     Timeline& GetOrCreateTimelineLocked(const Ring& ring) REQUIRES(mTimelinesMutex);
145 
146     // Go over the timeline, signal any fences without pending tasks, and remove
147     // timeline items that are no longer needed.
148     void poll_locked(const Ring&) REQUIRES(mTimelinesMutex);
149 
150     FenceCompletionCallback mFenceCompletionCallback;
151 
152     mutable std::mutex mTimelinesMutex;
153     // The mTaskIdToTask cache must be destroyed after the actual owner of Task,
154     // mTimelineQueues, is destroyed, because the deleter of Task will
155     // automatically remove the entry in mTaskIdToTask.
156     std::unordered_map<TaskId, std::weak_ptr<Task>> mTaskIdToTask;
157 
158     // LINT.IfChange(virtio_gpu_timelines)
159     std::atomic<TaskId> mNextId;
160     std::unordered_map<Ring, Timeline> mTimelineQueues GUARDED_BY(mTimelinesMutex);
161     // LINT.ThenChange(VirtioGpuTimelinesSnapshot.proto:virtio_gpu_timelines)
162 };
163 
164 #endif  // VIRTIO_GPU_TIMELINES_H
165