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 }
46
47 T object;
48 };
49
50 //! Check that object is not null
51 template <typename T>
check(T object)52 inline Checked<T> check(T object)
53 {
54 if (!object)
55 throw tcu::TestError("Object check() failed", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__,
56 __LINE__);
57 return Checked<T>(object);
58 }
59
60 //! Declare object as checked earlier
61 template <typename T>
notNull(T object)62 inline Checked<T> notNull(T object)
63 {
64 if (!object)
65 throw tcu::InternalError("Null object was given to notNull()", (std::string(getTypeName<T>()) + " = 0").c_str(),
66 __FILE__, __LINE__);
67 return Checked<T>(object);
68 }
69
70 //! Allow null object
71 template <typename T>
allowNull(T object)72 inline Checked<T> allowNull(T object)
73 {
74 return Checked<T>(object);
75 }
76
77 template <typename T>
78 class Deleter
79 {
80 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,const VkAllocationCallbacks * allocator)81 Deleter(const DeviceInterface &deviceIface, VkDevice device, const VkAllocationCallbacks *allocator)
82 : m_deviceIface(&deviceIface)
83 , m_device(device)
84 , m_allocator(allocator)
85 {
86 }
Deleter(void)87 Deleter(void) : m_deviceIface(DE_NULL), m_device(DE_NULL), m_allocator(DE_NULL)
88 {
89 }
90
91 void operator()(T obj) const;
92
93 private:
94 const DeviceInterface *m_deviceIface;
95 VkDevice m_device;
96 const VkAllocationCallbacks *m_allocator;
97 };
98
99 template <>
100 class Deleter<VkInstance>
101 {
102 public:
Deleter(const PlatformInterface & platformIface,VkInstance instance,const VkAllocationCallbacks * allocator)103 Deleter(const PlatformInterface &platformIface, VkInstance instance, const VkAllocationCallbacks *allocator)
104 : m_destroyInstance((DestroyInstanceFunc)platformIface.getInstanceProcAddr(instance, "vkDestroyInstance"))
105 , m_allocator(allocator)
106 {
107 }
Deleter(void)108 Deleter(void) : m_destroyInstance((DestroyInstanceFunc)DE_NULL), m_allocator(DE_NULL)
109 {
110 }
111
operator ()(VkInstance obj) const112 void operator()(VkInstance obj) const
113 {
114 m_destroyInstance(obj, m_allocator);
115 }
116
117 private:
118 DestroyInstanceFunc m_destroyInstance;
119 const VkAllocationCallbacks *m_allocator;
120 };
121
122 template <>
123 class Deleter<VkDevice>
124 {
125 public:
Deleter(const PlatformInterface & platformIface,VkInstance instance,VkDevice device,const VkAllocationCallbacks * allocator)126 Deleter(const PlatformInterface &platformIface, VkInstance instance, VkDevice device,
127 const VkAllocationCallbacks *allocator)
128 {
129 GetDeviceProcAddrFunc getDeviceProcAddr =
130 (GetDeviceProcAddrFunc)platformIface.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
131 m_destroyDevice = (DestroyDeviceFunc)getDeviceProcAddr(device, "vkDestroyDevice");
132 m_allocator = allocator;
133 }
Deleter(void)134 Deleter(void) : m_destroyDevice((DestroyDeviceFunc)DE_NULL), m_allocator(DE_NULL)
135 {
136 }
137
operator ()(VkDevice obj) const138 void operator()(VkDevice obj) const
139 {
140 m_destroyDevice(obj, m_allocator);
141 }
142
143 private:
144 DestroyDeviceFunc m_destroyDevice;
145 const VkAllocationCallbacks *m_allocator;
146 };
147
148 template <>
149 class Deleter<VkSurfaceKHR>
150 {
151 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)152 Deleter(const InstanceInterface &instanceIface, VkInstance instance, const VkAllocationCallbacks *allocator)
153 : m_instanceIface(&instanceIface)
154 , m_instance(instance)
155 , m_allocator(allocator)
156 {
157 }
Deleter(void)158 Deleter(void) : m_instanceIface(DE_NULL), m_instance((VkInstance)0), m_allocator(DE_NULL)
159 {
160 }
161
operator ()(VkSurfaceKHR obj) const162 void operator()(VkSurfaceKHR obj) const
163 {
164 m_instanceIface->destroySurfaceKHR(m_instance, obj, m_allocator);
165 }
166
167 private:
168 const InstanceInterface *m_instanceIface;
169 VkInstance m_instance;
170 const VkAllocationCallbacks *m_allocator;
171 };
172
173 #ifndef CTS_USES_VULKANSC
174
175 template <>
176 class Deleter<VkDebugReportCallbackEXT>
177 {
178 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)179 Deleter(const InstanceInterface &instanceIface, VkInstance instance, const VkAllocationCallbacks *allocator)
180 : m_instanceIface(&instanceIface)
181 , m_instance(instance)
182 , m_allocator(allocator)
183 {
184 }
Deleter(void)185 Deleter(void) : m_instanceIface(DE_NULL), m_instance((VkInstance)0), m_allocator(DE_NULL)
186 {
187 }
188
operator ()(VkDebugReportCallbackEXT obj) const189 void operator()(VkDebugReportCallbackEXT obj) const
190 {
191 m_instanceIface->destroyDebugReportCallbackEXT(m_instance, obj, m_allocator);
192 }
193
194 private:
195 const InstanceInterface *m_instanceIface;
196 VkInstance m_instance;
197 const VkAllocationCallbacks *m_allocator;
198 };
199
200 #endif // CTS_USES_VULKANSC
201
202 template <>
203 class Deleter<VkDebugUtilsMessengerEXT>
204 {
205 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)206 Deleter(const InstanceInterface &instanceIface, VkInstance instance, const VkAllocationCallbacks *allocator)
207 : m_instanceIface(&instanceIface)
208 , m_instance(instance)
209 , m_allocator(allocator)
210 {
211 }
Deleter(void)212 Deleter(void) : m_instanceIface(DE_NULL), m_instance((VkInstance)0), m_allocator(DE_NULL)
213 {
214 }
215
operator ()(VkDebugUtilsMessengerEXT obj) const216 void operator()(VkDebugUtilsMessengerEXT obj) const
217 {
218 m_instanceIface->destroyDebugUtilsMessengerEXT(m_instance, obj, m_allocator);
219 }
220
221 private:
222 const InstanceInterface *m_instanceIface;
223 VkInstance m_instance;
224 const VkAllocationCallbacks *m_allocator;
225 };
226
227 template <>
228 class Deleter<VkDescriptorSet>
229 {
230 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkDescriptorPool pool)231 Deleter(const DeviceInterface &deviceIface, VkDevice device, VkDescriptorPool pool)
232 : m_deviceIface(&deviceIface)
233 , m_device(device)
234 , m_pool(pool)
235 {
236 }
Deleter(void)237 Deleter(void) : m_deviceIface(DE_NULL), m_device(DE_NULL), m_pool(DE_NULL)
238 {
239 }
240
operator ()(VkDescriptorSet obj) const241 void operator()(VkDescriptorSet obj) const
242 {
243 m_deviceIface->freeDescriptorSets(m_device, m_pool, 1, &obj);
244 }
245
246 private:
247 const DeviceInterface *m_deviceIface;
248 VkDevice m_device;
249 VkDescriptorPool m_pool;
250 };
251
252 template <>
253 class Deleter<VkCommandBuffer>
254 {
255 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkCommandPool pool)256 Deleter(const DeviceInterface &deviceIface, VkDevice device, VkCommandPool pool)
257 : m_deviceIface(&deviceIface)
258 , m_device(device)
259 , m_pool(pool)
260 {
261 }
Deleter(void)262 Deleter(void) : m_deviceIface(DE_NULL), m_device(DE_NULL), m_pool(DE_NULL)
263 {
264 }
265
operator ()(VkCommandBuffer obj) const266 void operator()(VkCommandBuffer obj) const
267 {
268 m_deviceIface->freeCommandBuffers(m_device, m_pool, 1, &obj);
269 }
270
271 private:
272 const DeviceInterface *m_deviceIface;
273 VkDevice m_device;
274 VkCommandPool m_pool;
275 };
276
277 template <typename T>
278 struct RefData
279 {
RefDatavk::refdetails::RefData280 RefData(T object_, Deleter<T> deleter_) : object(object_), deleter(deleter_)
281 {
282 }
RefDatavk::refdetails::RefData283 RefData(void) : object(0)
284 {
285 }
286
287 T object;
288 Deleter<T> deleter;
289 };
290
291 template <typename T>
292 class RefBase
293 {
294 public:
295 ~RefBase(void);
296
get(void) const297 inline const T &get(void) const throw()
298 {
299 return m_data.object;
300 }
operator *(void) const301 inline const T &operator*(void) const throw()
302 {
303 return get();
304 }
operator bool(void) const305 inline explicit operator bool(void) const throw()
306 {
307 return !!get();
308 }
309
310 protected:
RefBase(RefData<T> data)311 RefBase(RefData<T> data) : m_data(data)
312 {
313 }
314
315 void reset(void); //!< Release previous object, set to null.
316 RefData<T> disown(void) throw(); //!< Disown and return object (ownership transferred to caller).
317 void assign(RefData<T> data); //!< Set new pointer, release previous pointer.
318
319 private:
320 RefData<T> m_data;
321 };
322
323 template <typename T>
~RefBase(void)324 inline RefBase<T>::~RefBase(void)
325 {
326 this->reset();
327 }
328
329 template <typename T>
reset(void)330 inline void RefBase<T>::reset(void)
331 {
332 if (!!m_data.object)
333 m_data.deleter(m_data.object);
334
335 m_data = RefData<T>();
336 }
337
338 template <typename T>
disown(void)339 inline RefData<T> RefBase<T>::disown(void) throw()
340 {
341 RefData<T> tmp;
342 swap(m_data, tmp);
343 return tmp;
344 }
345
346 template <typename T>
assign(RefData<T> data)347 inline void RefBase<T>::assign(RefData<T> data)
348 {
349 this->reset();
350 m_data = data;
351 }
352
353 /*--------------------------------------------------------------------*//*!
354 * \brief Movable Vulkan object reference.
355 *
356 * Similar to de::MovePtr.
357 *//*--------------------------------------------------------------------*/
358 template <typename T>
359 class Move : public RefBase<T>
360 {
361 public:
362 template <typename U>
Move(Checked<U> object,Deleter<U> deleter)363 Move(Checked<U> object, Deleter<U> deleter) : RefBase<T>(RefData<T>(object.object, deleter))
364 {
365 }
366
Move(RefData<T> data)367 Move(RefData<T> data) : RefBase<T>(data)
368 {
369 }
Move(Move<T> & other)370 Move(Move<T> &other) : RefBase<T>(other.RefBase<T>::disown())
371 {
372 }
Move(void)373 Move(void) : RefBase<T>(RefData<T>())
374 {
375 }
376
disown(void)377 T disown(void)
378 {
379 return this->RefBase<T>::disown().object;
380 }
381 Move<T> &operator=(Move<T> &other);
382 Move<T> &operator=(RefData<T> data);
383
operator RefData<T>(void)384 operator RefData<T>(void)
385 {
386 return this->RefBase<T>::disown();
387 }
388 };
389
390 template <typename T>
operator =(Move<T> & other)391 inline Move<T> &Move<T>::operator=(Move<T> &other)
392 {
393 if (this != &other)
394 this->assign(other.RefBase<T>::disown());
395
396 return *this;
397 }
398
399 template <typename T>
operator =(RefData<T> data)400 inline Move<T> &Move<T>::operator=(RefData<T> data)
401 {
402 this->assign(data);
403 return *this;
404 }
405
406 /*--------------------------------------------------------------------*//*!
407 * \brief Unique Vulkan object reference.
408 *
409 * Similar to de::UniquePtr.
410 *//*--------------------------------------------------------------------*/
411 template <typename T>
412 class Unique : public RefBase<T>
413 {
414 public:
415 template <typename U>
Unique(Checked<U> object,Deleter<U> deleter)416 Unique(Checked<U> object, Deleter<U> deleter) : RefBase<T>(RefData<T>(object.object, deleter))
417 {
418 }
419
Unique(RefData<T> data)420 Unique(RefData<T> data) : RefBase<T>(data)
421 {
422 }
423
424 private:
425 Unique(const Unique<T> &);
426 Unique<T> &operator=(const Unique<T> &);
427 };
428
429 } // namespace refdetails
430
431 using refdetails::allowNull;
432 using refdetails::check;
433 using refdetails::Deleter;
434 using refdetails::Move;
435 using refdetails::notNull;
436 using refdetails::Unique;
437
438 } // namespace vk
439
440 #endif // _VKREF_HPP
441