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