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