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 "VkMemory.h"
20
21 #include "System/Debug.hpp"
22
23 #include <Vulkan/VulkanPlatform.h>
24 #include <vulkan/vk_icd.h>
25 #include <new>
26
27 namespace vk {
28
29 template<typename T, typename VkT>
VkTtoT(VkT vkObject)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>
TtoVkT(T * object)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>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject,ExtendedInfo...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
destroy(const VkAllocationCallbacks * pAllocator)89 void destroy(const VkAllocationCallbacks *pAllocator) {} // Method defined by objects to delete their content, if necessary
90
91 template<typename CreateInfo, typename... ExtendedInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject,ExtendedInfo...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
GetAllocationScope()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:
operator VkT()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
Cast(VkT vkObject)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:
GetAllocationScope()125 static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
126
127 template<typename... Args>
DispatchableObject(Args...args)128 DispatchableObject(Args... args)
129 : object(args...)
130 {
131 }
132
133 ~DispatchableObject() = delete;
134
destroy(const VkAllocationCallbacks * pAllocator)135 void destroy(const VkAllocationCallbacks *pAllocator)
136 {
137 object.destroy(pAllocator);
138 }
139
operator delete(void * ptr,const VkAllocationCallbacks * pAllocator)140 void operator delete(void *ptr, const VkAllocationCallbacks *pAllocator)
141 {
142 // Should never happen
143 ASSERT(false);
144 }
145
146 template<typename CreateInfo, typename... ExtendedInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject,ExtendedInfo...extendedInfo)147 static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo)
148 {
149 return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...);
150 }
151
152 template<typename CreateInfo>
ComputeRequiredAllocationSize(const CreateInfo * pCreateInfo)153 static size_t ComputeRequiredAllocationSize(const CreateInfo *pCreateInfo)
154 {
155 return T::ComputeRequiredAllocationSize(pCreateInfo);
156 }
157
Cast(VkT vkObject)158 static inline T *Cast(VkT vkObject)
159 {
160 return (vkObject == VK_NULL_HANDLE) ? nullptr : &(reinterpret_cast<DispatchableObject<T, VkT> *>(vkObject)->object);
161 }
162
operator VkT()163 operator VkT()
164 {
165 return reinterpret_cast<VkT>(this);
166 }
167 };
168
169 } // namespace vk
170
171 #endif // VK_OBJECT_HPP_
172