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