blob: 6967f14ee19adca26ae3c1c79d11d01e85044400 [file] [log] [blame] [edit]
#ifndef _VKREF_HPP
#define _VKREF_HPP
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Vulkan object reference holder.
*//*--------------------------------------------------------------------*/
#include "vkDefs.hpp"
#include "vkStrUtil.hpp"
#include "deMeta.hpp"
#include <algorithm>
namespace vk
{
namespace refdetails
{
using std::swap;
template<typename T>
struct Checked
{
explicit inline Checked (T object_) : object(object_) {}
T object;
};
//! Check that object is not null
template<typename T>
inline Checked<T> check (T object)
{
if (!object)
throw tcu::TestError("Object check() failed", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
return Checked<T>(object);
}
//! Declare object as checked earlier
template<typename T>
inline Checked<T> notNull (T object)
{
if (!object)
throw tcu::InternalError("Null object was given to notNull()", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
return Checked<T>(object);
}
//! Allow null object
template<typename T>
inline Checked<T> allowNull (T object)
{
return Checked<T>(object);
}
template<typename T>
class Deleter
{
public:
Deleter (const DeviceInterface& deviceIface, VkDevice device, const VkAllocationCallbacks* allocator)
: m_deviceIface (&deviceIface)
, m_device (device)
, m_allocator (allocator)
{}
Deleter (void)
: m_deviceIface (DE_NULL)
, m_device (DE_NULL)
, m_allocator (DE_NULL)
{}
void operator() (T obj) const;
private:
const DeviceInterface* m_deviceIface;
VkDevice m_device;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkInstance>
{
public:
Deleter (const PlatformInterface& platformIface, VkInstance instance, const VkAllocationCallbacks* allocator)
: m_destroyInstance ((DestroyInstanceFunc)platformIface.getInstanceProcAddr(instance, "vkDestroyInstance"))
, m_allocator (allocator)
{}
Deleter (void)
: m_destroyInstance ((DestroyInstanceFunc)DE_NULL)
, m_allocator (DE_NULL)
{}
void operator() (VkInstance obj) const { m_destroyInstance(obj, m_allocator); }
private:
DestroyInstanceFunc m_destroyInstance;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkDevice>
{
public:
Deleter (const PlatformInterface& platformIface, VkInstance instance, VkDevice device, const VkAllocationCallbacks* allocator)
{
GetDeviceProcAddrFunc getDeviceProcAddr = (GetDeviceProcAddrFunc)platformIface.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
m_destroyDevice = (DestroyDeviceFunc)getDeviceProcAddr(device, "vkDestroyDevice");
m_allocator = allocator;
}
Deleter (void)
: m_destroyDevice ((DestroyDeviceFunc)DE_NULL)
, m_allocator (DE_NULL)
{}
void operator() (VkDevice obj) const { m_destroyDevice(obj, m_allocator); }
private:
DestroyDeviceFunc m_destroyDevice;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkSurfaceKHR>
{
public:
Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
: m_instanceIface (&instanceIface)
, m_instance (instance)
, m_allocator (allocator)
{}
Deleter (void)
: m_instanceIface (DE_NULL)
, m_instance ((VkInstance)0)
, m_allocator (DE_NULL)
{}
void operator() (VkSurfaceKHR obj) const { m_instanceIface->destroySurfaceKHR(m_instance, obj, m_allocator); }
private:
const InstanceInterface* m_instanceIface;
VkInstance m_instance;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkDebugReportCallbackEXT>
{
public:
Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
: m_instanceIface (&instanceIface)
, m_instance (instance)
, m_allocator (allocator)
{}
Deleter (void)
: m_instanceIface (DE_NULL)
, m_instance ((VkInstance)0)
, m_allocator (DE_NULL)
{}
void operator() (VkDebugReportCallbackEXT obj) const { m_instanceIface->destroyDebugReportCallbackEXT(m_instance, obj, m_allocator); }
private:
const InstanceInterface* m_instanceIface;
VkInstance m_instance;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkDebugUtilsMessengerEXT>
{
public:
Deleter (const InstanceInterface& instanceIface, VkInstance instance, const VkAllocationCallbacks* allocator)
: m_instanceIface (&instanceIface)
, m_instance (instance)
, m_allocator (allocator)
{}
Deleter (void)
: m_instanceIface (DE_NULL)
, m_instance ((VkInstance)0)
, m_allocator (DE_NULL)
{}
void operator() (VkDebugUtilsMessengerEXT obj) const { m_instanceIface->destroyDebugUtilsMessengerEXT(m_instance, obj, m_allocator); }
private:
const InstanceInterface* m_instanceIface;
VkInstance m_instance;
const VkAllocationCallbacks* m_allocator;
};
template<>
class Deleter<VkDescriptorSet>
{
public:
Deleter (const DeviceInterface& deviceIface, VkDevice device, VkDescriptorPool pool)
: m_deviceIface (&deviceIface)
, m_device (device)
, m_pool (pool)
{}
Deleter (void)
: m_deviceIface (DE_NULL)
, m_device (DE_NULL)
, m_pool (DE_NULL)
{}
void operator() (VkDescriptorSet obj) const { m_deviceIface->freeDescriptorSets(m_device, m_pool, 1, &obj); }
private:
const DeviceInterface* m_deviceIface;
VkDevice m_device;
VkDescriptorPool m_pool;
};
template<>
class Deleter<VkCommandBuffer>
{
public:
Deleter (const DeviceInterface& deviceIface, VkDevice device, VkCommandPool pool)
: m_deviceIface (&deviceIface)
, m_device (device)
, m_pool (pool)
{}
Deleter (void)
: m_deviceIface (DE_NULL)
, m_device (DE_NULL)
, m_pool (DE_NULL)
{}
void operator() (VkCommandBuffer obj) const { m_deviceIface->freeCommandBuffers(m_device, m_pool, 1, &obj); }
private:
const DeviceInterface* m_deviceIface;
VkDevice m_device;
VkCommandPool m_pool;
};
template<typename T>
struct RefData
{
RefData (T object_, Deleter<T> deleter_)
: object (object_)
, deleter (deleter_)
{}
RefData (void)
: object (0)
{}
T object;
Deleter<T> deleter;
};
template<typename T>
class RefBase
{
public:
~RefBase (void);
inline const T& get (void) const throw() { return m_data.object; }
inline const T& operator* (void) const throw() { return get(); }
inline operator bool (void) const throw() { return !!get(); }
protected:
RefBase (RefData<T> data) : m_data(data) {}
void reset (void); //!< Release previous object, set to null.
RefData<T> disown (void) throw(); //!< Disown and return object (ownership transferred to caller).
void assign (RefData<T> data); //!< Set new pointer, release previous pointer.
private:
RefData<T> m_data;
};
template<typename T>
inline RefBase<T>::~RefBase (void)
{
this->reset();
}
template<typename T>
inline void RefBase<T>::reset (void)
{
if (!!m_data.object)
m_data.deleter(m_data.object);
m_data = RefData<T>();
}
template<typename T>
inline RefData<T> RefBase<T>::disown (void) throw()
{
RefData<T> tmp;
swap(m_data, tmp);
return tmp;
}
template<typename T>
inline void RefBase<T>::assign (RefData<T> data)
{
this->reset();
m_data = data;
}
/*--------------------------------------------------------------------*//*!
* \brief Movable Vulkan object reference.
*
* Similar to de::MovePtr.
*//*--------------------------------------------------------------------*/
template<typename T>
class Move : public RefBase<T>
{
public:
template<typename U>
Move (Checked<U> object, Deleter<U> deleter)
: RefBase<T>(RefData<T>(object.object, deleter))
{}
Move (RefData<T> data)
: RefBase<T>(data)
{}
Move (Move<T>& other)
: RefBase<T>(other.RefBase<T>::disown())
{}
Move (void)
: RefBase<T>(RefData<T>())
{}
T disown (void) { return this->RefBase<T>::disown().object; }
Move<T>& operator= (Move<T>& other);
Move<T>& operator= (RefData<T> data);
operator RefData<T> (void) { return this->RefBase<T>::disown(); }
};
template<typename T>
inline Move<T>& Move<T>::operator= (Move<T>& other)
{
if (this != &other)
this->assign(other.RefBase<T>::disown());
return *this;
}
template<typename T>
inline Move<T>& Move<T>::operator= (RefData<T> data)
{
this->assign(data);
return *this;
}
/*--------------------------------------------------------------------*//*!
* \brief Unique Vulkan object reference.
*
* Similar to de::UniquePtr.
*//*--------------------------------------------------------------------*/
template<typename T>
class Unique : public RefBase<T>
{
public:
template<typename U>
Unique (Checked<U> object, Deleter<U> deleter)
: RefBase<T>(RefData<T>(object.object, deleter))
{}
Unique (RefData<T> data)
: RefBase<T>(data)
{}
private:
Unique (const Unique<T>&);
Unique<T>& operator= (const Unique<T>&);
};
} // refdetails
using refdetails::Move;
using refdetails::Unique;
using refdetails::Deleter;
using refdetails::check;
using refdetails::notNull;
using refdetails::allowNull;
} // vk
#endif // _VKREF_HPP