}
}
+const VkAllocationCallbacks *allocator::get_original_callbacks() const
+{
+ return m_callbacks.pfnAllocation == default_allocation ? nullptr : &m_callbacks;
+}
+
} /* namespace util */
#include <new>
#include <vector>
#include <string>
+#include <cassert>
#include <vulkan/vulkan.h>
class allocator
{
public:
+ /**
+ * @brief Construct a new wrapper for the given VK callbacks and scope.
+ * @param callbacks Pointer to allocation callbacks. If this is @c nullptr, then default
+ * allocation callbacks are used. These can be accessed through #m_callbacks.
+ * @param scope The scope to use for this allocator.
+ */
allocator(const VkAllocationCallbacks *callbacks, VkSystemAllocationScope scope);
+ /**
+ * @brief Get a pointer to the allocation callbacks provided while constructing this object.
+ * @return a copy of the #VkAllocationCallback argument provided in the allocator constructor
+ * or @c nullptr if this argument was provided as @c nullptr.
+ * @note The #m_callbacks member is always populated with callable pointers for pfnAllocation,
+ * pfnReallocation and pfnFree.
+ */
+ const VkAllocationCallbacks *get_original_callbacks() const;
+
+ /**
+ * @brief Helper method to allocate and construct objects with a custom allocator.
+ * @param num_objects Number of objects to create.
+ * @return Pointer to the newly created objects or @c nullptr if allocation failed.
+ */
template <typename T, typename... arg_types>
- T *create(arg_types &&... args) const;
+ T *create(size_t num_objects, arg_types &&... args) const noexcept;
+ /**
+ * @brief Helper method to destroy and deallocate objects constructed with allocator::create().
+ * @param num_objects Number of objects to destroy.
+ */
template <typename T>
- void destroy(T *obj) const;
+ void destroy(size_t num_objects, T *obj) const noexcept;
VkAllocationCallbacks m_callbacks;
VkSystemAllocationScope m_scope;
return false;
}
-/**
- * @brief Helper method to allocate and construct objects with a custom allocator.
- * @return The new object or @c nullptr if allocation failed.
- */
template <typename T, typename... arg_types>
-T *allocator::create(arg_types &&... args) const
+T *allocator::create(size_t num_objects, arg_types &&... args) const noexcept
{
+ if (num_objects < 1)
+ {
+ return nullptr;
+ }
+
custom_allocator<T> allocator(*this);
T *ptr;
try
{
- ptr = allocator.allocate(1);
+ ptr = allocator.allocate(num_objects);
}
catch (...)
{
return nullptr;
}
+ size_t objects_constructed = 0;
try
{
- new (ptr) T(std::forward<arg_types>(args)...);
+ while (objects_constructed < num_objects)
+ {
+ T *next_object = &ptr[objects_constructed];
+ new (next_object) T(std::forward<arg_types>(args)...);
+ objects_constructed++;
+ }
}
catch (...)
{
/* We catch all exceptions thrown while constructing the object, not just
* std::bad_alloc.
*/
- allocator.deallocate(ptr, 1);
+ while (objects_constructed > 0)
+ {
+ objects_constructed--;
+ ptr[objects_constructed].~T();
+ }
+ allocator.deallocate(ptr, num_objects);
return nullptr;
}
return ptr;
}
-/**
- * @brief Helper method to destroy and deallocate objects constructed with create_custom().
- */
template <typename T>
-void allocator::destroy(T *obj) const
+void allocator::destroy(size_t num_objects, T *objects) const noexcept
{
- obj->~T();
+ assert((objects == nullptr) == (num_objects == 0));
+ if (num_objects == 0)
+ {
+ return;
+ }
+
custom_allocator<T> allocator(*this);
- allocator.deallocate(obj, 1);
+ for (size_t i = 0; i < num_objects; i++)
+ {
+ objects[i].~T();
+ }
+ allocator.deallocate(objects, num_objects);
}
template <typename T>
image_data *data = nullptr;
/* Create image_data */
- if (m_alloc_callbacks != nullptr)
- {
- data = static_cast<image_data *>(m_alloc_callbacks->pfnAllocation(
- m_alloc_callbacks->pUserData, sizeof(image_data), 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
- }
- else
- {
- data = static_cast<image_data *>(malloc(sizeof(image_data)));
- }
-
+ data = m_allocator.create<image_data>(1);
if (data == nullptr)
{
- m_device_data.disp.DestroyImage(m_device, image.image, m_alloc_callbacks);
+ m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
image.data = reinterpret_cast<void *>(data);
if (image.image != VK_NULL_HANDLE)
{
- m_device_data.disp.DestroyImage(m_device, image.image, m_alloc_callbacks);
+ m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
image.image = VK_NULL_HANDLE;
}
}
m_device_data.disp.FreeMemory(m_device, data->memory, nullptr);
data->memory = VK_NULL_HANDLE;
}
- if (m_alloc_callbacks != nullptr)
- {
- m_alloc_callbacks->pfnFree(m_alloc_callbacks->pUserData, data);
- }
- else
- {
- free(data);
- }
+ m_allocator.destroy(1, data);
image.data = nullptr;
}
m_free_image_semaphore.post();
}
-swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *allocator)
+swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *callbacks)
: m_device_data(dev_data)
, m_page_flip_thread_run(true)
, m_thread_sem_defined(false)
, m_first_present(true)
, m_pending_buffer_pool{ nullptr, 0, 0, 0 }
- , m_alloc_callbacks(allocator)
- , m_swapchain_images(util::allocator(m_alloc_callbacks, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
+ , m_allocator(callbacks, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)
+ , m_swapchain_images(m_allocator)
, m_surface(VK_NULL_HANDLE)
, m_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR)
, m_descendant(VK_NULL_HANDLE)
return VK_ERROR_OUT_OF_HOST_MEMORY;
/* Initialize ring buffer. */
- if (m_alloc_callbacks != nullptr)
- {
- m_pending_buffer_pool.ring = static_cast<uint32_t *>(
- m_alloc_callbacks->pfnAllocation(m_alloc_callbacks->pUserData, sizeof(uint32_t) * m_swapchain_images.size(),
- alignof(uint32_t), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
- }
- else
- {
- m_pending_buffer_pool.ring = static_cast<uint32_t *>(malloc(sizeof(uint32_t) * m_swapchain_images.size()));
- }
-
+ m_pending_buffer_pool.ring = m_allocator.create<uint32_t>(m_swapchain_images.size(), 0);
if (m_pending_buffer_pool.ring == nullptr)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
destroy_image(img);
}
- if (m_pending_buffer_pool.ring != nullptr)
- {
- if (m_alloc_callbacks != nullptr)
- {
- m_alloc_callbacks->pfnFree(m_alloc_callbacks->pUserData, m_pending_buffer_pool.ring);
- }
- else
- {
- free(m_pending_buffer_pool.ring);
- }
- }
+ m_allocator.destroy(m_swapchain_images.size(), m_pending_buffer_pool.ring);
}
VkResult swapchain_base::acquire_next_image(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index)
/**
* @brief User provided memory allocation callbacks.
*/
- const VkAllocationCallbacks *m_alloc_callbacks;
+ const util::allocator m_allocator;
/**
* @brief Vector of images in the swapchain.
*/
VkQueue m_queue;
- /*
+ /**
+ * @brief Return the VkAllocationCallbacks passed in this object constructor.
+ */
+ const VkAllocationCallbacks *get_allocation_callbacks()
+ {
+ return m_allocator.get_original_callbacks();
+ }
+
+ /**
* @brief Method to wait on all pending buffers to be displayed.
*/
void wait_for_pending_buffers();