void reset() noexcept
{
m_has_value = false;
+ m_value = T{};
+ }
+
+ /**
+ * @brief Reassign/assign the value in the optional.
+ *
+ * @return optional& This optional object with the value.
+ */
+ optional &set(T &&val) noexcept
+ {
+ m_value = std::move(val);
+ m_has_value = true;
+ return *this;
+ }
+
+ optional &set(const T &val) noexcept
+ {
+ m_value = val;
+ m_has_value = true;
+ return *this;
}
/**
--- /dev/null
+/*
+ * Copyright (c) 2021 Arm Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <memory>
+#include <array>
+
+#include "optional.hpp"
+
+namespace util
+{
+
+template <typename T, std::size_t N>
+class ring_buffer
+{
+public:
+ /**
+ * @brief Return maximum capacity of the ring buffer.
+ */
+ constexpr std::size_t capacity()
+ {
+ return N;
+ }
+
+ /**
+ * @brief Return current size of the ring buffer.
+ */
+ std::size_t size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * @brief Places item into next slot of the ring buffer.
+ * @return Boolean to indicate success or failure.
+ */
+ template <typename U>
+ bool push_back(U &&item)
+ {
+ if (size() == capacity())
+ {
+ return false;
+ }
+
+ m_data[(m_begin + m_size) % N].set(std::forward<U>(item));
+ ++m_size;
+
+ return true;
+ }
+
+ /**
+ * @brief Gets a pointer to the item at the starting index of the ring buffer.
+ */
+ T *front()
+ {
+ return get(m_begin);
+ }
+
+ /**
+ * @brief Gets a pointer to the item that was last placed into the ring buffer.
+ */
+ T *back()
+ {
+ return get((m_begin + m_size + N - 1) % N);
+ }
+
+ /**
+ * @brief Pop the front of the ring buffer.
+ *
+ * Item at the starting index of the ring buffer is returned. The slot is subsequently emptied. The starting index of
+ * the ring buffer increments by 1.
+ *
+ * @return Item wrapped in an optional.
+ */
+ util::optional<T> pop_front()
+ {
+ if (size() == 0)
+ {
+ return util::optional<T>{};
+ }
+
+ util::optional<T> value = std::move(m_data[m_begin]);
+
+ m_begin = (m_begin + 1) % N;
+ --m_size;
+
+ return value;
+ }
+
+private:
+ T *get(std::size_t index)
+ {
+ if (m_data[index].has_value())
+ {
+ return std::addressof(m_data[index].value());
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+
+ std::array<util::optional<T>, N> m_data{};
+
+ // Marks the start index of the ring buffer.
+ std::size_t m_begin{};
+
+ // The number of entries in the ring buffer from the start index.
+ std::size_t m_size{};
+};
+
+} /* namespace util */
\ No newline at end of file
UNUSED(surface);
/* Image count limits */
surface_capabilities->minImageCount = 1;
- /* There is no maximum theoretically speaking */
- surface_capabilities->maxImageCount = UINT32_MAX;
+ surface_capabilities->maxImageCount = MAX_SWAPCHAIN_IMAGE_COUNT;
/* Surface extents */
surface_capabilities->currentExtent = { 0xffffffff, 0xffffffff };
* At least the specific VkSurface creation entrypoint must be intercepted.
*/
virtual PFN_vkVoidFunction get_proc_addr(const char *name) = 0;
+
+ /* There is no maximum theoretically speaking however we choose 3 for practicality */
+ static constexpr uint32_t MAX_SWAPCHAIN_IMAGE_COUNT = 3;
};
} /* namespace wsi */
/* We want to present the oldest queued for present image from our present queue,
* which we can find at the sc->pending_buffer_pool.head index. */
- uint32_t pending_index = m_pending_buffer_pool.ring[m_pending_buffer_pool.head];
- m_pending_buffer_pool.head = (m_pending_buffer_pool.head + 1) % m_pending_buffer_pool.size;
+ auto pending_index = m_pending_buffer_pool.pop_front();
+ assert(pending_index.has_value());
/* We wait for the fence of the oldest pending image to be signalled. */
- vk_res = m_device_data.disp.WaitForFences(m_device, 1, &sc_images[pending_index].present_fence, VK_TRUE,
+ vk_res = m_device_data.disp.WaitForFences(m_device, 1, &sc_images[*pending_index].present_fence, VK_TRUE,
timeout);
if (vk_res != VK_SUCCESS)
{
/* If the descendant has started presenting the queue_present operation has marked the image
* as FREE so we simply release it and continue. */
- if (sc_images[pending_index].status == swapchain_image::FREE)
+ if (sc_images[*pending_index].status == swapchain_image::FREE)
{
- destroy_image(sc_images[pending_index]);
+ destroy_image(sc_images[*pending_index]);
m_free_image_semaphore.post();
continue;
}
sem_post(&m_start_present_semaphore);
- present_image(pending_index);
+ present_image(*pending_index);
m_first_present = false;
}
/* The swapchain has already started presenting. */
else
{
- present_image(pending_index);
+ present_image(*pending_index);
}
}
}
, m_page_flip_thread_run(true)
, m_thread_sem_defined(false)
, m_first_present(true)
- , m_pending_buffer_pool{ nullptr, 0, 0, 0 }
+ , m_pending_buffer_pool{}
, m_allocator(dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, callbacks)
, m_swapchain_images(m_allocator)
, m_surface(VK_NULL_HANDLE)
if (!m_swapchain_images.try_resize(swapchain_create_info->minImageCount))
return VK_ERROR_OUT_OF_HOST_MEMORY;
- /* Initialize ring buffer. */
- 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;
- }
-
- m_pending_buffer_pool.head = 0;
- m_pending_buffer_pool.tail = 0;
- m_pending_buffer_pool.size = m_swapchain_images.size();
-
/* We have allocated images, we can call the platform init function if something needs to be done. */
result = init_platform(device, swapchain_create_info);
if (result != VK_SUCCESS)
/* Call implementation specific release */
destroy_image(img);
}
-
- 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)
}
}
-VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index)
+VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, uint32_t image_index)
{
VkResult result;
bool descendent_started_presenting = false;
if (descendent_started_presenting)
{
m_swapchain_images[image_index].status = swapchain_image::FREE;
-
- m_pending_buffer_pool.ring[m_pending_buffer_pool.tail] = image_index;
- m_pending_buffer_pool.tail = (m_pending_buffer_pool.tail + 1) % m_pending_buffer_pool.size;
+ m_pending_buffer_pool.push_back(image_index);
m_page_flip_semaphore.post();
-
return VK_ERROR_OUT_OF_DATE_KHR;
}
m_swapchain_images[image_index].status = swapchain_image::PENDING;
-
- m_pending_buffer_pool.ring[m_pending_buffer_pool.tail] = image_index;
- m_pending_buffer_pool.tail = (m_pending_buffer_pool.tail + 1) % m_pending_buffer_pool.size;
-
+ m_pending_buffer_pool.push_back(image_index);
m_page_flip_semaphore.post();
return VK_SUCCESS;
}
#include <layer/private_data.hpp>
#include <util/timed_semaphore.hpp>
#include <util/custom_allocator.hpp>
+#include <util/ring_buffer.hpp>
+#include "surface_properties.hpp"
namespace wsi
{
*/
bool m_is_valid;
- struct ring_buffer
- {
- /* Ring buffer to hold the image indexes. */
- uint32_t *ring;
- /* Head of the ring. */
- uint32_t head;
- /* End of the ring. */
- uint32_t tail;
- /* Size of the ring. */
- uint32_t size;
- };
/**
* @brief A semaphore to be signalled once a page flip event occurs.
*/
* threads and we do not allow the application to acquire more images
* than we have we eliminate race conditions.
*/
- ring_buffer m_pending_buffer_pool;
+ util::ring_buffer<uint32_t, wsi::surface_properties::MAX_SWAPCHAIN_IMAGE_COUNT> m_pending_buffer_pool;
/**
* @brief User provided memory allocation callbacks.
{
/* Image count limits */
pSurfaceCapabilities->minImageCount = 2;
- /* There is no maximum theoretically speaking */
- pSurfaceCapabilities->maxImageCount = UINT32_MAX;
+ pSurfaceCapabilities->maxImageCount = MAX_SWAPCHAIN_IMAGE_COUNT;
/* Surface extents */
pSurfaceCapabilities->currentExtent = { 0xffffffff, 0xffffffff };