• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2025 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 
15 #pragma once
16 
17 #include <deque>
18 #include <mutex>
19 
20 #include "VulkanDispatch.h"
21 #include "VulkanHandles.h"
22 #include "VulkanStream.h"
23 #include "aemu/base/ThreadAnnotations.h"
24 #include "aemu/base/containers/HybridEntityManager.h"
25 #include "aemu/base/containers/Lookup.h"
26 #include "aemu/base/synchronization/ConditionVariable.h"
27 #include "aemu/base/synchronization/Lock.h"
28 
29 namespace gfxstream {
30 namespace vk {
31 
32 #define DEFINE_BOXED_HANDLE_TYPE_TAG(type) Tag_##type,
33 
34 enum BoxedHandleTypeTag {
35     Tag_Invalid = 0,
36 
37     GOLDFISH_VK_LIST_HANDLE_TYPES_BY_STAGE(DEFINE_BOXED_HANDLE_TYPE_TAG)
38 
39     // additional generic tag
40     Tag_VkGeneric = 1001,
41 };
42 
43 using BoxedHandle = uint64_t;
44 using UnboxedHandle = uint64_t;
45 
46 struct OrderMaintenanceInfo {
47     uint32_t sequenceNumber = 0;
48     android::base::Lock lock;
49     android::base::ConditionVariable cv;
50 
51     uint32_t refcount = 1;
52 
incRefOrderMaintenanceInfo53     void incRef() { __atomic_add_fetch(&refcount, 1, __ATOMIC_SEQ_CST); }
54 
decRefOrderMaintenanceInfo55     bool decRef() { return 0 == __atomic_sub_fetch(&refcount, 1, __ATOMIC_SEQ_CST); }
56 };
57 
acquireOrderMaintInfo(OrderMaintenanceInfo * ord)58 inline void acquireOrderMaintInfo(OrderMaintenanceInfo* ord) {
59     if (!ord) return;
60     ord->incRef();
61 }
62 
releaseOrderMaintInfo(OrderMaintenanceInfo * ord)63 inline void releaseOrderMaintInfo(OrderMaintenanceInfo* ord) {
64     if (!ord) return;
65     if (ord->decRef()) delete ord;
66 }
67 
68 class BoxedHandleInfo {
69    public:
70     UnboxedHandle underlying;
71     VulkanDispatch* dispatch = nullptr;
72     bool ownDispatch = false;
73     OrderMaintenanceInfo* ordMaintInfo = nullptr;
74     VulkanMemReadingStream* readStream = nullptr;
75 };
76 
77 class BoxedHandleManager {
78    public:
79     // The hybrid entity manager uses a sequence lock to protect access to
80     // a working set of 16000 handles, allowing us to avoid using a regular
81     // lock for those. Performance is degraded when going over this number,
82     // as it will then fall back to a std::map.
83     //
84     // We use 16000 as the max number of live handles to track; we don't
85     // expect the system to go over 16000 total live handles, outside some
86     // dEQP object management tests.
87     using Store = android::base::HybridEntityManager<16000, BoxedHandle, BoxedHandleInfo>;
88 
89     BoxedHandle add(const BoxedHandleInfo& item, BoxedHandleTypeTag tag);
90 
91     void update(BoxedHandle handle, const BoxedHandleInfo& item, BoxedHandleTypeTag tag);
92 
93     void remove(BoxedHandle h);
94     void removeDelayed(uint64_t h, VkDevice device, std::function<void()> callback);
95 
96     // Do not call directly! Instead use `processDelayedRemovesForDevice()` which has
97     // thread safety annotations for `VkDecoderGlobalState::Impl`.
98     void processDelayedRemoves(VkDevice device);
99 
100     BoxedHandleInfo* get(BoxedHandle handle);
101     BoxedHandle getBoxedFromUnboxed(UnboxedHandle unboxed);
102 
103     void replayHandles(std::vector<BoxedHandle> handles);
104 
105     void clear();
106 
107    private:
108     mutable Store mStore;
109 
110     std::mutex mMutex;
111     std::unordered_map<UnboxedHandle, BoxedHandle> mReverseMap GUARDED_BY(mMutex);
112 
113     struct DelayedRemove {
114         BoxedHandle handle;
115         std::function<void()> callback;
116     };
117     std::unordered_map<VkDevice, std::vector<DelayedRemove>> mDelayedRemoves GUARDED_BY(mMutex);
118 
119     // If true, `add()` will use and consume the handles in `mHandleReplayQueue`.
120     // This is useful for snapshot loading when a explicit set of handles should
121     // be used when replaying commands.
122     bool mHandleReplay = false;
123     std::deque<BoxedHandle> mHandleReplayQueue;
124 };
125 
126 extern BoxedHandleManager sBoxedHandleManager;
127 
128 #define DEFINE_BOXED_DISPATCHABLE_HANDLE_API_DECL(type)                                 \
129     type new_boxed_##type(type underlying, VulkanDispatch* dispatch, bool ownDispatch); \
130     void delete_##type(type boxed);                                                     \
131     type unbox_##type(type boxed);                                                      \
132     type try_unbox_##type(type boxed);                                                  \
133     type unboxed_to_boxed_##type(type boxed);                                           \
134     VulkanDispatch* dispatch_##type(type boxed);                                        \
135     OrderMaintenanceInfo* ordmaint_##type(type boxed);                                  \
136     VulkanMemReadingStream* readstream_##type(type boxed);
137 
138 #define DEFINE_BOXED_NON_DISPATCHABLE_HANDLE_API_DECL(type)                                  \
139     type new_boxed_non_dispatchable_##type(type underlying);                                 \
140     void delete_##type(type boxed);                                                          \
141     void delayed_delete_##type(type boxed, VkDevice device, std::function<void()> callback); \
142     type unbox_##type(type boxed);                                                           \
143     type try_unbox_##type(type boxed);                                                       \
144     type unboxed_to_boxed_non_dispatchable_##type(type boxed);                               \
145     void set_boxed_non_dispatchable_##type(type boxed, type underlying);
146 
147 GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(DEFINE_BOXED_DISPATCHABLE_HANDLE_API_DECL)
148 GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(DEFINE_BOXED_NON_DISPATCHABLE_HANDLE_API_DECL)
149 
150 }  // namespace vk
151 }  // namespace gfxstream
152