Commit f0b541a4 authored by Matteo Franchin's avatar Matteo Franchin
Browse files

Use util::allocator in swapchain object



Change util::allocator's create and destroy methods so that they can
allocate multiple objects, in line with the allocate and deallocate
methods of std::allocator.

Also add documentation for util::allocator and its methods.

Finally, use util::allocator in swapchain.cpp, rather than allocating
memory directly via VkAllocationCallbacks.

Change-Id: I0bc25abe3cbc3af9608218411da8d70e04dd9749
Signed-off-by: Matteo Franchin's avatarMatteo Franchin <matteo.franchin@arm.com>
parent 5b2b2511
Pipeline #244801 passed with stage
in 1 minute and 36 seconds
......@@ -62,4 +62,9 @@ allocator::allocator(const VkAllocationCallbacks *callbacks, VkSystemAllocationS
}
}
const VkAllocationCallbacks *allocator::get_original_callbacks() const
{
return m_callbacks.pfnAllocation == default_allocation ? nullptr : &m_callbacks;
}
} /* namespace util */
......@@ -25,6 +25,7 @@
#include <new>
#include <vector>
#include <string>
#include <cassert>
#include <vulkan/vulkan.h>
......@@ -39,13 +40,37 @@ namespace util
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;
......@@ -118,48 +143,66 @@ bool operator!=(const custom_allocator<T> &, const custom_allocator<U> &)
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>
......
......@@ -88,19 +88,10 @@ VkResult swapchain::create_image(const VkImageCreateInfo &image_create, wsi::swa
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);
......@@ -150,7 +141,7 @@ void swapchain::destroy_image(wsi::swapchain_image &image)
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;
}
}
......@@ -163,14 +154,7 @@ void swapchain::destroy_image(wsi::swapchain_image &image)
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;
}
......
......@@ -134,14 +134,14 @@ void swapchain_base::unpresent_image(uint32_t presented_index)
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)
......@@ -184,17 +184,7 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
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;
......@@ -377,17 +367,7 @@ void swapchain_base::teardown()
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)
......
......@@ -200,7 +200,7 @@ protected:
/**
* @brief User provided memory allocation callbacks.
*/
const VkAllocationCallbacks *m_alloc_callbacks;
const util::allocator m_allocator;
/**
* @brief Vector of images in the swapchain.
......@@ -243,7 +243,15 @@ protected:
*/
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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment