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 #include <vulkan/vulkan.h>
22 #include <vulkan/vk_icd.h>
23 
24 namespace vk
25 {
26 // For use in the placement new to make it verbose that we're allocating an object using device memory
27 static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;
28 
29 template<typename T, typename VkT, typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)30 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
31 {
32 	*outObject = VK_NULL_HANDLE;
33 
34 	size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
35 	void* memory = nullptr;
36 	if(size)
37 	{
38 		memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
39 		if(!memory)
40 		{
41 			return VK_ERROR_OUT_OF_HOST_MEMORY;
42 		}
43 	}
44 
45 	auto object = new (pAllocator) T(pCreateInfo, memory);
46 
47 	if(!object)
48 	{
49 		vk::deallocate(memory, pAllocator);
50 		return VK_ERROR_OUT_OF_HOST_MEMORY;
51 	}
52 
53 	*outObject = *object;
54 
55 	return VK_SUCCESS;
56 }
57 
58 template<typename T, typename VkT>
59 class ObjectBase
60 {
61 public:
62 	using VkType = VkT;
63 
destroy(const VkAllocationCallbacks * pAllocator)64 	void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary
65 
operator new(size_t count,const VkAllocationCallbacks * pAllocator)66 	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
67 	{
68 		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
69 	}
70 
operator delete(void * ptr,const VkAllocationCallbacks * pAllocator)71 	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
72 	{
73 		// Should never happen
74 		ASSERT(false);
75 	}
76 
77 	template<typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)78 	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
79 	{
80 		return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
81 	}
82 
GetAllocationScope()83 	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
84 
85 protected:
86 	// All derived classes should have deleted destructors
~ObjectBase()87 	~ObjectBase() {}
88 };
89 
90 template<typename T, typename VkT>
91 class Object : public ObjectBase<T, VkT>
92 {
93 public:
operator VkT()94 	operator VkT()
95 	{
96 		return reinterpret_cast<VkT>(this);
97 	}
98 };
99 
100 template<typename T, typename VkT>
101 class DispatchableObject
102 {
103 	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
104 
105 	T object;
106 public:
GetAllocationScope()107 	static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
108 
109 	template<typename ...Args>
DispatchableObject(Args...args)110 	DispatchableObject(Args... args) : object(args...)
111 	{
112 	}
113 
114 	~DispatchableObject() = delete;
115 
destroy(const VkAllocationCallbacks * pAllocator)116 	void destroy(const VkAllocationCallbacks* pAllocator)
117 	{
118 		object.destroy(pAllocator);
119 	}
120 
operator new(size_t count,const VkAllocationCallbacks * pAllocator)121 	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
122 	{
123 		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
124 	}
125 
operator delete(void * ptr,const VkAllocationCallbacks * pAllocator)126 	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
127 	{
128 		// Should never happen
129 		ASSERT(false);
130 	}
131 
132 	template<typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)133 	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
134 	{
135 		return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
136 	}
137 
138 	template<typename CreateInfo>
ComputeRequiredAllocationSize(const CreateInfo * pCreateInfo)139 	static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
140 	{
141 		return T::ComputeRequiredAllocationSize(pCreateInfo);
142 	}
143 
Cast(VkT vkObject)144 	static inline T* Cast(VkT vkObject)
145 	{
146 		return &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
147 	}
148 
operator VkT()149 	operator VkT()
150 	{
151 		return reinterpret_cast<VkT>(this);
152 	}
153 };
154 
155 } // namespace vk
156 
157 #endif // VK_OBJECT_HPP_
158