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