1 | // Copyright 2018 The SwiftShader Authors. All Rights Reserved. |
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 | #ifndef VK_OBJECT_HPP_ |
16 | #define VK_OBJECT_HPP_ |
17 | |
18 | #include "VkConfig.h" |
19 | #include "VkDebug.hpp" |
20 | #include "VkMemory.h" |
21 | |
22 | #include <new> |
23 | #include <Vulkan/VulkanPlatform.h> |
24 | #include <vulkan/vk_icd.h> |
25 | |
26 | namespace vk |
27 | { |
28 | |
29 | template<typename T, typename VkT> |
30 | static inline T* VkTtoT(VkT vkObject) |
31 | { |
32 | return static_cast<T*>(static_cast<void*>(vkObject)); |
33 | } |
34 | |
35 | template<typename T, typename VkT> |
36 | static inline VkT TtoVkT(T* object) |
37 | { |
38 | return { static_cast<uint64_t>(reinterpret_cast<uintptr_t>(object)) }; |
39 | } |
40 | |
41 | // For use in the placement new to make it verbose that we're allocating an object using device memory |
42 | static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr; |
43 | |
44 | template<typename T, typename VkT, typename CreateInfo, typename... ExtendedInfo> |
45 | static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo) |
46 | { |
47 | *outObject = VK_NULL_HANDLE; |
48 | |
49 | size_t size = T::ComputeRequiredAllocationSize(pCreateInfo); |
50 | void* memory = nullptr; |
51 | if(size) |
52 | { |
53 | memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope()); |
54 | if(!memory) |
55 | { |
56 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
57 | } |
58 | } |
59 | |
60 | void* objectMemory = vk::allocate(sizeof(T), alignof(T), pAllocator, T::GetAllocationScope()); |
61 | if(!objectMemory) |
62 | { |
63 | vk::deallocate(memory, pAllocator); |
64 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
65 | } |
66 | |
67 | auto object = new (objectMemory) T(pCreateInfo, memory, extendedInfo...); |
68 | |
69 | if(!object) |
70 | { |
71 | vk::deallocate(memory, pAllocator); |
72 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
73 | } |
74 | |
75 | *outObject = *object; |
76 | |
77 | // Assert that potential v-table offsets from multiple inheritance aren't causing an offset on the handle |
78 | ASSERT(*outObject == objectMemory); |
79 | |
80 | return VK_SUCCESS; |
81 | } |
82 | |
83 | template<typename T, typename VkT> |
84 | class ObjectBase |
85 | { |
86 | public: |
87 | using VkType = VkT; |
88 | |
89 | void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary |
90 | |
91 | template<typename CreateInfo, typename... ExtendedInfo> |
92 | static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo) |
93 | { |
94 | return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...); |
95 | } |
96 | |
97 | static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; } |
98 | }; |
99 | |
100 | template<typename T, typename VkT> |
101 | class Object : public ObjectBase<T, VkT> |
102 | { |
103 | public: |
104 | operator VkT() |
105 | { |
106 | // The static_cast<T*> is used to make sure the returned pointer points to the |
107 | // beginning of the object, even if the derived class uses multiple inheritance |
108 | return vk::TtoVkT<T, VkT>(static_cast<T*>(this)); |
109 | } |
110 | |
111 | static inline T* Cast(VkT vkObject) |
112 | { |
113 | return vk::VkTtoT<T, VkT>(vkObject); |
114 | } |
115 | }; |
116 | |
117 | template<typename T, typename VkT> |
118 | class DispatchableObject |
119 | { |
120 | VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC }; |
121 | |
122 | T object; |
123 | |
124 | public: |
125 | static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); } |
126 | |
127 | template<typename ...Args> |
128 | DispatchableObject(Args... args) : object(args...) |
129 | { |
130 | } |
131 | |
132 | ~DispatchableObject() = delete; |
133 | |
134 | void destroy(const VkAllocationCallbacks* pAllocator) |
135 | { |
136 | object.destroy(pAllocator); |
137 | } |
138 | |
139 | void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator) |
140 | { |
141 | // Should never happen |
142 | ASSERT(false); |
143 | } |
144 | |
145 | template<typename CreateInfo, typename... ExtendedInfo> |
146 | static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo) |
147 | { |
148 | return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...); |
149 | } |
150 | |
151 | template<typename CreateInfo> |
152 | static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo) |
153 | { |
154 | return T::ComputeRequiredAllocationSize(pCreateInfo); |
155 | } |
156 | |
157 | static inline T* Cast(VkT vkObject) |
158 | { |
159 | return (vkObject == VK_NULL_HANDLE) ? nullptr : |
160 | &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object); |
161 | } |
162 | |
163 | operator VkT() |
164 | { |
165 | return reinterpret_cast<VkT>(this); |
166 | } |
167 | }; |
168 | |
169 | } // namespace vk |
170 | |
171 | #endif // VK_OBJECT_HPP_ |
172 | |