1 #ifndef _VKREF_HPP
2 #define _VKREF_HPP
3 /*-------------------------------------------------------------------------
4  * Vulkan CTS Framework
5  * --------------------
6  *
7  * Copyright (c) 2015 Google Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Vulkan object reference holder.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vkDefs.hpp"
27 #include "vkStrUtil.hpp"
28 #include "deMeta.hpp"
29 
30 #include <algorithm>
31 
32 namespace vk
33 {
34 
35 namespace refdetails
36 {
37 
38 using std::swap;
39 
40 template<typename T>
41 struct Checked
42 {
Checkedvk::refdetails::Checked43 	explicit inline		Checked		(T object_) : object(object_) {}
44 
45 	T					object;
46 };
47 
48 //! Check that object is not null
49 template<typename T>
check(T object)50 inline Checked<T> check (T object)
51 {
52 	if (!object)
53 		throw tcu::TestError("Object check() failed", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
54 	return Checked<T>(object);
55 }
56 
57 //! Declare object as checked earlier
58 template<typename T>
notNull(T object)59 inline Checked<T> notNull (T object)
60 {
61 	if (!object)
62 		throw tcu::InternalError("Null object was given to notNull()", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
63 	return Checked<T>(object);
64 }
65 
66 //! Allow null object
67 template<typename T>
allowNull(T object)68 inline Checked<T> allowNull (T object)
69 {
70 	return Checked<T>(object);
71 }
72 
73 template<typename T>
74 class Deleter
75 {
76 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,const VkAllocationCallbacks * allocator)77 									Deleter		(const DeviceInterface& deviceIface, VkDevice device, const VkAllocationCallbacks* allocator)
78 										: m_deviceIface	(&deviceIface)
79 										, m_device		(device)
80 										, m_allocator	(allocator)
81 									{}
Deleter(void)82 									Deleter		(void)
83 										: m_deviceIface	(DE_NULL)
84 										, m_device		(DE_NULL)
85 										, m_allocator	(DE_NULL)
86 									{}
87 
88 	void							operator()	(T obj) const;
89 
90 private:
91 	const DeviceInterface*			m_deviceIface;
92 	VkDevice						m_device;
93 	const VkAllocationCallbacks*	m_allocator;
94 };
95 
96 template<>
97 class Deleter<VkInstance>
98 {
99 public:
Deleter(const PlatformInterface & platformIface,VkInstance instance,const VkAllocationCallbacks * allocator)100 									Deleter		(const PlatformInterface& platformIface, VkInstance instance, const VkAllocationCallbacks* allocator)
101 										: m_destroyInstance	((DestroyInstanceFunc)platformIface.getInstanceProcAddr(instance, "vkDestroyInstance"))
102 										, m_allocator		(allocator)
103 									{}
Deleter(void)104 									Deleter		(void)
105 										: m_destroyInstance	((DestroyInstanceFunc)DE_NULL)
106 										, m_allocator		(DE_NULL)
107 									{}
108 
operator ()(VkInstance obj) const109 	void							operator()	(VkInstance obj) const { m_destroyInstance(obj, m_allocator); }
110 
111 private:
112 	DestroyInstanceFunc				m_destroyInstance;
113 	const VkAllocationCallbacks*	m_allocator;
114 };
115 
116 template<>
117 class Deleter<VkDevice>
118 {
119 public:
Deleter(const InstanceInterface & instanceIface,VkDevice device,const VkAllocationCallbacks * allocator)120 									Deleter		(const InstanceInterface& instanceIface, VkDevice device, const VkAllocationCallbacks* allocator)
121 										: m_destroyDevice	((DestroyDeviceFunc)instanceIface.getDeviceProcAddr(device, "vkDestroyDevice"))
122 										, m_allocator		(allocator)
123 									{}
Deleter(void)124 									Deleter		(void)
125 										: m_destroyDevice	((DestroyDeviceFunc)DE_NULL)
126 										, m_allocator		(DE_NULL)
127 									{}
128 
operator ()(VkDevice obj) const129 	void							operator()	(VkDevice obj) const { m_destroyDevice(obj, m_allocator); }
130 
131 private:
132 	DestroyDeviceFunc				m_destroyDevice;
133 	const VkAllocationCallbacks*	m_allocator;
134 };
135 
136 template<>
137 class Deleter<VkSurfaceKHR>
138 {
139 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)140 									Deleter		(const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
141 										: m_instanceIface	(&instanceIface)
142 										, m_instance		(instance)
143 										, m_allocator		(allocator)
144 									{}
Deleter(void)145 									Deleter		(void)
146 										: m_instanceIface	(DE_NULL)
147 										, m_instance		((VkInstance)0)
148 										, m_allocator		(DE_NULL)
149 									{}
150 
operator ()(VkSurfaceKHR obj) const151 	void							operator()	(VkSurfaceKHR obj) const { m_instanceIface->destroySurfaceKHR(m_instance, obj, m_allocator); }
152 
153 private:
154 	const InstanceInterface*		m_instanceIface;
155 	VkInstance						m_instance;
156 	const VkAllocationCallbacks*	m_allocator;
157 };
158 
159 template<>
160 class Deleter<VkDebugReportCallbackEXT>
161 {
162 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)163 									Deleter		(const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
164 										: m_instanceIface	(&instanceIface)
165 										, m_instance		(instance)
166 										, m_allocator		(allocator)
167 									{}
Deleter(void)168 									Deleter		(void)
169 										: m_instanceIface	(DE_NULL)
170 										, m_instance		((VkInstance)0)
171 										, m_allocator		(DE_NULL)
172 									{}
173 
operator ()(VkDebugReportCallbackEXT obj) const174 	void							operator()	(VkDebugReportCallbackEXT obj) const { m_instanceIface->destroyDebugReportCallbackEXT(m_instance, obj, m_allocator); }
175 
176 private:
177 	const InstanceInterface*		m_instanceIface;
178 	VkInstance						m_instance;
179 	const VkAllocationCallbacks*	m_allocator;
180 };
181 
182 template<>
183 class Deleter<VkDescriptorSet>
184 {
185 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkDescriptorPool pool)186 							Deleter		(const DeviceInterface& deviceIface, VkDevice device, VkDescriptorPool pool)
187 								: m_deviceIface	(&deviceIface)
188 								, m_device		(device)
189 								, m_pool		(pool)
190 							{}
Deleter(void)191 							Deleter		(void)
192 								: m_deviceIface	(DE_NULL)
193 								, m_device		(DE_NULL)
194 								, m_pool		(DE_NULL)
195 							{}
196 
operator ()(VkDescriptorSet obj) const197 	void					operator()	(VkDescriptorSet obj) const { m_deviceIface->freeDescriptorSets(m_device, m_pool, 1, &obj); }
198 
199 private:
200 	const DeviceInterface*	m_deviceIface;
201 	VkDevice				m_device;
202 	VkDescriptorPool		m_pool;
203 };
204 
205 template<>
206 class Deleter<VkCommandBuffer>
207 {
208 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkCommandPool pool)209 							Deleter		(const DeviceInterface& deviceIface, VkDevice device, VkCommandPool pool)
210 								: m_deviceIface	(&deviceIface)
211 								, m_device		(device)
212 								, m_pool		(pool)
213 							{}
Deleter(void)214 							Deleter		(void)
215 								: m_deviceIface	(DE_NULL)
216 								, m_device		(DE_NULL)
217 								, m_pool		(DE_NULL)
218 							{}
219 
operator ()(VkCommandBuffer obj) const220 	void					operator()	(VkCommandBuffer obj) const { m_deviceIface->freeCommandBuffers(m_device, m_pool, 1, &obj); }
221 
222 private:
223 	const DeviceInterface*	m_deviceIface;
224 	VkDevice				m_device;
225 	VkCommandPool			m_pool;
226 };
227 
228 template<typename T>
229 struct RefData
230 {
RefDatavk::refdetails::RefData231 				RefData		(T object_, Deleter<T> deleter_)
232 								: object	(object_)
233 								, deleter	(deleter_)
234 				{}
RefDatavk::refdetails::RefData235 				RefData		(void)
236 								: object	(0)
237 				{}
238 
239 	T			object;
240 	Deleter<T>	deleter;
241 };
242 
243 template<typename T>
244 class RefBase
245 {
246 public:
247 						~RefBase	(void);
248 
get(void) const249 	inline const T&		get			(void) const throw() { return m_data.object;	}
operator *(void) const250 	inline const T&		operator*	(void) const throw() { return get();			}
operator bool(void) const251 	inline operator		bool		(void) const throw() { return !!get();			}
252 
253 protected:
RefBase(RefData<T> data)254 						RefBase		(RefData<T> data) : m_data(data)	{}
255 
256 	void				reset		(void);				//!< Release previous object, set to null.
257 	RefData<T>			disown		(void) throw();		//!< Disown and return object (ownership transferred to caller).
258 	void				assign		(RefData<T> data);	//!< Set new pointer, release previous pointer.
259 
260 private:
261 	RefData<T>			m_data;
262 };
263 
264 template<typename T>
~RefBase(void)265 inline RefBase<T>::~RefBase (void)
266 {
267 	this->reset();
268 }
269 
270 template<typename T>
reset(void)271 inline void RefBase<T>::reset (void)
272 {
273 	if (!!m_data.object)
274 		m_data.deleter(m_data.object);
275 
276 	m_data = RefData<T>();
277 }
278 
279 template<typename T>
disown(void)280 inline RefData<T> RefBase<T>::disown (void) throw()
281 {
282 	RefData<T> tmp;
283 	swap(m_data, tmp);
284 	return tmp;
285 }
286 
287 template<typename T>
assign(RefData<T> data)288 inline void RefBase<T>::assign (RefData<T> data)
289 {
290 	this->reset();
291 	m_data = data;
292 }
293 
294 /*--------------------------------------------------------------------*//*!
295  * \brief Movable Vulkan object reference.
296  *
297  * Similar to de::MovePtr.
298  *//*--------------------------------------------------------------------*/
299 template<typename T>
300 class Move : public RefBase<T>
301 {
302 public:
303 	template<typename U>
Move(Checked<U> object,Deleter<U> deleter)304 				Move		(Checked<U> object, Deleter<U> deleter)
305 								: RefBase<T>(RefData<T>(object.object, deleter))
306 				{}
307 
Move(RefData<T> data)308 				Move		(RefData<T> data)
309 								: RefBase<T>(data)
310 				{}
Move(Move<T> & other)311 				Move		(Move<T>& other)
312 								: RefBase<T>(other.RefBase<T>::disown())
313 				{}
Move(void)314 				Move		(void)
315 								: RefBase<T>(RefData<T>())
316 				{}
317 
disown(void)318 	T			disown		(void) { return this->RefBase<T>::disown().object; }
319 	Move<T>&	operator=	(Move<T>& other);
320 	Move<T>&	operator=	(RefData<T> data);
321 
operator RefData<T>(void)322 	operator	RefData<T>	(void) { return this->RefBase<T>::disown(); }
323 };
324 
325 template<typename T>
operator =(Move<T> & other)326 inline Move<T>& Move<T>::operator= (Move<T>& other)
327 {
328 	if (this != &other)
329 		this->assign(other.RefBase<T>::disown());
330 
331 	return *this;
332 }
333 
334 template<typename T>
operator =(RefData<T> data)335 inline Move<T>& Move<T>::operator= (RefData<T> data)
336 {
337 	this->assign(data);
338 	return *this;
339 }
340 
341 /*--------------------------------------------------------------------*//*!
342  * \brief Unique Vulkan object reference.
343  *
344  * Similar to de::UniquePtr.
345  *//*--------------------------------------------------------------------*/
346 template<typename T>
347 class Unique : public RefBase<T>
348 {
349 public:
350 	template<typename U>
Unique(Checked<U> object,Deleter<U> deleter)351 				Unique		(Checked<U> object, Deleter<U> deleter)
352 								: RefBase<T>(RefData<T>(object.object, deleter))
353 				{}
354 
Unique(RefData<T> data)355 				Unique		(RefData<T> data)
356 								: RefBase<T>(data)
357 				{}
358 
359 private:
360 				Unique		(const Unique<T>&);
361 	Unique<T>&	operator=	(const Unique<T>&);
362 };
363 
364 } // refdetails
365 
366 using refdetails::Move;
367 using refdetails::Unique;
368 using refdetails::Deleter;
369 using refdetails::check;
370 using refdetails::notNull;
371 using refdetails::allowNull;
372 
373 } // vk
374 
375 #endif // _VKREF_HPP
376