diff --git a/CMakeLists.txt b/CMakeLists.txt index b06897c..8a06103 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,7 @@ if(BUILD_WSI_HEADLESS) list(APPEND LINK_WSI_LIBS wsi_headless) else() list(APPEND JSON_COMMANDS COMMAND sed -i '/VK_EXT_headless_surface/d' ${CMAKE_CURRENT_BINARY_DIR}/VkLayer_window_system_integration.json) + list(APPEND JSON_COMMANDS COMMAND sed -i '/VK_KHR_shared_presentable_image/d' ${CMAKE_CURRENT_BINARY_DIR}/VkLayer_window_system_integration.json) endif() # Layer diff --git a/layer/VkLayer_window_system_integration.json b/layer/VkLayer_window_system_integration.json index f5c922c..edd28c1 100644 --- a/layer/VkLayer_window_system_integration.json +++ b/layer/VkLayer_window_system_integration.json @@ -17,6 +17,7 @@ {"name" : "VK_KHR_get_surface_capabilities2", "spec_version" : "1"} ], "device_extensions": [ + {"name": "VK_KHR_shared_presentable_image", "spec_version": "1", "entrypoints": ["vkGetSwapchainStatusKHR"]}, {"name": "VK_EXT_image_compression_control_swapchain", "spec_version": "1"}, { "name": "VK_KHR_swapchain", diff --git a/layer/layer.cpp b/layer/layer.cpp index 69f39be..b0337e9 100644 --- a/layer/layer.cpp +++ b/layer/layer.cpp @@ -435,6 +435,11 @@ wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName) VWL_API_POS GET_PROC_ADDR(vkGetDeviceGroupPresentCapabilitiesKHR); GET_PROC_ADDR(vkGetDeviceGroupSurfacePresentModesKHR); } + if (layer::device_private_data::get(device).is_device_extension_enabled( + VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME)) + { + GET_PROC_ADDR(vkGetSwapchainStatusKHR); + } GET_PROC_ADDR(vkDestroyDevice); GET_PROC_ADDR(vkCreateImage); diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 5cbcffd..b25ce56 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -369,6 +369,8 @@ private: EP(GetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \ EP(AcquireNextImageKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \ EP(QueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME, API_VERSION_MAX, false) \ + /* VK_KHR_shared_presentable_image */ \ + EP(GetSwapchainStatusKHR, VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME, API_VERSION_MAX, false) \ /* VK_KHR_device_group + VK_KHR_swapchain or */ \ /* 1.1 with VK_KHR_swapchain */ \ EP(AcquireNextImage2KHR, VK_KHR_DEVICE_GROUP_EXTENSION_NAME, VK_API_VERSION_1_1, false) \ diff --git a/layer/swapchain_api.cpp b/layer/swapchain_api.cpp index e091e67..645befc 100644 --- a/layer/swapchain_api.cpp +++ b/layer/swapchain_api.cpp @@ -382,3 +382,18 @@ wsi_layer_vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, } return endpoint_result; } + +VWL_VKAPI_CALL(VkResult) +wsi_layer_vkGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain) VWL_API_POST +{ + auto &device_data = layer::device_private_data::get(device); + + if (!device_data.layer_owns_swapchain(swapchain)) + { + return device_data.disp.GetSwapchainStatusKHR(device, swapchain); + } + + auto *sc = reinterpret_cast(swapchain); + + return sc->get_swapchain_status(); +} diff --git a/layer/swapchain_api.hpp b/layer/swapchain_api.hpp index 36f1467..d882da6 100644 --- a/layer/swapchain_api.hpp +++ b/layer/swapchain_api.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 Arm Limited. + * Copyright (c) 2018-2019, 2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -76,3 +76,6 @@ wsi_layer_vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, c VWL_VKAPI_CALL(VkResult) wsi_layer_vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos) VWL_API_POST; + +VWL_VKAPI_CALL(VkResult) +wsi_layer_vkGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain) VWL_API_POST; diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index 35891af..ff7457a 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 2021-2023 Arm Limited. + * Copyright (c) 2017-2019, 2021-2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -113,7 +113,12 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical UNUSED(physical_device); UNUSED(surface); - static const std::array modes = { VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR }; + static const std::array modes = { + VK_PRESENT_MODE_FIFO_KHR, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, + }; return get_surface_present_modes_common(present_mode_count, present_modes, modes); } diff --git a/wsi/headless/swapchain.cpp b/wsi/headless/swapchain.cpp index d64d48b..59f9231 100644 --- a/wsi/headless/swapchain.cpp +++ b/wsi/headless/swapchain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2022 Arm Limited. + * Copyright (c) 2017-2022, 2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -50,7 +50,9 @@ struct image_data swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator) : wsi::swapchain_base(dev_data, pAllocator) #if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN - , m_image_compression_control{} + , m_image_compression_control +{ +} #endif { } @@ -61,6 +63,21 @@ swapchain::~swapchain() teardown(); } +VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info, + bool &use_presentation_thread) +{ + if (swapchain_create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR) + { + use_presentation_thread = false; + } + else + { + use_presentation_thread = true; + } + + return VK_SUCCESS; +} + VkResult swapchain::create_and_bind_swapchain_image(VkImageCreateInfo image_create, wsi::swapchain_image &image) { VkResult res = VK_SUCCESS; @@ -178,7 +195,6 @@ void swapchain::destroy_image(wsi::swapchain_image &image) m_allocator.destroy(1, data); image.data = nullptr; } - } VkResult swapchain::image_set_present_payload(swapchain_image &image, VkQueue queue, const VkSemaphore *sem_payload, diff --git a/wsi/headless/swapchain.hpp b/wsi/headless/swapchain.hpp index dd7d8e8..3d0573d 100644 --- a/wsi/headless/swapchain.hpp +++ b/wsi/headless/swapchain.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 2021-2022 Arm Limited. + * Copyright (c) 2017-2019, 2021-2022, 2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -57,11 +57,7 @@ protected: * @brief Platform specific init */ VkResult init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info, - bool &use_presentation_thread) override - { - use_presentation_thread = true; - return VK_SUCCESS; - }; + bool &use_presentation_thread) override; /** * @brief Creates and binds a new swapchain image. @@ -109,7 +105,6 @@ protected: const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) override; private: - #if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN VkImageCompressionControlEXT m_image_compression_control; #endif diff --git a/wsi/swapchain_base.cpp b/wsi/swapchain_base.cpp index 0746e36..fd014c3 100644 --- a/wsi/swapchain_base.cpp +++ b/wsi/swapchain_base.cpp @@ -62,24 +62,47 @@ void swapchain_base::page_flip_thread() */ while (m_page_flip_thread_run) { - /* Waiting for the page_flip_semaphore which will be signalled once there is an - * image to display.*/ - if ((vk_res = m_page_flip_semaphore.wait(SEMAPHORE_TIMEOUT)) == VK_TIMEOUT) - { - /* Image is not ready yet. */ - continue; - } - assert(vk_res == VK_SUCCESS); - /* 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. */ - std::unique_lock image_status_lock(m_image_status_mutex); - auto pending_index = m_pending_buffer_pool.pop_front(); - assert(pending_index.has_value()); - image_status_lock.unlock(); + uint32_t image_index; + if (m_present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) + { + /* In continuous mode the application will only make one presentation request, + * therefore the page flip semaphore will only be signalled once. */ + if (!m_first_present) + { + vk_res = VK_SUCCESS; + } + else if ((vk_res = m_page_flip_semaphore.wait(SEMAPHORE_TIMEOUT)) == VK_TIMEOUT) + { + /* Image is not ready yet. */ + continue; + } + assert(vk_res == VK_SUCCESS); + + /* For continuous mode there will be only one image in the swapchain. + * This image will always be used, and there is no pending state in this case. */ + image_index = 0; + } + else + { + /* Waiting for the page_flip_semaphore which will be signalled once there is an + * image to display.*/ + if ((vk_res = m_page_flip_semaphore.wait(SEMAPHORE_TIMEOUT)) == VK_TIMEOUT) + { + /* Image is not ready yet. */ + continue; + } + + /* 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. */ + std::unique_lock image_status_lock(m_image_status_mutex); + auto pending_index = m_pending_buffer_pool.pop_front(); + assert(pending_index.has_value()); + image_index = *pending_index; + } /* We may need to wait for the payload of the present sync of the oldest pending image to be finished. */ - while ((vk_res = image_wait_present(sc_images[*pending_index], timeout)) == VK_TIMEOUT) + while ((vk_res = image_wait_present(sc_images[image_index], timeout)) == VK_TIMEOUT) { WSI_LOG_WARNING("Timeout waiting for image's present fences, retrying.."); } @@ -90,7 +113,7 @@ void swapchain_base::page_flip_thread() continue; } - call_present(*pending_index); + call_present(image_index); } } @@ -157,10 +180,23 @@ void swapchain_base::unpresent_image(uint32_t presented_index) { std::unique_lock image_status_lock(m_image_status_mutex); - m_swapchain_images[presented_index].status = swapchain_image::FREE; + if (m_present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + m_present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) + { + m_swapchain_images[presented_index].status = swapchain_image::ACQUIRED; + } + else + { + m_swapchain_images[presented_index].status = swapchain_image::FREE; + } image_status_lock.unlock(); - m_free_image_semaphore.post(); + + if (m_present_mode != VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR && + m_present_mode != VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) + { + m_free_image_semaphore.post(); + } } swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *callbacks) @@ -519,6 +555,11 @@ VkResult swapchain_base::create_aliased_image_handle(VkImage *image) return m_device_data.disp.CreateImage(m_device, &m_image_create_info, get_allocation_callbacks(), image); } +VkResult swapchain_base::get_swapchain_status() +{ + return get_error_state(); +} + VkResult swapchain_base::notify_presentation_engine(uint32_t image_index) { const std::lock_guard lock(m_image_status_mutex); @@ -563,6 +604,13 @@ VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *pr sem_count = present_info->waitSemaphoreCount; } + if (!m_page_flip_thread_run) + { + /* If the page flip thread is not running, we need to wait for any present payload here, before setting a new present payload. */ + constexpr uint64_t WAIT_PRESENT_TIMEOUT = 1000000000; /* 1 second */ + TRY_LOG_CALL(image_wait_present(m_swapchain_images[image_index], WAIT_PRESENT_TIMEOUT)); + } + TRY_LOG_CALL(image_set_present_payload(m_swapchain_images[image_index], queue, wait_semaphores, sem_count)); TRY(notify_presentation_engine(image_index)); diff --git a/wsi/swapchain_base.hpp b/wsi/swapchain_base.hpp index 5a53298..3371768 100644 --- a/wsi/swapchain_base.hpp +++ b/wsi/swapchain_base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2022 Arm Limited. + * Copyright (c) 2017-2022, 2024 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -207,6 +207,13 @@ public: return m_swapchain_images[image_index].present_semaphore; } + /** + * @brief Get the swapchain status. + * + * @return VK_SUCCESS + */ + VkResult get_swapchain_status(); + protected: layer::device_private_data &m_device_data;