Add support for present wait2 ext. for physical, surface and sc. Signed-off-by: Nir.Ekhauz <nir.ekhauz@arm.com> Change-Id: I0f7cdadb2d3ea0ecbc32b8b2efe9fc3bb4ba0369 |
||
|---|---|---|
| .. | ||
| display | ||
| extensions | ||
| headless | ||
| swapchain_image_create_extensions | ||
| wayland | ||
| compatible_present_modes.hpp | ||
| external_memory.cpp | ||
| external_memory.hpp | ||
| README.md | ||
| surface.hpp | ||
| surface_properties.cpp | ||
| surface_properties.hpp | ||
| swapchain_base.cpp | ||
| swapchain_base.hpp | ||
| swapchain_image_creator.cpp | ||
| swapchain_image_creator.hpp | ||
| synchronization.cpp | ||
| synchronization.hpp | ||
| unsupported_surfaces.hpp | ||
| wsi_alloc_utils.cpp | ||
| wsi_alloc_utils.hpp | ||
| wsi_factory.cpp | ||
| wsi_factory.hpp | ||
WSI integration guide
This integration guide provides information relevant for a developer wishing to extend the Vulkan® WSI Layer with support for a new windowing system. In Vulkan® a windowing system is abstracted by a WSI platform and for each platform a specific extension exists.
In the layer a Vulkan® WSI platform is represented by a WSI backend. Adding a
WSI backend means implementing a WSI extension. Two WSI extensions that are implemented
in the layer are VK_KHR_wayland_surface and VK_EXT_headless_surface.
Directory Structure
Each WSI backend implementation resides in the wsi folder and has its own
directory. A new folder should be created for a new implementation,
for example wsi/new_wsi.
Each WSI backend implements the surface, surface_properties
and swapchain interfaces. A new WSI backend implementation should be structured
as follows, where a separate file is used to contain the implementation of each
interface:
wsi/new_wsi
├── surface.cpp
├── surface.hpp
├── surface_properties.cpp
├── surface_properties.hpp
├── swapchain.cpp
└── swapchain.hpp
Build configuration
A new build option should be added to the CMakeLists.txt file to enable support for the new WSI backend. This allows compiling the layer for platforms that do not have the necessary support for the backend.
Furthermore the extension that is implemented by the new backend must be added in
the instance_extensions list in the
VkLayer_window_system_integration.json
file. For example, VK_KHR_wayland_surface is added to the JSON manifest when Wayland
support is enabled.
Interfaces implementations
surface_properties
This interface contains functions that will be called during the interception of various Vulkan® surface related entrypoints. These functions should contain the platform specific code required to support the new WSI backend. For example, some of the functions that are intercepted are:
- vkGetPhysicalDeviceSurfaceCapabilitiesKHR
- vkGetPhysicalDeviceSurfaceCapabilitiesKHR2
- vkGetPhysicalDeviceSurfaceFormatsKHR
- vkGetPhysicalDeviceSurfaceFormatsKHR2
- vkGetPhysicalDeviceSurfacePresentModesKHR
A new WSI backend should implement the functions the interface consists of, which are described in the surface_properties.hpp file.
Each WSI extension defines surface/platform specific entrypoints, which are only used by
each individual surface. These entrypoints are exposed to the application through
the surface_properties::get_proc_addr function, which returns a function pointer
to the implementation of the requested entrypoint. For example, if the extension for
a new WSI backend defines the entrypoint vkCreateNewXyzSurface, then get_proc_addr
should look like this.
VWL_VKAPI_CALL(VkResult) CreateNewXyzSurface(...) VWL_API_POST
{
...
}
PFN_vkVoidFunction surface_properties::get_proc_addr(const char *name)
{
if (strcmp(name, "vkCreateNewXyzSurface") == 0)
{
return reinterpret_cast<PFN_vkVoidFunction>(CreateNewXyzSurface);
}
...
}
NOTE: The VWL_* macros are defined in macros.hpp and are used to mark function signatures.
NOTE: The extensions and their entrypoints are partially implemented by the Vulkan® loader so an appropriate loader should be used.
If any of the extension's specific entrypoints needs to call the next implementation
in the chain (e.g. call the ICD's entrypoint implementation), depending on
whether it is an instance or device entrypoint either the
INSTANCE_ENTRYPOINTS_LIST or DEVICE_ENTRYPOINTS_LIST must be extended with
the name of the entrypoint. For example, for the vkCreateNewXyzSurface the instance
list should be extended.
diff --git a/layer/private_data.hpp b/layer/private_data.hpp
--- a/layer/private_data.hpp
+++ b/layer/private_data.hpp
@@ -73,6 +73,9 @@ namespace layer
OPTIONAL(CreateHeadlessSurfaceEXT) \
/* VK_KHR_wayland_surface */ \
OPTIONAL(CreateWaylandSurfaceKHR) \
+ /* VK_KHR_new_wsi */ \
+ OPTIONAL(CreateNewXyzSurface) \
/* VK_KHR_get_surface_capabilities2 */ \
OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \
OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \
Furthermore, these lists must be extended when the implementation needs to make use of
entrypoints defined by other extensions. For example, if a WSI implementation
needs to import a fence payload from a POSIX file descriptor the vkImportFenceFdKHR
function can be used, which is provided by the VK_KHR_external_fence_fd
extension. In order for the entrypoint to become visible to the implementation,
OPTIONAL(ImportFenceFdKHR) must be added to the DEVICE_ENTRYPOINTS_LIST
(also an ICD that implements the extension must be used).
When a new entry is added to either of these lists the disp member variable of
the singleton instance_private_data or device_private_data object is extended with a
function pointer that has the same name as the one that was added in the list.
The entrypoint can be called by getting the instance_private_data/device_private_data
object and then using the function pointer in the disp attribute.
For example, a WSI implementation that calls down the chain for the
vkCreateNewXyzSurface function, should do the following.
auto &instance_data = layer::instance_private_data::get(instance);
VkResult res = instance_data.disp.CreateNewXyzSurface(...);
In order for the new surface_properties implementation to be picked up by the
common layer code the following changes must be applied to the
wsi_factory.cpp file.
- Conditionally include the header of the WSI specific
surface_propertiesimplementation. - Extend the
supported_wsi_extensionswith the new WSI. - Add a new case with the new WSI platform in
get_surface_properties.
diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp
--- a/wsi/wsi_factory.cpp
+++ b/wsi/wsi_factory.cpp
@@ -46,6 +46,10 @@
#include "wayland/surface_properties.hpp"
#endif
+#if BUILD_NEW_WSI
+#include "new_wsi/surface_properties.hpp"
+#endif /* BUILD_NEW_WSI */
+
namespace wsi
{
@@ -60,6 +64,9 @@ static struct wsi_extension
#if BUILD_WSI_WAYLAND
{ { VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_WAYLAND },
#endif
+#if BUILD_NEW_WSI
+ { { VK_KHR_NEW_WSI_EXTENSION_NAME, VK_KHR_NEW_WSI_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_NEW_WSI },
+#endif /* BUILD_NEW_WSI */
};
static surface_properties *get_surface_properties(VkIcdWsiPlatform platform)
@@ -74,6 +81,10 @@ static surface_properties *get_surface_properties(VkIcdWsiPlatform platform)
case VK_ICD_WSI_PLATFORM_WAYLAND:
return &wayland::surface_properties::get_instance();
#endif
+#if BUILD_NEW_WSI
+ case VK_ICD_WSI_PLATFORM_NEW_WSI:
+ return &new_wsi::surface_properties::get_instance();
+#endif /* BUILD_NEW_WSI */
default:
return nullptr;
}
surface
The surface interface represents a VkSurface. Each WSI backend's implementation
of this interface represents the platform specific surface. The wsi::surface
objects are associated with the corresponding VkSurface objects in
instance_private_data and they should be created
and linked to the instance_data during the specific VkSurface creation entrypoint.
A new WSI backend should implement the functions the interface consists of, which are described in surface.hpp.
swapchain
The common swapchain functionality is implemented in the swapchain_base class.
A new WSI backend should implement the virtual functions defined in
swapchain_base.hpp.
The base swapchain implementation has support for the FIFO presentation mode, which makes use of the presentation thread. Also, it gives the option to disable the thread in order to support other present modes like Mailbox. All of the WSI implementations can use the FIFO mode without any modifications. If a WSI implementation wants to leverage the Mailbox present mode extra synchronization with the presentation engine may be needed.
The use of the presentation thread is enabled in the init_platform function
by setting the use_presentation_thread flag.
In the layer the swapchain images are represented by the swapchain_image struct.
This struct has a member variable which is called data and is of void * type.
This member variable is used to store the unique data that are needed by the images in
each WSI implementation.
Before submitting an image to the presentation engine the swapchain must wait
for the rendering operations on this image to finish. The synchronization primitives
used for this waiting operation by the WSI implementations are abstracted by the
classes defined in the synchronization.hpp file. Currently only
Vulkan® fences and fences exportable to Sync FD are supported. The specific behaviour
that depends on the type of the synchronization primitive a backend uses is implemented
in the image_set_present_payload and image_wait_present functions.
Helpers
Helper objects and utilities can be found in util. These helpers can
be used to aid development. For example, alternatives to the standard containers
(std::vector, std::unordered_map, ...) are provided to make it easier for the
Vulkan® WSI Layer code to conform to the allocation requirements of Vulkan®. Also,
logging macros have been defined there for logging messages with different priority.
A non exhaustive list follows with the useful helper objects and functions
implemented there:
util::vectorutil::allocatorutil::allocator::make_uniqueutil::fd_ownerutil::ring_bufferutil::unordered_maputil::unordered_set
And macros:
TRYWSI_LOG_*