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 PlatformInterface & platformIface,VkInstance instance,VkDevice device,const VkAllocationCallbacks * allocator)120 Deleter (const PlatformInterface& platformIface, VkInstance instance, VkDevice device, const VkAllocationCallbacks* allocator)
121 {
122 GetDeviceProcAddrFunc getDeviceProcAddr = (GetDeviceProcAddrFunc)platformIface.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
123 m_destroyDevice = (DestroyDeviceFunc)getDeviceProcAddr(device, "vkDestroyDevice");
124 m_allocator = allocator;
125 }
Deleter(void)126 Deleter (void)
127 : m_destroyDevice ((DestroyDeviceFunc)DE_NULL)
128 , m_allocator (DE_NULL)
129 {}
130
operator ()(VkDevice obj) const131 void operator() (VkDevice obj) const { m_destroyDevice(obj, m_allocator); }
132
133 private:
134 DestroyDeviceFunc m_destroyDevice;
135 const VkAllocationCallbacks* m_allocator;
136 };
137
138 template<>
139 class Deleter<VkSurfaceKHR>
140 {
141 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)142 Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
143 : m_instanceIface (&instanceIface)
144 , m_instance (instance)
145 , m_allocator (allocator)
146 {}
Deleter(void)147 Deleter (void)
148 : m_instanceIface (DE_NULL)
149 , m_instance ((VkInstance)0)
150 , m_allocator (DE_NULL)
151 {}
152
operator ()(VkSurfaceKHR obj) const153 void operator() (VkSurfaceKHR obj) const { m_instanceIface->destroySurfaceKHR(m_instance, obj, m_allocator); }
154
155 private:
156 const InstanceInterface* m_instanceIface;
157 VkInstance m_instance;
158 const VkAllocationCallbacks* m_allocator;
159 };
160
161 #ifndef CTS_USES_VULKANSC
162
163 template<>
164 class Deleter<VkDebugReportCallbackEXT>
165 {
166 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)167 Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
168 : m_instanceIface (&instanceIface)
169 , m_instance (instance)
170 , m_allocator (allocator)
171 {}
Deleter(void)172 Deleter (void)
173 : m_instanceIface (DE_NULL)
174 , m_instance ((VkInstance)0)
175 , m_allocator (DE_NULL)
176 {}
177
operator ()(VkDebugReportCallbackEXT obj) const178 void operator() (VkDebugReportCallbackEXT obj) const { m_instanceIface->destroyDebugReportCallbackEXT(m_instance, obj, m_allocator); }
179
180 private:
181 const InstanceInterface* m_instanceIface;
182 VkInstance m_instance;
183 const VkAllocationCallbacks* m_allocator;
184 };
185
186 #endif // CTS_USES_VULKANSC
187
188 template<>
189 class Deleter<VkDebugUtilsMessengerEXT>
190 {
191 public:
Deleter(const InstanceInterface & instanceIface,VkInstance instance,const VkAllocationCallbacks * allocator)192 Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
193 : m_instanceIface (&instanceIface)
194 , m_instance (instance)
195 , m_allocator (allocator)
196 {}
Deleter(void)197 Deleter (void)
198 : m_instanceIface (DE_NULL)
199 , m_instance ((VkInstance)0)
200 , m_allocator (DE_NULL)
201 {}
202
operator ()(VkDebugUtilsMessengerEXT obj) const203 void operator() (VkDebugUtilsMessengerEXT obj) const { m_instanceIface->destroyDebugUtilsMessengerEXT(m_instance, obj, m_allocator); }
204
205 private:
206 const InstanceInterface* m_instanceIface;
207 VkInstance m_instance;
208 const VkAllocationCallbacks* m_allocator;
209 };
210
211 template<>
212 class Deleter<VkDescriptorSet>
213 {
214 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkDescriptorPool pool)215 Deleter (const DeviceInterface& deviceIface, VkDevice device, VkDescriptorPool pool)
216 : m_deviceIface (&deviceIface)
217 , m_device (device)
218 , m_pool (pool)
219 {}
Deleter(void)220 Deleter (void)
221 : m_deviceIface (DE_NULL)
222 , m_device (DE_NULL)
223 , m_pool (DE_NULL)
224 {}
225
operator ()(VkDescriptorSet obj) const226 void operator() (VkDescriptorSet obj) const { m_deviceIface->freeDescriptorSets(m_device, m_pool, 1, &obj); }
227
228 private:
229 const DeviceInterface* m_deviceIface;
230 VkDevice m_device;
231 VkDescriptorPool m_pool;
232 };
233
234 template<>
235 class Deleter<VkCommandBuffer>
236 {
237 public:
Deleter(const DeviceInterface & deviceIface,VkDevice device,VkCommandPool pool)238 Deleter (const DeviceInterface& deviceIface, VkDevice device, VkCommandPool pool)
239 : m_deviceIface (&deviceIface)
240 , m_device (device)
241 , m_pool (pool)
242 {}
Deleter(void)243 Deleter (void)
244 : m_deviceIface (DE_NULL)
245 , m_device (DE_NULL)
246 , m_pool (DE_NULL)
247 {}
248
operator ()(VkCommandBuffer obj) const249 void operator() (VkCommandBuffer obj) const { m_deviceIface->freeCommandBuffers(m_device, m_pool, 1, &obj); }
250
251 private:
252 const DeviceInterface* m_deviceIface;
253 VkDevice m_device;
254 VkCommandPool m_pool;
255 };
256
257 template<typename T>
258 struct RefData
259 {
RefDatavk::refdetails::RefData260 RefData (T object_, Deleter<T> deleter_)
261 : object (object_)
262 , deleter (deleter_)
263 {}
RefDatavk::refdetails::RefData264 RefData (void)
265 : object (0)
266 {}
267
268 T object;
269 Deleter<T> deleter;
270 };
271
272 template<typename T>
273 class RefBase
274 {
275 public:
276 ~RefBase (void);
277
get(void) const278 inline const T& get (void) const throw() { return m_data.object; }
operator *(void) const279 inline const T& operator* (void) const throw() { return get(); }
operator bool(void) const280 inline explicit operator bool (void) const throw() { return !!get(); }
281
282 protected:
RefBase(RefData<T> data)283 RefBase (RefData<T> data) : m_data(data) {}
284
285 void reset (void); //!< Release previous object, set to null.
286 RefData<T> disown (void) throw(); //!< Disown and return object (ownership transferred to caller).
287 void assign (RefData<T> data); //!< Set new pointer, release previous pointer.
288
289 private:
290 RefData<T> m_data;
291 };
292
293 template<typename T>
~RefBase(void)294 inline RefBase<T>::~RefBase (void)
295 {
296 this->reset();
297 }
298
299 template<typename T>
reset(void)300 inline void RefBase<T>::reset (void)
301 {
302 if (!!m_data.object)
303 m_data.deleter(m_data.object);
304
305 m_data = RefData<T>();
306 }
307
308 template<typename T>
disown(void)309 inline RefData<T> RefBase<T>::disown (void) throw()
310 {
311 RefData<T> tmp;
312 swap(m_data, tmp);
313 return tmp;
314 }
315
316 template<typename T>
assign(RefData<T> data)317 inline void RefBase<T>::assign (RefData<T> data)
318 {
319 this->reset();
320 m_data = data;
321 }
322
323 /*--------------------------------------------------------------------*//*!
324 * \brief Movable Vulkan object reference.
325 *
326 * Similar to de::MovePtr.
327 *//*--------------------------------------------------------------------*/
328 template<typename T>
329 class Move : public RefBase<T>
330 {
331 public:
332 template<typename U>
Move(Checked<U> object,Deleter<U> deleter)333 Move (Checked<U> object, Deleter<U> deleter)
334 : RefBase<T>(RefData<T>(object.object, deleter))
335 {}
336
Move(RefData<T> data)337 Move (RefData<T> data)
338 : RefBase<T>(data)
339 {}
Move(Move<T> & other)340 Move (Move<T>& other)
341 : RefBase<T>(other.RefBase<T>::disown())
342 {}
Move(void)343 Move (void)
344 : RefBase<T>(RefData<T>())
345 {}
346
disown(void)347 T disown (void) { return this->RefBase<T>::disown().object; }
348 Move<T>& operator= (Move<T>& other);
349 Move<T>& operator= (RefData<T> data);
350
operator RefData<T>(void)351 operator RefData<T> (void) { return this->RefBase<T>::disown(); }
352 };
353
354 template<typename T>
operator =(Move<T> & other)355 inline Move<T>& Move<T>::operator= (Move<T>& other)
356 {
357 if (this != &other)
358 this->assign(other.RefBase<T>::disown());
359
360 return *this;
361 }
362
363 template<typename T>
operator =(RefData<T> data)364 inline Move<T>& Move<T>::operator= (RefData<T> data)
365 {
366 this->assign(data);
367 return *this;
368 }
369
370 /*--------------------------------------------------------------------*//*!
371 * \brief Unique Vulkan object reference.
372 *
373 * Similar to de::UniquePtr.
374 *//*--------------------------------------------------------------------*/
375 template<typename T>
376 class Unique : public RefBase<T>
377 {
378 public:
379 template<typename U>
Unique(Checked<U> object,Deleter<U> deleter)380 Unique (Checked<U> object, Deleter<U> deleter)
381 : RefBase<T>(RefData<T>(object.object, deleter))
382 {}
383
Unique(RefData<T> data)384 Unique (RefData<T> data)
385 : RefBase<T>(data)
386 {}
387
388 private:
389 Unique (const Unique<T>&);
390 Unique<T>& operator= (const Unique<T>&);
391 };
392
393 } // refdetails
394
395 using refdetails::Move;
396 using refdetails::Unique;
397 using refdetails::Deleter;
398 using refdetails::check;
399 using refdetails::notNull;
400 using refdetails::allowNull;
401
402 } // vk
403
404 #endif // _VKREF_HPP
405