mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-20 04:30:11 +01:00
This commit adds the initial sources for the vulkan-wsi-layer project: a Vulkan layer which implements some of the Vulkan window system integration extensions such as VK_KHR_swapchain. The layer is designed to be GPU vendor agnostic when used as part of the Vulkan ICD/loader architecture. The project currently implements support for VK_EXT_headless_surface and its dependencies. We hope to extend support for further platforms such as Wayland and direct-to-display rendering in the future. This initial commit collects contributions from different individuals employed by Arm. More information on the project (building instructions, how to contribute, etc.) can be found on the README.md file at the top of the project tree. Signed-off-by: Matteo Franchin <matteo.franchin@arm.com>
361 lines
11 KiB
C++
361 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2017-2019 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.
|
|
*/
|
|
|
|
/**
|
|
* @file swapchain_base.hpp
|
|
*
|
|
* @brief Contains the class definition for a base swapchain.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <pthread.h>
|
|
#include <semaphore.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include <layer/private_data.hpp>
|
|
#include <util/timed_semaphore.hpp>
|
|
|
|
namespace wsi
|
|
{
|
|
|
|
/* Forward declare the page flip thread function so we can befriend it. */
|
|
void *page_flip_thread(void *ptr);
|
|
|
|
struct swapchain_image
|
|
{
|
|
enum status
|
|
{
|
|
INVALID,
|
|
ACQUIRED,
|
|
PENDING,
|
|
PRESENTED,
|
|
FREE,
|
|
};
|
|
|
|
/* Implementation specific data */
|
|
void *data;
|
|
|
|
VkImage image;
|
|
status status;
|
|
|
|
VkFence present_fence;
|
|
};
|
|
|
|
/**
|
|
* @brief Base swapchain class
|
|
*
|
|
* - the swapchain implementations inherit from this class.
|
|
* - the VkSwapchain will hold a pointer to this class.
|
|
* - much of the swapchain implementation is done by this class, as the only things needed
|
|
* in the implementation are how to create a presentable image and how to present an image.
|
|
*/
|
|
class swapchain_base
|
|
{
|
|
public:
|
|
swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *allocator);
|
|
|
|
virtual ~swapchain_base()
|
|
{
|
|
/* nop */
|
|
}
|
|
|
|
/**
|
|
* @brief Create swapchain.
|
|
*
|
|
* Perform all swapchain initialization, create presentable images etc.
|
|
*/
|
|
VkResult init(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info);
|
|
|
|
/**
|
|
* @brief Acquires a free image.
|
|
*
|
|
* Current implementation blocks until a free image is available.
|
|
*
|
|
* @param timeout Unused since we block until a free image is available.
|
|
*
|
|
* @param semaphore A semaphore signaled once an image is acquired.
|
|
*
|
|
* @param fence A fence signaled once an image is acquired.
|
|
*
|
|
* @param pImageIndex The index of the acquired image.
|
|
*
|
|
* @return VK_SUCCESS on completion.
|
|
*/
|
|
VkResult acquire_next_image(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index);
|
|
|
|
/**
|
|
* @brief Gets the number of swapchain images or a number of at most
|
|
* m_num_swapchain_images images.
|
|
*
|
|
* @param pSwapchainImageCount Used to return number of images in
|
|
* the swapchain if second parameter is nullptr or represents the
|
|
* number of images to be returned in second parameter.
|
|
*
|
|
* @param pSwapchainImage Array of VkImage handles.
|
|
*
|
|
* @return If number of requested images is less than the number of available
|
|
* images in the swapchain returns VK_INCOMPLETE otherwise VK_SUCCESS.
|
|
*/
|
|
VkResult get_swapchain_images(uint32_t *swapchain_image_count, VkImage *swapchain_image);
|
|
|
|
/**
|
|
* @brief Submits a present request for the supplied image.
|
|
*
|
|
* @param queue The queue to which the submission will be made to.
|
|
*
|
|
* @param pPresentInfo Information about the swapchain and image to be presented.
|
|
*
|
|
* @param imageIndex The index of the image to be presented.
|
|
*
|
|
* @return If queue submission fails returns error of vkQueueSubmit, if the
|
|
* swapchain has a descendant who started presenting returns VK_ERROR_OUT_OF_DATE_KHR,
|
|
* otherwise returns VK_SUCCESS.
|
|
*/
|
|
VkResult queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index);
|
|
|
|
protected:
|
|
friend void *page_flip_thread(void *ptr);
|
|
|
|
layer::device_private_data &m_device_data;
|
|
|
|
/**
|
|
* @brief Handle to the page flip thread.
|
|
*/
|
|
pthread_t m_page_flip_thread;
|
|
|
|
/**
|
|
* @brief In case we encounter threading or drm errors we need a way to
|
|
* notify the user of the failure. When this flag is false, acquire_next_image
|
|
* will return an error code.
|
|
*/
|
|
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 even occurs.
|
|
*/
|
|
sem_t m_page_flip_semaphore;
|
|
|
|
/**
|
|
* @brief A semaphore to be signalled once the swapchain has one frame on screen.
|
|
*/
|
|
sem_t m_start_present_semaphore;
|
|
|
|
/**
|
|
* @brief Defines if the pthread_t and sem_t members of the class are defined.
|
|
*
|
|
* As they are opaque types theer's no known invalid value that we ca initialize to,
|
|
* and therefore determine if we need to cleanup.
|
|
*/
|
|
bool m_thread_sem_defined;
|
|
|
|
/**
|
|
* @brief A flag to track if it is the first present for the chain.
|
|
*/
|
|
bool m_first_present;
|
|
|
|
/**
|
|
* @brief In order to present the images in a FIFO order we implement
|
|
* a ring buffer to hold the images queued for presentation. Since the
|
|
* two pointers (head and tail) are used by different
|
|
* therads and we do not allow the application to acquire more images
|
|
* than we have we eliminate race conditions.
|
|
*/
|
|
ring_buffer m_pending_buffer_pool;
|
|
|
|
/**
|
|
* @brief The number of swapchain images.
|
|
*/
|
|
uint32_t m_num_swapchain_images;
|
|
|
|
/**
|
|
* @brief Array of images in the swapchain.
|
|
*/
|
|
swapchain_image *m_swapchain_images;
|
|
|
|
/**
|
|
* @brief User provided memory allocation callbacks.
|
|
*/
|
|
const VkAllocationCallbacks *m_alloc_callbacks;
|
|
|
|
/**
|
|
* @brief Handle to the surface object this swapchain will present images to.
|
|
*/
|
|
VkSurfaceKHR m_surface;
|
|
|
|
/**
|
|
* @brief present mode to use for this swapchain
|
|
*/
|
|
VkPresentModeKHR m_present_mode;
|
|
|
|
/**
|
|
* @brief Descendant of this swapchain.
|
|
* Used to check whether or not a descendant of this swapchain has started
|
|
* presenting images to the surface already. If it has, any calls to queuePresent
|
|
* for this swapchain will return VK_ERROR_OUT_OF_DATE_KHR.
|
|
*/
|
|
VkSwapchainKHR m_descendant;
|
|
|
|
/**
|
|
* @brief Ancestor of this swapchain.
|
|
* Used to check whether the ancestor swapchain has completed all of its
|
|
* pending page flips (this is required before this swapchain presents for the
|
|
* first time.
|
|
*/
|
|
VkSwapchainKHR m_ancestor;
|
|
|
|
/**
|
|
* @brief Handle to the logical device the swapchain is created for.
|
|
*/
|
|
VkDevice m_device;
|
|
|
|
/**
|
|
* @brief Handle to the queue used for signalling submissions
|
|
*/
|
|
VkQueue m_queue;
|
|
|
|
/*
|
|
* @brief Method to wait on all pending buffers to be displayed.
|
|
*/
|
|
void wait_for_pending_buffers();
|
|
|
|
/**
|
|
* @brief Remove cached ancestor.
|
|
*/
|
|
void clear_ancestor();
|
|
|
|
/**
|
|
* @brief Remove cached descendant.
|
|
*/
|
|
void clear_descendant();
|
|
|
|
/**
|
|
* @brief Deprecate this swapchain.
|
|
*
|
|
* If an application replaces an old swapchain with a new one, the older swapchain
|
|
* needs to be deprecated. This method releases all the FREE images and sets the
|
|
* descendant of the swapchain. We do not need to care about images in other states
|
|
* at this point since they will be released by the page flip thread.
|
|
*
|
|
* @param descendant Handle to the descendant swapchain.
|
|
*/
|
|
void deprecate(VkSwapchainKHR descendant);
|
|
|
|
/**
|
|
* @brief Platform specific initialization
|
|
*/
|
|
virtual VkResult init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) = 0;
|
|
|
|
/**
|
|
* @brief Base swapchain teardown.
|
|
*
|
|
* Even though the inheritance gives us a nice way to defer display specific allocation
|
|
* and presentation outside of the base class, it however robs the children classes - which
|
|
* also happen to do some of their state setting - the oppurtunity to do the last clean up
|
|
* call, as the base class' destructor is called at the end. This method provides a way to do it.
|
|
* The destructor is a virtual function and much of the swapchain teardown happens in this method
|
|
* which gets called from the child's destructor.
|
|
*/
|
|
void teardown();
|
|
|
|
/**
|
|
* @brief Creates a new swapchain image.
|
|
*
|
|
* @param image_create_info Data to be used to create the image.
|
|
*
|
|
* @param image Handle to the image.
|
|
*
|
|
* @return If image creation is successful returns VK_SUCCESS, otherwise
|
|
* will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED
|
|
* depending on the error that occured.
|
|
*/
|
|
virtual VkResult create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) = 0;
|
|
|
|
/**
|
|
* @brief Method to present and image
|
|
*
|
|
* @param pending_index Index of the pending image to be presented.
|
|
*
|
|
*/
|
|
virtual void present_image(uint32_t pending_index) = 0;
|
|
|
|
/**
|
|
* @brief Transition a presented image to free.
|
|
*
|
|
* Called by swapchain implementation when a new image has been presented.
|
|
*
|
|
* @param presented_index Index of the image to be marked as free.
|
|
*/
|
|
void unpresent_image(uint32_t presented_index);
|
|
|
|
/**
|
|
* @brief Method to release a swapchain image
|
|
*
|
|
* @param image Handle to the image about to be released.
|
|
*/
|
|
virtual void destroy_image(swapchain_image &image){};
|
|
|
|
/**
|
|
* @brief Hook for any actions to free up a buffer for acquire
|
|
*
|
|
* @param[in,out] timeout time to wait, in nanoseconds. 0 doesn't block,
|
|
* UINT64_MAX waits indefinately. The timeout should
|
|
* be updated if a sleep is required - this can
|
|
* be set to 0 if the semaphore is now not expected
|
|
* block.
|
|
*/
|
|
virtual VkResult get_free_buffer(uint64_t *timeout)
|
|
{
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* @brief Wait for a buffer to become free.
|
|
*/
|
|
VkResult wait_for_free_buffer(uint64_t timeout);
|
|
|
|
/**
|
|
* @brief A semaphore to be signalled once a free image becomes available.
|
|
*
|
|
* Uses a custom semaphore implementation that uses a condition variable.
|
|
* it is slower, but has a safe timedwait implementation.
|
|
*
|
|
* This is kept private as waiting should be done via wait_for_free_buffer().
|
|
*/
|
|
util::timed_semaphore m_free_image_semaphore;
|
|
};
|
|
|
|
} /* namespace wsi */
|