Implement support for marking frame boundaries

This commit is contained in:
Normunds Rieksts 2024-10-01 15:18:22 +00:00 committed by Iason Paraskevopoulos
parent 2449525741
commit 94dd9840c9
20 changed files with 401 additions and 38 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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.
*

View file

@ -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)
{

View file

@ -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:

View file

@ -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)

View file

@ -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
View 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
View 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);
}

View file

@ -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)

View file

@ -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;

View file

@ -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)
{

View file

@ -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 */

View file

@ -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,

View file

@ -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 */

View file

@ -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)

View file

@ -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;

View file

@ -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)