mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-25 14:00:08 +01:00
Previously, the number of planes was incorrectly calculated. The number of planes for non-linear images was the format planes from wsialloc instead of the memory planes expected by the implementation. Additionally, the VK_IMAGE_CREATE_DISJOINT_BIT was based on the format planes during image creation, instead of using the allocation planes from wsialloc. This commit corrects these issues by ensuring the plane count and disjoint bit is set based on the appropriate memory planes. Signed-off-by: Angeliki Agathi Tsintzira <angelikiagathi.tsintzira@arm.com> Change-Id: I47ca4a0c710cdf21d94705c57f08de4f04b3a761
621 lines
22 KiB
C++
621 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2017-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.
|
|
*/
|
|
|
|
#define VK_USE_PLATFORM_WAYLAND_KHR 1
|
|
|
|
#include "swapchain.hpp"
|
|
#include "wl_helpers.hpp"
|
|
#include "surface_properties.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <unistd.h>
|
|
#include <cstdlib>
|
|
#include <cerrno>
|
|
#include <cstdio>
|
|
#include <climits>
|
|
#include <functional>
|
|
|
|
#include "util/drm/drm_utils.hpp"
|
|
#include "util/log.hpp"
|
|
#include "util/helpers.hpp"
|
|
#include "util/macros.hpp"
|
|
#include "util/format_modifiers.hpp"
|
|
|
|
namespace wsi
|
|
{
|
|
namespace wayland
|
|
{
|
|
|
|
swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator,
|
|
surface &wsi_surface)
|
|
: swapchain_base(dev_data, pAllocator)
|
|
, m_display(wsi_surface.get_wl_display())
|
|
, m_surface(wsi_surface.get_wl_surface())
|
|
, m_wsi_surface(&wsi_surface)
|
|
, m_buffer_queue(nullptr)
|
|
, m_wsi_allocator(nullptr)
|
|
, m_image_creation_parameters({}, m_allocator, {}, {})
|
|
{
|
|
m_image_create_info.format = VK_FORMAT_UNDEFINED;
|
|
}
|
|
|
|
swapchain::~swapchain()
|
|
{
|
|
teardown();
|
|
|
|
if (m_wsi_allocator != nullptr)
|
|
{
|
|
wsialloc_delete(m_wsi_allocator);
|
|
}
|
|
m_wsi_allocator = nullptr;
|
|
if (m_buffer_queue != nullptr)
|
|
{
|
|
wl_event_queue_destroy(m_buffer_queue);
|
|
}
|
|
}
|
|
|
|
VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info,
|
|
bool &use_presentation_thread)
|
|
{
|
|
if ((m_display == nullptr) || (m_surface == nullptr) || (m_wsi_surface->get_dmabuf_interface() == nullptr))
|
|
{
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
m_buffer_queue = wl_display_create_queue(m_display);
|
|
if (m_buffer_queue == nullptr)
|
|
{
|
|
WSI_LOG_ERROR("Failed to create buffer wl queue.");
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
WSIALLOC_ASSERT_VERSION();
|
|
if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
|
|
{
|
|
WSI_LOG_ERROR("Failed to create wsi allocator.");
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
/*
|
|
* When VK_PRESENT_MODE_MAILBOX_KHR has been chosen by the application we don't
|
|
* initialize the page flip thread so the present_image function can be called
|
|
* during vkQueuePresent.
|
|
*/
|
|
use_presentation_thread = (m_present_mode != VK_PRESENT_MODE_MAILBOX_KHR);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VWL_CAPI_CALL(void) buffer_release(void *data, struct wl_buffer *wayl_buffer) VWL_API_POST
|
|
{
|
|
auto sc = reinterpret_cast<swapchain *>(data);
|
|
sc->release_buffer(wayl_buffer);
|
|
}
|
|
|
|
void swapchain::release_buffer(struct wl_buffer *wayl_buffer)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < m_swapchain_images.size(); i++)
|
|
{
|
|
auto data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[i].data);
|
|
if (data && data->buffer == wayl_buffer)
|
|
{
|
|
unpresent_image(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* check we found a buffer to unpresent */
|
|
assert(i < m_swapchain_images.size());
|
|
}
|
|
|
|
static struct wl_buffer_listener buffer_listener = { buffer_release };
|
|
|
|
VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info,
|
|
util::vector<wsialloc_format> &importable_formats,
|
|
util::vector<uint64_t> &exportable_modifers,
|
|
util::vector<VkDrmFormatModifierPropertiesEXT> &drm_format_props)
|
|
{
|
|
TRY_LOG(util::get_drm_format_properties(m_device_data.physical_device, info.format, drm_format_props),
|
|
"Failed to get format properties");
|
|
|
|
for (const auto &prop : drm_format_props)
|
|
{
|
|
bool is_supported = false;
|
|
drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier };
|
|
|
|
for (const auto &format : m_wsi_surface->get_formats())
|
|
{
|
|
if (format.fourcc == drm_format.fourcc && format.modifier == drm_format.modifier)
|
|
{
|
|
is_supported = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!is_supported)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
VkExternalImageFormatPropertiesKHR external_props = {};
|
|
external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR;
|
|
|
|
VkImageFormatProperties2KHR format_props = {};
|
|
format_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
|
|
format_props.pNext = &external_props;
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
{
|
|
VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {};
|
|
external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR;
|
|
external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
|
|
|
|
VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {};
|
|
drm_mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
|
|
drm_mod_info.pNext = &external_info;
|
|
drm_mod_info.drmFormatModifier = prop.drmFormatModifier;
|
|
drm_mod_info.sharingMode = info.sharingMode;
|
|
drm_mod_info.queueFamilyIndexCount = info.queueFamilyIndexCount;
|
|
drm_mod_info.pQueueFamilyIndices = info.pQueueFamilyIndices;
|
|
|
|
VkPhysicalDeviceImageFormatInfo2KHR image_info = {};
|
|
image_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR;
|
|
image_info.pNext = &drm_mod_info;
|
|
image_info.format = info.format;
|
|
image_info.type = info.imageType;
|
|
image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
|
image_info.usage = info.usage;
|
|
image_info.flags = info.flags;
|
|
|
|
#if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN
|
|
VkImageCompressionControlEXT compression_control = {};
|
|
compression_control.sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT;
|
|
compression_control.flags = m_image_compression_control_params.flags;
|
|
compression_control.compressionControlPlaneCount =
|
|
m_image_compression_control_params.compression_control_plane_count;
|
|
compression_control.pFixedRateFlags = m_image_compression_control_params.fixed_rate_flags.data();
|
|
|
|
if (m_device_data.is_swapchain_compression_control_enabled())
|
|
{
|
|
compression_control.pNext = image_info.pNext;
|
|
image_info.pNext = &compression_control;
|
|
}
|
|
#endif
|
|
result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(
|
|
m_device_data.physical_device, &image_info, &format_props);
|
|
}
|
|
if (result != VK_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
if (format_props.imageFormatProperties.maxExtent.width < info.extent.width ||
|
|
format_props.imageFormatProperties.maxExtent.height < info.extent.height ||
|
|
format_props.imageFormatProperties.maxExtent.depth < info.extent.depth)
|
|
{
|
|
continue;
|
|
}
|
|
if (format_props.imageFormatProperties.maxMipLevels < info.mipLevels ||
|
|
format_props.imageFormatProperties.maxArrayLayers < info.arrayLayers)
|
|
{
|
|
continue;
|
|
}
|
|
if ((format_props.imageFormatProperties.sampleCounts & info.samples) != info.samples)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (external_props.externalMemoryProperties.externalMemoryFeatures &
|
|
VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR)
|
|
{
|
|
if (!exportable_modifers.try_push_back(drm_format.modifier))
|
|
{
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (external_props.externalMemoryProperties.externalMemoryFeatures &
|
|
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)
|
|
{
|
|
uint64_t flags =
|
|
(prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
|
|
wsialloc_format import_format{ drm_format.fourcc, drm_format.modifier, flags };
|
|
if (!importable_formats.try_push_back(import_format))
|
|
{
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
|
|
util::vector<wsialloc_format> &importable_formats,
|
|
wsialloc_format *allocated_format, bool avoid_allocation)
|
|
{
|
|
bool is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
|
|
uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
|
|
if (avoid_allocation)
|
|
{
|
|
allocation_flags |= WSIALLOC_ALLOCATE_NO_MEMORY;
|
|
}
|
|
|
|
#if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN
|
|
if (m_image_compression_control_params.flags & VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT)
|
|
{
|
|
allocation_flags |= WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION;
|
|
}
|
|
#endif
|
|
|
|
wsialloc_allocate_info alloc_info = { importable_formats.data(), static_cast<unsigned>(importable_formats.size()),
|
|
image_create_info.extent.width, image_create_info.extent.height,
|
|
allocation_flags };
|
|
|
|
wsialloc_allocate_result alloc_result = { 0 };
|
|
/* Clear buffer_fds and average_row_strides for error purposes */
|
|
for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
|
|
{
|
|
alloc_result.buffer_fds[i] = -1;
|
|
alloc_result.average_row_strides[i] = -1;
|
|
}
|
|
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &alloc_result);
|
|
if (res != WSIALLOC_ERROR_NONE)
|
|
{
|
|
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
|
|
if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
|
|
{
|
|
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
|
}
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
*allocated_format = alloc_result.format;
|
|
auto &external_memory = image_data->external_mem;
|
|
external_memory.set_strides(alloc_result.average_row_strides);
|
|
external_memory.set_buffer_fds(alloc_result.buffer_fds);
|
|
external_memory.set_offsets(alloc_result.offsets);
|
|
|
|
uint32_t num_planes = util::drm::drm_fourcc_format_get_num_planes(alloc_result.format.fourcc);
|
|
|
|
if (!avoid_allocation)
|
|
{
|
|
uint32_t num_memory_planes = 0;
|
|
|
|
for (uint32_t i = 0; i < num_planes; ++i)
|
|
{
|
|
auto it = std::find(std::begin(alloc_result.buffer_fds) + i + 1, std::end(alloc_result.buffer_fds),
|
|
alloc_result.buffer_fds[i]);
|
|
if (it == std::end(alloc_result.buffer_fds))
|
|
{
|
|
num_memory_planes++;
|
|
}
|
|
}
|
|
|
|
assert(alloc_result.is_disjoint == (num_memory_planes > 1));
|
|
external_memory.set_num_memories(num_memory_planes);
|
|
}
|
|
|
|
external_memory.set_format_info(alloc_result.is_disjoint, num_planes);
|
|
external_memory.set_memory_handle_type(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VkResult fill_image_create_info(VkImageCreateInfo &image_create_info,
|
|
util::vector<VkSubresourceLayout> &image_plane_layouts,
|
|
VkImageDrmFormatModifierExplicitCreateInfoEXT &drm_mod_info,
|
|
VkExternalMemoryImageCreateInfoKHR &external_info,
|
|
wayland_image_data &image_data, uint64_t modifier)
|
|
{
|
|
TRY_LOG_CALL(image_data.external_mem.fill_image_plane_layouts(image_plane_layouts));
|
|
|
|
if (image_data.external_mem.is_disjoint())
|
|
{
|
|
image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
|
|
}
|
|
|
|
image_data.external_mem.fill_drm_mod_info(image_create_info.pNext, drm_mod_info, image_plane_layouts, modifier);
|
|
image_data.external_mem.fill_external_info(external_info, &drm_mod_info);
|
|
image_create_info.pNext = &external_info;
|
|
image_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data)
|
|
{
|
|
util::vector<wsialloc_format> importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
|
|
auto &m_allocated_format = m_image_creation_parameters.m_allocated_format;
|
|
if (!importable_formats.try_push_back(m_allocated_format))
|
|
{
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
TRY_LOG_CALL(allocate_wsialloc(m_image_create_info, image_data, importable_formats, &m_allocated_format, false));
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::create_wl_buffer(const VkImageCreateInfo &image_create_info, swapchain_image &image,
|
|
wayland_image_data *image_data)
|
|
{
|
|
/* create a wl_buffer using the dma_buf protocol */
|
|
zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(m_wsi_surface->get_dmabuf_interface());
|
|
uint32_t modifier_hi = m_image_creation_parameters.m_allocated_format.modifier >> 32;
|
|
uint32_t modifier_low = m_image_creation_parameters.m_allocated_format.modifier & 0xFFFFFFFF;
|
|
for (uint32_t plane = 0; plane < image_data->external_mem.get_num_planes(); plane++)
|
|
{
|
|
zwp_linux_buffer_params_v1_add(params, image_data->external_mem.get_buffer_fds()[plane], plane,
|
|
image_data->external_mem.get_offsets()[plane],
|
|
image_data->external_mem.get_strides()[plane], modifier_hi, modifier_low);
|
|
}
|
|
|
|
const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
|
|
assert(image_create_info.extent.width <= INT32_MAX);
|
|
assert(image_create_info.extent.height <= INT32_MAX);
|
|
image_data->buffer = zwp_linux_buffer_params_v1_create_immed(params, image_create_info.extent.width,
|
|
image_create_info.extent.height, fourcc, 0);
|
|
zwp_linux_buffer_params_v1_destroy(params);
|
|
|
|
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(image_data->buffer), m_buffer_queue);
|
|
auto res = wl_buffer_add_listener(image_data->buffer, &buffer_listener, this);
|
|
if (res < 0)
|
|
{
|
|
destroy_image(image);
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::allocate_and_bind_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
|
|
image.status = swapchain_image::FREE;
|
|
|
|
assert(image.data != nullptr);
|
|
auto image_data = static_cast<wayland_image_data *>(image.data);
|
|
TRY_LOG(allocate_image(image_create_info, image_data), "Failed to allocate image");
|
|
image_status_lock.unlock();
|
|
|
|
TRY_LOG(create_wl_buffer(image_create_info, image, image_data), "Failed to create wl_buffer");
|
|
|
|
TRY_LOG(image_data->external_mem.import_memory_and_bind_swapchain_image(image.image),
|
|
"Failed to import memory and bind swapchain image");
|
|
|
|
/* Initialize presentation fence. */
|
|
auto present_fence = sync_fd_fence_sync::create(m_device_data);
|
|
if (!present_fence.has_value())
|
|
{
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
image_data->present_fence = std::move(present_fence.value());
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image)
|
|
{
|
|
/* Create image_data */
|
|
auto image_data = m_allocator.create<wayland_image_data>(1, m_device, m_allocator);
|
|
if (image_data == nullptr)
|
|
{
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
image.data = image_data;
|
|
|
|
if (m_image_create_info.format == VK_FORMAT_UNDEFINED)
|
|
{
|
|
util::vector<wsialloc_format> importable_formats(
|
|
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
|
|
util::vector<uint64_t> exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
|
|
|
|
/* Query supported modifers. */
|
|
util::vector<VkDrmFormatModifierPropertiesEXT> drm_format_props(
|
|
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
|
|
|
|
TRY_LOG_CALL(
|
|
get_surface_compatible_formats(image_create_info, importable_formats, exportable_modifiers, drm_format_props));
|
|
|
|
/* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
|
|
if (importable_formats.empty())
|
|
{
|
|
WSI_LOG_ERROR("Export/Import not supported.");
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
wsialloc_format allocated_format = { 0 };
|
|
TRY_LOG_CALL(allocate_wsialloc(image_create_info, image_data, importable_formats, &allocated_format, true));
|
|
|
|
for (auto &prop : drm_format_props)
|
|
{
|
|
if (prop.drmFormatModifier == allocated_format.modifier)
|
|
{
|
|
image_data->external_mem.set_num_memories(prop.drmFormatModifierPlaneCount);
|
|
}
|
|
}
|
|
|
|
TRY_LOG_CALL(fill_image_create_info(
|
|
image_create_info, m_image_creation_parameters.m_image_layout, m_image_creation_parameters.m_drm_mod_info,
|
|
m_image_creation_parameters.m_external_info, *image_data, allocated_format.modifier));
|
|
|
|
m_image_create_info = image_create_info;
|
|
m_image_creation_parameters.m_allocated_format = allocated_format;
|
|
}
|
|
|
|
return m_device_data.disp.CreateImage(m_device, &m_image_create_info, get_allocation_callbacks(), &image.image);
|
|
}
|
|
|
|
void swapchain::present_image(uint32_t pendingIndex)
|
|
{
|
|
int res;
|
|
wayland_image_data *image_data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[pendingIndex].data);
|
|
|
|
/* if a frame is already pending, wait for a hint to present again */
|
|
if (!m_wsi_surface->wait_next_frame_event())
|
|
{
|
|
set_error_state(VK_ERROR_SURFACE_LOST_KHR);
|
|
}
|
|
|
|
wl_surface_attach(m_surface, image_data->buffer, 0, 0);
|
|
|
|
auto present_sync_fd = image_data->present_fence.export_sync_fd();
|
|
if (!present_sync_fd.has_value())
|
|
{
|
|
WSI_LOG_ERROR("Failed to export present fence.");
|
|
set_error_state(VK_ERROR_SURFACE_LOST_KHR);
|
|
}
|
|
else if (present_sync_fd->is_valid())
|
|
{
|
|
zwp_linux_surface_synchronization_v1_set_acquire_fence(m_wsi_surface->get_surface_sync_interface(),
|
|
present_sync_fd->get());
|
|
}
|
|
|
|
/* TODO: work out damage */
|
|
wl_surface_damage(m_surface, 0, 0, INT32_MAX, INT32_MAX);
|
|
|
|
if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
|
|
{
|
|
if (!m_wsi_surface->set_frame_callback())
|
|
{
|
|
set_error_state(VK_ERROR_SURFACE_LOST_KHR);
|
|
}
|
|
}
|
|
|
|
wl_surface_commit(m_surface);
|
|
res = wl_display_flush(m_display);
|
|
if (res < 0)
|
|
{
|
|
WSI_LOG_ERROR("error flushing the display");
|
|
/* Setting the swapchain as invalid */
|
|
set_error_state(VK_ERROR_SURFACE_LOST_KHR);
|
|
}
|
|
}
|
|
|
|
void swapchain::destroy_image(swapchain_image &image)
|
|
{
|
|
std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
|
|
|
|
if (image.status != swapchain_image::INVALID)
|
|
{
|
|
if (image.image != VK_NULL_HANDLE)
|
|
{
|
|
m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
|
|
image.image = VK_NULL_HANDLE;
|
|
}
|
|
|
|
image.status = swapchain_image::INVALID;
|
|
}
|
|
|
|
image_status_lock.unlock();
|
|
|
|
if (image.data != nullptr)
|
|
{
|
|
auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
|
|
if (image_data->buffer != nullptr)
|
|
{
|
|
wl_buffer_destroy(image_data->buffer);
|
|
}
|
|
m_allocator.destroy(1, image_data);
|
|
image.data = nullptr;
|
|
}
|
|
}
|
|
|
|
bool swapchain::free_image_found()
|
|
{
|
|
for (auto &img : m_swapchain_images)
|
|
{
|
|
if (img.status == swapchain_image::FREE)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
VkResult swapchain::get_free_buffer(uint64_t *timeout)
|
|
{
|
|
int ms_timeout, res;
|
|
|
|
if (*timeout >= INT_MAX * 1000llu * 1000llu)
|
|
{
|
|
ms_timeout = INT_MAX;
|
|
}
|
|
else
|
|
{
|
|
ms_timeout = *timeout / 1000llu / 1000llu;
|
|
}
|
|
|
|
/* The current dispatch_queue implementation will return if any
|
|
* events are returned, even if no events are dispatched to the buffer
|
|
* queue. Therefore dispatch repeatedly until a buffer has been freed.
|
|
*/
|
|
do
|
|
{
|
|
res = dispatch_queue(m_display, m_buffer_queue, ms_timeout);
|
|
} while (!free_image_found() && res > 0);
|
|
|
|
if (res > 0)
|
|
{
|
|
*timeout = 0;
|
|
return VK_SUCCESS;
|
|
}
|
|
else if (res == 0)
|
|
{
|
|
if (*timeout == 0)
|
|
{
|
|
return VK_NOT_READY;
|
|
}
|
|
else
|
|
{
|
|
return VK_TIMEOUT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return VK_ERROR_SURFACE_LOST_KHR;
|
|
}
|
|
}
|
|
|
|
VkResult swapchain::image_set_present_payload(swapchain_image &image, VkQueue queue,
|
|
const queue_submit_semaphores &semaphores)
|
|
{
|
|
auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
|
|
return image_data->present_fence.set_payload(queue, semaphores);
|
|
}
|
|
|
|
VkResult swapchain::image_wait_present(swapchain_image &, uint64_t)
|
|
{
|
|
/* With explicit sync in use there is no need to wait for the present sync before submiting the image to the
|
|
* compositor. */
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult swapchain::bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
|
|
const VkBindImageMemorySwapchainInfoKHR *bind_sc_info)
|
|
{
|
|
const wsi::swapchain_image &swapchain_image = m_swapchain_images[bind_sc_info->imageIndex];
|
|
auto image_data = reinterpret_cast<wayland_image_data *>(swapchain_image.data);
|
|
return image_data->external_mem.bind_swapchain_image_memory(bind_image_mem_info->image);
|
|
}
|
|
|
|
} // namespace wayland
|
|
} // namespace wsi
|