mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2026-04-26 21:50:46 +02:00
Implement support for marking frame boundaries
This commit is contained in:
parent
2449525741
commit
94dd9840c9
20 changed files with 401 additions and 38 deletions
|
|
@ -54,14 +54,24 @@ else()
|
|||
endif()
|
||||
|
||||
# Build Configuration options
|
||||
|
||||
# Backend support
|
||||
option(BUILD_WSI_HEADLESS "Build with support for VK_EXT_headless_surface" ON)
|
||||
option(BUILD_WSI_WAYLAND "Build with support for VK_KHR_wayland_surface" OFF)
|
||||
option(BUILD_WSI_DISPLAY "Build with support for VK_KHR_display" OFF)
|
||||
|
||||
set(SELECT_EXTERNAL_ALLOCATOR "none" CACHE STRING "Select an external system allocator (none, ion)")
|
||||
set(EXTERNAL_WSIALLOC_LIBRARY "" CACHE STRING "External implementation of the wsialloc interface to use")
|
||||
|
||||
# Optional features
|
||||
option(BUILD_WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN "Build with support for VK_EXT_image_compression_control_swapchain" OFF)
|
||||
option(BUILD_WSI_DISPLAY_SUPPORT_FORMAT_MODIFIERS "Build with support for format modifiers in VK_KHR_display" ON)
|
||||
option(VULKAN_WSI_LAYER_EXPERIMENTAL "Enable the Vulkan WSI Experimental features" OFF)
|
||||
set(SELECT_EXTERNAL_ALLOCATOR "none" CACHE STRING "Select an external system allocator (none, ion)")
|
||||
set(EXTERNAL_WSIALLOC_LIBRARY "" CACHE STRING "External implementation of the wsialloc interface to use")
|
||||
|
||||
# Enables the layer to pass frame boundary events if the ICD or layers below have support for it by
|
||||
# making use of the VK_EXT_frame_boundary extension. If the application itself makes use of the
|
||||
# VK_EXT_frame_boundary then the layer will not pass its own frame boundary events.
|
||||
option(ENABLE_INSTRUMENTATION "Pass frame boundary events by using VK_EXT_frame_boundary" OFF)
|
||||
|
||||
if(BUILD_WSI_WAYLAND OR BUILD_WSI_DISPLAY)
|
||||
set(BUILD_DRM_UTILS true)
|
||||
|
|
@ -232,6 +242,7 @@ add_library(${PROJECT_NAME} SHARED
|
|||
util/log.cpp
|
||||
util/format_modifiers.cpp
|
||||
wsi/external_memory.cpp
|
||||
wsi/frame_boundary.cpp
|
||||
wsi/surface_properties.cpp
|
||||
wsi/swapchain_base.cpp
|
||||
wsi/synchronization.cpp
|
||||
|
|
@ -262,6 +273,12 @@ else()
|
|||
add_definitions("-DWSI_DISPLAY_SUPPORT_FORMAT_MODIFIERS=0")
|
||||
endif()
|
||||
|
||||
if(ENABLE_INSTRUMENTATION)
|
||||
add_definitions("-DENABLE_INSTRUMENTATION=1")
|
||||
else()
|
||||
add_definitions("-DENABLE_INSTRUMENTATION=0")
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_WSI_LIBS})
|
||||
|
||||
add_custom_target(manifest_json ALL COMMAND
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -115,6 +115,19 @@ provides a generic ion implementation that may work in systems that support
|
|||
linear formats. This is selected by the `-DSELECT_EXTERNAL_ALLOCATOR=ion`
|
||||
option, as shown above.
|
||||
|
||||
### Building with frame instrumentation support
|
||||
|
||||
The layer can be built to pass frame boundary information down to other
|
||||
layers or ICD by making use of the [VK_EXT_frame_boundary extension](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_frame_boundary.html).
|
||||
|
||||
By enabling this feature, if application is not making use of the
|
||||
VK_EXT_frame_boundary extension, the layer will generate and pass down
|
||||
frame boundary events which enables the ability to instrument present submissions
|
||||
for applications that do not make use of this extension.
|
||||
|
||||
In order to enable this feature `-DENABLE_INSTRUMENTATION=1` option can
|
||||
be passed at build time.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy the shared library `libVkLayer_window_system_integration.so` and JSON
|
||||
|
|
|
|||
|
|
@ -244,12 +244,17 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
auto &inst_data = instance_private_data::get(physicalDevice);
|
||||
util::allocator allocator{ inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, pAllocator };
|
||||
util::vector<const char *> modified_enabled_extensions{ allocator };
|
||||
util::extension_list enabled_extensions{ allocator };
|
||||
|
||||
util::extension_list application_requested_extensions{ allocator };
|
||||
TRY_LOG_CALL(
|
||||
application_requested_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount));
|
||||
|
||||
util::extension_list enabled_extensions{ allocator };
|
||||
const util::wsi_platform_set &enabled_platforms = inst_data.get_enabled_platforms();
|
||||
if (!enabled_platforms.empty())
|
||||
{
|
||||
TRY_LOG_CALL(enabled_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount));
|
||||
TRY_LOG_CALL(enabled_extensions.add(application_requested_extensions));
|
||||
|
||||
TRY_LOG_CALL(wsi::add_device_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions));
|
||||
TRY_LOG_CALL(enabled_extensions.get_extension_strings(modified_enabled_extensions));
|
||||
|
||||
|
|
@ -257,6 +262,29 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
modified_info.enabledExtensionCount = modified_enabled_extensions.size();
|
||||
}
|
||||
|
||||
bool should_layer_handle_frame_boundary_events = false;
|
||||
VkPhysicalDeviceFrameBoundaryFeaturesEXT frame_boundary;
|
||||
|
||||
/* Check if we should handle frame boundary feature ourselves. The conditions for handling this ourselves is:
|
||||
* 1 - Application did not ask to enable VK_EXT_frame_boundary extension
|
||||
* 2 - The layer has been built with instrumentation enabled
|
||||
* 3 - The underlying layers/ICD can support the VK_EXT_frame_boundary extension */
|
||||
if (!application_requested_extensions.contains(VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME) && ENABLE_INSTRUMENTATION)
|
||||
{
|
||||
if (enabled_extensions.contains(VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME))
|
||||
{
|
||||
if (inst_data.has_frame_boundary_support(physicalDevice))
|
||||
{
|
||||
frame_boundary.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT;
|
||||
frame_boundary.pNext = const_cast<void *>(modified_info.pNext);
|
||||
frame_boundary.frameBoundary = VK_TRUE;
|
||||
|
||||
modified_info.pNext = &frame_boundary;
|
||||
should_layer_handle_frame_boundary_events = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now call create device on the chain further down the list. */
|
||||
TRY_LOG(fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice), "Failed to create the device");
|
||||
|
||||
|
|
@ -296,8 +324,11 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
* Store the enabled device extensions in order to return nullptr in
|
||||
* vkGetDeviceProcAddr for functions of disabled extensions.
|
||||
*/
|
||||
result = layer::device_private_data::get(*pDevice).set_device_enabled_extensions(
|
||||
modified_info.ppEnabledExtensionNames, modified_info.enabledExtensionCount);
|
||||
auto &device_data = layer::device_private_data::get(*pDevice);
|
||||
device_data.set_layer_frame_boundary_handling_enabled(should_layer_handle_frame_boundary_events);
|
||||
|
||||
result = device_data.set_device_enabled_extensions(modified_info.ppEnabledExtensionNames,
|
||||
modified_info.enabledExtensionCount);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
layer::device_private_data::disassociate(*pDevice);
|
||||
|
|
@ -311,7 +342,7 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT, pCreateInfo->pNext);
|
||||
if (swapchain_compression_feature != nullptr)
|
||||
{
|
||||
layer::device_private_data::get(*pDevice).set_swapchain_compression_control_enabled(
|
||||
device_data.set_swapchain_compression_control_enabled(
|
||||
swapchain_compression_feature->imageCompressionControlSwapchain);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -320,7 +351,7 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR, pCreateInfo->pNext);
|
||||
if (present_id_features != nullptr)
|
||||
{
|
||||
layer::device_private_data::get(*pDevice).set_present_id_feature_enabled(present_id_features->presentId);
|
||||
device_data.set_present_id_feature_enabled(present_id_features->presentId);
|
||||
}
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
|
|
@ -329,7 +360,7 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
|
|||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, pCreateInfo->pNext);
|
||||
if (physical_device_swapchain_maintenance1_features != nullptr)
|
||||
{
|
||||
layer::device_private_data::get(*pDevice).set_swapchain_maintenance1_enabled(
|
||||
device_data.set_swapchain_maintenance1_enabled(
|
||||
physical_device_swapchain_maintenance1_features->swapchainMaintenance1);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -370,6 +370,18 @@ bool instance_private_data::has_image_compression_support(VkPhysicalDevice phys_
|
|||
}
|
||||
#endif
|
||||
|
||||
bool instance_private_data::has_frame_boundary_support(VkPhysicalDevice phys_dev)
|
||||
{
|
||||
VkPhysicalDeviceFrameBoundaryFeaturesEXT frame_boundary = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT, nullptr, VK_FALSE
|
||||
};
|
||||
VkPhysicalDeviceFeatures2KHR features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR, &frame_boundary };
|
||||
|
||||
disp.GetPhysicalDeviceFeatures2KHR(phys_dev, &features);
|
||||
|
||||
return frame_boundary.frameBoundary != VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult instance_private_data::set_instance_enabled_extensions(const char *const *extension_names,
|
||||
size_t extension_count)
|
||||
{
|
||||
|
|
@ -549,6 +561,16 @@ bool device_private_data::is_swapchain_compression_control_enabled() const
|
|||
}
|
||||
#endif /* WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN */
|
||||
|
||||
void device_private_data::set_layer_frame_boundary_handling_enabled(bool enable)
|
||||
{
|
||||
handle_frame_boundary_events = enable;
|
||||
}
|
||||
|
||||
bool device_private_data::should_layer_handle_frame_boundary_events() const
|
||||
{
|
||||
return handle_frame_boundary_events;
|
||||
}
|
||||
|
||||
void device_private_data::set_present_id_feature_enabled(bool enable)
|
||||
{
|
||||
present_id_enabled = enable;
|
||||
|
|
|
|||
|
|
@ -597,6 +597,8 @@ public:
|
|||
bool has_image_compression_support(VkPhysicalDevice phys_dev);
|
||||
#endif /* WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN */
|
||||
|
||||
bool has_frame_boundary_support(VkPhysicalDevice phys_dev);
|
||||
|
||||
/**
|
||||
* @brief Get the instance allocator
|
||||
*
|
||||
|
|
@ -805,6 +807,20 @@ public:
|
|||
bool is_swapchain_compression_control_enabled() const;
|
||||
#endif /* WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN */
|
||||
|
||||
/**
|
||||
* @brief Set whether we should handle frame boundary events.
|
||||
*
|
||||
* @param enable true if the layer should handle them.
|
||||
*/
|
||||
void set_layer_frame_boundary_handling_enabled(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Check whether we should handle frame boundary events.
|
||||
*
|
||||
* @return true if supported, false otherwise.
|
||||
*/
|
||||
bool should_layer_handle_frame_boundary_events() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether the device supports the present ID feature.
|
||||
*
|
||||
|
|
@ -869,6 +885,11 @@ private:
|
|||
bool compression_control_enabled;
|
||||
#endif /* WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN */
|
||||
|
||||
/**
|
||||
* @brief Stores whether the layer should handle frame boundary events.
|
||||
*/
|
||||
bool handle_frame_boundary_events{ false };
|
||||
|
||||
/**
|
||||
* @brief Stores whether the device supports the present ID feature.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ wsi_layer_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapc, uint64_t
|
|||
}
|
||||
|
||||
static VkResult submit_wait_request(VkQueue queue, const VkPresentInfoKHR &present_info,
|
||||
layer::device_private_data &device_data)
|
||||
layer::device_private_data &device_data, bool &frame_boundary_event_handled)
|
||||
{
|
||||
util::vector<VkSemaphore> swapchain_semaphores{ util::allocator(device_data.get_allocator(),
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND) };
|
||||
|
|
@ -143,7 +143,17 @@ static VkResult submit_wait_request(VkQueue queue, const VkPresentInfoKHR &prese
|
|||
swapchain_semaphores.data(),
|
||||
static_cast<uint32_t>(swapchain_semaphores.size()) };
|
||||
|
||||
TRY(wsi::sync_queue_submit(device_data, queue, VK_NULL_HANDLE, semaphores));
|
||||
void *submission_pnext = nullptr;
|
||||
auto frame_boundary = wsi::create_frame_boundary(present_info);
|
||||
if (frame_boundary.has_value())
|
||||
{
|
||||
submission_pnext = &frame_boundary.value();
|
||||
}
|
||||
|
||||
/* Notify that we don't want to pass any further frame boundary events */
|
||||
frame_boundary_event_handled = submission_pnext != nullptr;
|
||||
|
||||
TRY(wsi::sync_queue_submit(device_data, queue, VK_NULL_HANDLE, semaphores, &submission_pnext));
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +173,10 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
|
|||
/* Avoid allocating on the heap when there is only one swapchain. */
|
||||
const VkPresentInfoKHR *present_info = pPresentInfo;
|
||||
bool use_image_present_semaphore = false;
|
||||
bool frame_boundary_event_handled = true;
|
||||
if (pPresentInfo->swapchainCount > 1)
|
||||
{
|
||||
TRY_LOG_CALL(submit_wait_request(queue, *pPresentInfo, device_data));
|
||||
TRY_LOG_CALL(submit_wait_request(queue, *pPresentInfo, device_data, frame_boundary_event_handled));
|
||||
use_image_present_semaphore = true;
|
||||
}
|
||||
|
||||
|
|
@ -201,6 +212,7 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
|
|||
present_params.pending_present.present_id = present_id;
|
||||
|
||||
present_params.use_image_present_semaphore = use_image_present_semaphore;
|
||||
present_params.handle_present_frame_boundary_event = frame_boundary_event_handled;
|
||||
VkResult res = sc->queue_present(queue, present_info, present_params);
|
||||
if (pPresentInfo->pResults != nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Arm Limited.
|
||||
* Copyright (c) 2021-2022, 2024 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -99,6 +99,15 @@ T *find_extension(VkStructureType sType, void *pNext)
|
|||
return reinterpret_cast<T *>(entry);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T shallow_copy_extension(const T *structure_to_copy)
|
||||
{
|
||||
T shallow_copy = *structure_to_copy;
|
||||
shallow_copy.pNext = nullptr;
|
||||
|
||||
return shallow_copy;
|
||||
}
|
||||
|
||||
class noncopyable
|
||||
{
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -520,11 +520,11 @@ void swapchain::present_image(const pending_present_request &pending_present)
|
|||
}
|
||||
|
||||
VkResult swapchain::image_set_present_payload(swapchain_image &image, VkQueue queue, const VkSemaphore *sem_payload,
|
||||
uint32_t sem_count)
|
||||
uint32_t sem_count, const void *submission_pnext)
|
||||
{
|
||||
|
||||
auto image_data = reinterpret_cast<display_image_data *>(image.data);
|
||||
return image_data->present_fence.set_payload(queue, sem_payload, sem_count);
|
||||
return image_data->present_fence.set_payload(queue, sem_payload, sem_count, submission_pnext);
|
||||
}
|
||||
|
||||
VkResult swapchain::image_wait_present(swapchain_image &image, uint64_t timeout)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public:
|
|||
void present_image(const pending_present_request &pending_present) override;
|
||||
|
||||
virtual VkResult image_set_present_payload(swapchain_image &image, VkQueue queue, const VkSemaphore *sem_payload,
|
||||
uint32_t sem_count) override;
|
||||
uint32_t sem_count, const void *submission_pnext) override;
|
||||
virtual VkResult image_wait_present(swapchain_image &image, uint64_t timeout) override;
|
||||
|
||||
void destroy_image(swapchain_image &image) override;
|
||||
|
|
|
|||
95
wsi/frame_boundary.cpp
Normal file
95
wsi/frame_boundary.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2024 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 frame_boundary.cpp
|
||||
*
|
||||
* @brief Contains the functionality for frame boundary handling.
|
||||
*/
|
||||
|
||||
#include "frame_boundary.hpp"
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
frame_boundary_handler::frame_boundary_handler(const layer::device_private_data &device_data)
|
||||
: m_handle_frame_boundary_events(device_data.should_layer_handle_frame_boundary_events())
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<VkFrameBoundaryEXT> frame_boundary_handler::handle_frame_boundary_event(
|
||||
const VkPresentInfoKHR *present_info, VkImage *current_image_to_be_presented)
|
||||
{
|
||||
/* If frame boundary feature is not enabled by the application, the layer will pass its own frame boundary events back to ICD.
|
||||
* Otherwise, let the application handle the frame boundary events. */
|
||||
return m_handle_frame_boundary_events ? create_frame_boundary(current_image_to_be_presented) :
|
||||
wsi::create_frame_boundary(*present_info);
|
||||
}
|
||||
|
||||
std::optional<VkFrameBoundaryEXT> create_frame_boundary(const VkPresentInfoKHR &present_info)
|
||||
{
|
||||
auto *present_frame_boundary =
|
||||
util::find_extension<VkFrameBoundaryEXT>(VK_STRUCTURE_TYPE_PRESENT_ID_KHR, present_info.pNext);
|
||||
|
||||
/* Extract the VkFrameBoundaryEXT structure to avoid passing other, unrelated structures to vkQueueSubmit */
|
||||
if (present_frame_boundary != nullptr)
|
||||
{
|
||||
return util::shallow_copy_extension(present_frame_boundary);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool frame_boundary_handler::should_layer_handle_frame_boundary_events() const
|
||||
{
|
||||
return m_handle_frame_boundary_events;
|
||||
}
|
||||
|
||||
VkFrameBoundaryEXT frame_boundary_handler::create_frame_boundary(VkImage *image)
|
||||
{
|
||||
VkFrameBoundaryEXT frame_boundary{};
|
||||
frame_boundary.sType = VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT;
|
||||
frame_boundary.flags = VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT;
|
||||
/* Number of presented images by swapchain as the frame boundary
|
||||
* would not work as when the page flip thread is running, the
|
||||
* number frame ID could remain the same until the image is picked
|
||||
* up by the thread so we use our own counter for the frame boundary. */
|
||||
frame_boundary.frameID = m_current_frame_boundary_id++;
|
||||
frame_boundary.imageCount = 1;
|
||||
frame_boundary.pImages = image;
|
||||
frame_boundary.pBuffers = nullptr;
|
||||
frame_boundary.bufferCount = 0;
|
||||
|
||||
/* Create an unique identifier for the layer in case tools make use of it.
|
||||
* The number below is derived from converting characters 'WSI' into
|
||||
* their numerical representation from the ASCII table. */
|
||||
frame_boundary.tagName = 0x575349;
|
||||
|
||||
/* No additional data attached */
|
||||
frame_boundary.tagSize = 0;
|
||||
frame_boundary.pTag = nullptr;
|
||||
|
||||
return frame_boundary;
|
||||
}
|
||||
|
||||
}
|
||||
89
wsi/frame_boundary.hpp
Normal file
89
wsi/frame_boundary.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2024 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 frame_boundary.hpp
|
||||
*
|
||||
* @brief Contains the functionality for frame boundary handling.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <layer/private_data.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
class frame_boundary_handler
|
||||
{
|
||||
public:
|
||||
frame_boundary_handler(const layer::device_private_data &device_data);
|
||||
|
||||
/**
|
||||
* @brief Handle frame boundary event at present time
|
||||
*
|
||||
* @param present_info Information about the swapchain and image to be presented.
|
||||
* @param current_image_to_be_presented Address to the currently to be presented image
|
||||
*/
|
||||
std::optional<VkFrameBoundaryEXT> handle_frame_boundary_event(const VkPresentInfoKHR *present_info,
|
||||
VkImage *current_image_to_be_presented);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Create a frame boundary with the current image
|
||||
*
|
||||
* @param image Address to the currently to be presented image
|
||||
* @return Frame boundary structure
|
||||
*/
|
||||
VkFrameBoundaryEXT create_frame_boundary(VkImage *image);
|
||||
|
||||
/**
|
||||
* @brief Check whether we should handle frame boundary events.
|
||||
*
|
||||
* @return true if supported, false otherwise.
|
||||
*/
|
||||
bool should_layer_handle_frame_boundary_events() const;
|
||||
|
||||
/**
|
||||
* @brief Holds the number of the current frame identifier for the swapchain
|
||||
*/
|
||||
uint64_t m_current_frame_boundary_id{ 0 };
|
||||
|
||||
/**
|
||||
* @brief Stores whether the layer should handle frame boundary events.
|
||||
*/
|
||||
const bool m_handle_frame_boundary_events;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a frame boundary object
|
||||
*
|
||||
* @param present_info Present info
|
||||
* @return Frame boundary if @p present_info has passed it.
|
||||
*/
|
||||
std::optional<VkFrameBoundaryEXT> create_frame_boundary(const VkPresentInfoKHR &present_info);
|
||||
|
||||
}
|
||||
|
|
@ -197,10 +197,10 @@ void swapchain::destroy_image(wsi::swapchain_image &image)
|
|||
}
|
||||
|
||||
VkResult swapchain::image_set_present_payload(swapchain_image &image, VkQueue queue,
|
||||
const queue_submit_semaphores &semaphores)
|
||||
const queue_submit_semaphores &semaphores, const void *submission_pnext)
|
||||
{
|
||||
auto data = reinterpret_cast<image_data *>(image.data);
|
||||
return data->present_fence.set_payload(queue, semaphores);
|
||||
return data->present_fence.set_payload(queue, semaphores, submission_pnext);
|
||||
}
|
||||
|
||||
VkResult swapchain::image_wait_present(swapchain_image &image, uint64_t timeout)
|
||||
|
|
|
|||
|
|
@ -97,8 +97,18 @@ protected:
|
|||
*/
|
||||
void destroy_image(wsi::swapchain_image &image);
|
||||
|
||||
VkResult image_set_present_payload(swapchain_image &image, VkQueue queue,
|
||||
const queue_submit_semaphores &semaphores) override;
|
||||
/**
|
||||
* @brief Sets the present payload for a swapchain image.
|
||||
*
|
||||
* @param[in] image The swapchain image for which to set a present payload.
|
||||
* @param queue A Vulkan queue that can be used for any Vulkan commands needed.
|
||||
* @param[in] sem_payload Array of Vulkan semaphores that constitute the payload.
|
||||
* @param[in] submission_pnext Chain of pointers to attach to the payload submission.
|
||||
*
|
||||
* @return VK_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
VkResult image_set_present_payload(swapchain_image &image, VkQueue queue, const queue_submit_semaphores &semaphores,
|
||||
const void *submission_pnext) override;
|
||||
|
||||
VkResult image_wait_present(swapchain_image &image, uint64_t timeout) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAll
|
|||
, m_image_acquire_lock()
|
||||
, m_error_state(VK_NOT_READY)
|
||||
, m_started_presenting(false)
|
||||
, m_frame_boundary_handler(m_device_data)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -690,6 +691,19 @@ VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *pr
|
|||
image_wait_present(m_swapchain_images[submit_info.pending_present.image_index], WAIT_PRESENT_TIMEOUT));
|
||||
}
|
||||
|
||||
void *submission_pnext = nullptr;
|
||||
std::optional<VkFrameBoundaryEXT> frame_boundary;
|
||||
/* Do not handle the event if it was handled before reaching this point */
|
||||
if (submit_info.handle_present_frame_boundary_event)
|
||||
{
|
||||
frame_boundary = m_frame_boundary_handler.handle_frame_boundary_event(
|
||||
present_info, &m_swapchain_images[submit_info.pending_present.image_index].image);
|
||||
if (frame_boundary.has_value())
|
||||
{
|
||||
submission_pnext = &frame_boundary.value();
|
||||
}
|
||||
}
|
||||
|
||||
queue_submit_semaphores semaphores = {
|
||||
wait_semaphores,
|
||||
sem_count,
|
||||
|
|
@ -698,8 +712,8 @@ VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *pr
|
|||
nullptr,
|
||||
(submit_info.present_fence != VK_NULL_HANDLE) ? 1u : 0,
|
||||
};
|
||||
TRY_LOG_CALL(
|
||||
image_set_present_payload(m_swapchain_images[submit_info.pending_present.image_index], queue, semaphores));
|
||||
TRY_LOG_CALL(image_set_present_payload(m_swapchain_images[submit_info.pending_present.image_index], queue,
|
||||
semaphores, submission_pnext));
|
||||
|
||||
if (submit_info.present_fence != VK_NULL_HANDLE)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <util/ring_buffer.hpp>
|
||||
#include "surface_properties.hpp"
|
||||
#include "wsi/synchronization.hpp"
|
||||
#include "wsi/frame_boundary.hpp"
|
||||
#include "util/helpers.hpp"
|
||||
|
||||
namespace wsi
|
||||
|
|
@ -103,6 +104,12 @@ struct swapchain_presentation_parameters
|
|||
|
||||
/* Contains details about the pending present request */
|
||||
pending_present_request pending_present{};
|
||||
|
||||
/**
|
||||
* Flag that indicates whether a frame boundary should be passed
|
||||
* to underlying layers/ICD if the feature is enabled.
|
||||
*/
|
||||
VkBool32 handle_present_frame_boundary_event{ true };
|
||||
};
|
||||
|
||||
#if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN
|
||||
|
|
@ -516,14 +523,16 @@ protected:
|
|||
/**
|
||||
* @brief Sets the present payload for a swapchain image.
|
||||
*
|
||||
* @param[in] image The swapchain image for which to set a present payload.
|
||||
* @param queue A Vulkan queue that can be used for any Vulkan commands needed.
|
||||
* @param[in] semaphores The wait and signal semaphores and their number of elements.
|
||||
* @param[in] image The swapchain image for which to set a present payload.
|
||||
* @param queue A Vulkan queue that can be used for any Vulkan commands needed.
|
||||
* @param[in] semaphores The wait and signal semaphores and their number of elements.
|
||||
* @param[in] submission_pnext Chain of pointers to attach to the payload submission.
|
||||
*
|
||||
* @return VK_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
virtual VkResult image_set_present_payload(swapchain_image &image, VkQueue queue,
|
||||
const queue_submit_semaphores &semaphores) = 0;
|
||||
const queue_submit_semaphores &semaphores,
|
||||
const void *submission_pnext = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* @brief Waits for the present payload of an image if necessary.
|
||||
|
|
@ -695,6 +704,12 @@ private:
|
|||
* @brief Current present ID for this swapchain.
|
||||
*/
|
||||
uint64_t m_present_id{ 0 };
|
||||
|
||||
/**
|
||||
* @brief Handler for frame boundary events
|
||||
*
|
||||
*/
|
||||
frame_boundary_handler m_frame_boundary_handler;
|
||||
};
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ VkResult fence_sync::wait_payload(uint64_t timeout)
|
|||
return res;
|
||||
}
|
||||
|
||||
VkResult fence_sync::set_payload(VkQueue queue, const queue_submit_semaphores &semaphores)
|
||||
VkResult fence_sync::set_payload(VkQueue queue, const queue_submit_semaphores &semaphores, const void *submission_pnext)
|
||||
{
|
||||
VkResult result = dev->disp.ResetFences(dev->device, 1, &fence);
|
||||
if (result != VK_SUCCESS)
|
||||
|
|
@ -103,7 +103,7 @@ VkResult fence_sync::set_payload(VkQueue queue, const queue_submit_semaphores &s
|
|||
}
|
||||
has_payload = false;
|
||||
|
||||
result = sync_queue_submit(*dev, queue, fence, semaphores);
|
||||
result = sync_queue_submit(*dev, queue, fence, semaphores, submission_pnext);
|
||||
if (result == VK_SUCCESS)
|
||||
{
|
||||
has_payload = true;
|
||||
|
|
@ -170,7 +170,7 @@ std::optional<util::fd_owner> sync_fd_fence_sync::export_sync_fd()
|
|||
}
|
||||
|
||||
VkResult sync_queue_submit(const layer::device_private_data &device, VkQueue queue, VkFence fence,
|
||||
const queue_submit_semaphores &semaphores)
|
||||
const queue_submit_semaphores &semaphores, const void *submission_pnext)
|
||||
{
|
||||
/* When the semaphore that comes in is signalled, we know that all work is done. So, we do not
|
||||
* want to block any future Vulkan queue work on it. So, we pass in BOTTOM_OF_PIPE bit as the
|
||||
|
|
@ -194,7 +194,7 @@ VkResult sync_queue_submit(const layer::device_private_data &device, VkQueue que
|
|||
}
|
||||
|
||||
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
nullptr,
|
||||
submission_pnext,
|
||||
semaphores.wait_semaphores_count,
|
||||
semaphores.wait_semaphores,
|
||||
pipeline_stage_flag_data,
|
||||
|
|
|
|||
|
|
@ -95,11 +95,13 @@ public:
|
|||
* @note This method is not threadsafe.
|
||||
*
|
||||
* @param queue The Vulkan queue that may be used to submit synchronization commands.
|
||||
* @param semaphores The wait and signal semaphores.
|
||||
* @param semaphores The wait and signal semaphores.
|
||||
* @param submission_pnext Chain of pointers to attach to the payload submission.
|
||||
*
|
||||
* @return VK_SUCCESS on success or other error code on failing to set the payload.
|
||||
*/
|
||||
VkResult set_payload(VkQueue queue, const queue_submit_semaphores &semaphores);
|
||||
VkResult set_payload(VkQueue queue, const queue_submit_semaphores &semaphores,
|
||||
const void *submission_pnext = nullptr);
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
@ -190,9 +192,10 @@ private:
|
|||
* @param fence The fence to be signalled, it could be VK_NULL_HANDLE in the absence
|
||||
* of a fence to be signalled.
|
||||
* @param semaphores The wait and signal semaphores.
|
||||
* @param submission_pnext Chain of pointers to attach to the payload submission.
|
||||
*
|
||||
* @return VK_SUCCESS on success, an appropiate error code otherwise.
|
||||
*/
|
||||
VkResult sync_queue_submit(const layer::device_private_data &device, VkQueue queue, VkFence fence,
|
||||
const queue_submit_semaphores &semaphores);
|
||||
const queue_submit_semaphores &semaphores, const void *submission_pnext = nullptr);
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -599,10 +599,10 @@ VkResult swapchain::get_free_buffer(uint64_t *timeout)
|
|||
}
|
||||
|
||||
VkResult swapchain::image_set_present_payload(swapchain_image &image, VkQueue queue,
|
||||
const queue_submit_semaphores &semaphores)
|
||||
const queue_submit_semaphores &semaphores, const void *submission_pnext)
|
||||
{
|
||||
auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
|
||||
return image_data->present_fence.set_payload(queue, semaphores);
|
||||
return image_data->present_fence.set_payload(queue, semaphores, submission_pnext);
|
||||
}
|
||||
|
||||
VkResult swapchain::image_wait_present(swapchain_image &, uint64_t)
|
||||
|
|
|
|||
|
|
@ -149,8 +149,18 @@ protected:
|
|||
*/
|
||||
VkResult get_free_buffer(uint64_t *timeout) override;
|
||||
|
||||
VkResult image_set_present_payload(swapchain_image &image, VkQueue queue,
|
||||
const queue_submit_semaphores &semaphores) override;
|
||||
/**
|
||||
* @brief Sets the present payload for a swapchain image.
|
||||
*
|
||||
* @param[in] image The swapchain image for which to set a present payload.
|
||||
* @param queue A Vulkan queue that can be used for any Vulkan commands needed.
|
||||
* @param[in] sem_payload Array of Vulkan semaphores that constitute the payload.
|
||||
* @param[in] submission_pnext Chain of pointers to attach to the payload submission.
|
||||
*
|
||||
* @return VK_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
VkResult image_set_present_payload(swapchain_image &image, VkQueue queue, const queue_submit_semaphores &semaphores,
|
||||
const void *submission_pnext) override;
|
||||
|
||||
VkResult image_wait_present(swapchain_image &image, uint64_t timeout) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -166,9 +166,11 @@ VkResult add_device_extensions_required_by_layer(VkPhysicalDevice phys_dev,
|
|||
const char *optional_extensions[] = {
|
||||
VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME,
|
||||
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
|
||||
#if ENABLE_INSTRUMENTATION
|
||||
VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME,
|
||||
#endif
|
||||
};
|
||||
|
||||
for (auto extension : optional_extensions)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue