2 * Copyright (c) 2017-2019, 2021 Arm Limited.
4 * SPDX-License-Identifier: MIT
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #define VK_USE_PLATFORM_WAYLAND_KHR 1
27 #include "swapchain.hpp"
28 #include "wl_helpers.hpp"
40 #include "util/drm/drm_utils.hpp"
41 #include "util/log.hpp"
51 static std::unique_ptr<T, std::function<void(T *)>>
52 make_proxy_with_queue(T *object, wl_event_queue *queue)
54 auto proxy = reinterpret_cast<T *>(wl_proxy_create_wrapper(object));
57 wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(proxy), queue);
60 auto delete_proxy = [](T *proxy)
62 wl_proxy_wrapper_destroy(reinterpret_cast<wl_proxy *>(proxy));
65 return std::unique_ptr<T, std::function<void(T *)>>(proxy, delete_proxy);
68 const VkImageAspectFlagBits plane_flag_bits[MAX_PLANES] = {
69 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
70 VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
71 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
72 VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
75 struct swapchain::wayland_image_data
77 int buffer_fd[MAX_PLANES];
78 int stride[MAX_PLANES];
79 uint32_t offset[MAX_PLANES];
82 VkDeviceMemory memory[MAX_PLANES];
87 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
88 : swapchain_base(dev_data, pAllocator)
91 , m_dmabuf_interface(nullptr)
92 , m_surface_queue(nullptr)
93 , m_buffer_queue(nullptr)
94 , m_wsi_allocator(nullptr)
95 , m_present_pending(false)
99 swapchain::~swapchain()
103 wsialloc_delete(m_wsi_allocator);
104 m_wsi_allocator = nullptr;
105 if (m_surface_queue != nullptr)
107 wl_event_queue_destroy(m_surface_queue);
109 if (m_buffer_queue != nullptr)
111 wl_event_queue_destroy(m_buffer_queue);
118 wl_event_queue *queue;
121 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
123 VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(pSwapchainCreateInfo->surface);
125 m_display = vk_surf->display;
126 m_surface = vk_surf->surface;
128 m_surface_queue = wl_display_create_queue(m_display);
130 if (m_surface_queue == nullptr)
132 WSI_LOG_ERROR("Failed to create wl surface display_queue.");
133 return VK_ERROR_INITIALIZATION_FAILED;
136 m_buffer_queue = wl_display_create_queue(m_display);
137 if (m_buffer_queue == nullptr)
139 WSI_LOG_ERROR("Failed to create wl buffer display_queue.");
140 return VK_ERROR_INITIALIZATION_FAILED;
143 auto display_proxy = make_proxy_with_queue(m_display, m_surface_queue);
144 if (display_proxy == nullptr)
146 WSI_LOG_ERROR("Failed to create wl display proxy.");
147 return VK_ERROR_INITIALIZATION_FAILED;
150 auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) };
151 if (registry == nullptr)
153 WSI_LOG_ERROR("Failed to get wl display registry.");
154 return VK_ERROR_INITIALIZATION_FAILED;
157 const wl_registry_listener registry_listener = { registry_handler };
158 int res = wl_registry_add_listener(registry.get(), ®istry_listener, &m_dmabuf_interface);
161 WSI_LOG_ERROR("Failed to add registry listener.");
162 return VK_ERROR_INITIALIZATION_FAILED;
165 res = wl_display_roundtrip_queue(m_display, m_surface_queue);
168 WSI_LOG_ERROR("Roundtrip failed.");
169 return VK_ERROR_INITIALIZATION_FAILED;
172 if (m_dmabuf_interface.get() == nullptr)
174 return VK_ERROR_INITIALIZATION_FAILED;
177 if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
179 WSI_LOG_ERROR("Failed to create wsi allocator.");
180 return VK_ERROR_INITIALIZATION_FAILED;
186 extern "C" void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
187 struct wl_buffer *buffer)
189 auto wayland_buffer = reinterpret_cast<wl_buffer **>(data);
190 *wayland_buffer = buffer;
193 static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL };
195 extern "C" void buffer_release(void *data, struct wl_buffer *wayl_buffer)
197 auto sc = reinterpret_cast<swapchain *>(data);
198 sc->release_buffer(wayl_buffer);
201 void swapchain::release_buffer(struct wl_buffer *wayl_buffer)
204 for (i = 0; i < m_swapchain_images.size(); i++)
206 auto data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[i].data);
207 if (data->buffer == wayl_buffer)
214 /* check we found a buffer to unpresent */
215 assert(i < m_swapchain_images.size());
218 static struct wl_buffer_listener buffer_listener = { buffer_release };
220 VkResult swapchain::allocate_plane_memory(int fd, VkDeviceMemory *memory)
222 uint32_t mem_index = -1;
223 VkResult result = get_fd_mem_type_index(fd, mem_index);
224 if (result != VK_SUCCESS)
229 const off_t dma_buf_size = lseek(fd, 0, SEEK_END);
230 if (dma_buf_size < 0)
232 WSI_LOG_ERROR("Failed to get DMA Buf size.");
233 return VK_ERROR_OUT_OF_HOST_MEMORY;
236 VkImportMemoryFdInfoKHR import_mem_info = {};
237 import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
238 import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
239 import_mem_info.fd = fd;
241 VkMemoryAllocateInfo alloc_info = {};
242 alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
243 alloc_info.pNext = &import_mem_info;
244 alloc_info.allocationSize = static_cast<uint64_t>(dma_buf_size);
245 alloc_info.memoryTypeIndex = mem_index;
247 result = m_device_data.disp.AllocateMemory(
248 m_device, &alloc_info, get_allocation_callbacks(), memory);
250 if (result != VK_SUCCESS)
252 WSI_LOG_ERROR("Failed to import memory.");
259 VkResult swapchain::get_fd_mem_type_index(int fd, uint32_t &mem_idx)
261 VkMemoryFdPropertiesKHR mem_props = {};
262 mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
264 VkResult result = m_device_data.disp.GetMemoryFdPropertiesKHR(
265 m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, fd, &mem_props);
266 if (result != VK_SUCCESS)
268 WSI_LOG_ERROR("Error querying Fd properties.");
272 for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
274 if (mem_props.memoryTypeBits & (1 << mem_idx))
280 assert(mem_idx < VK_MAX_MEMORY_TYPES);
285 VkResult swapchain::get_drm_format_properties(
286 VkFormat format, util::vector<VkDrmFormatModifierPropertiesEXT> &format_props_list)
288 VkDrmFormatModifierPropertiesListEXT format_modifier_props = {};
289 format_modifier_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
291 VkFormatProperties2KHR format_props = {};
292 format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
293 format_props.pNext = &format_modifier_props;
295 m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
296 m_device_data.physical_device, format, &format_props);
298 if (!format_props_list.try_resize(format_modifier_props.drmFormatModifierCount))
300 return VK_ERROR_OUT_OF_HOST_MEMORY;
303 format_modifier_props.pDrmFormatModifierProperties = format_props_list.data();
304 m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
305 m_device_data.physical_device, format, &format_props);
310 static bool is_disjoint_supported(
311 const util::vector<VkDrmFormatModifierPropertiesEXT> &format_props, uint64_t modifier)
313 for (const auto &prop : format_props)
315 if (prop.drmFormatModifier == modifier &&
316 prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT)
325 static uint32_t get_same_fd_index(int fd, int const *fds)
328 while (fd != fds[index])
336 VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
339 VkResult result = VK_SUCCESS;
340 const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
342 image_data->buffer = nullptr;
343 image_data->num_planes = 0;
344 for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
346 image_data->buffer_fd[plane] = -1;
347 image_data->memory[plane] = VK_NULL_HANDLE;
350 /* Query support for disjoint images. */
351 util::vector<VkDrmFormatModifierPropertiesEXT> drm_format_props(m_allocator);
352 result = get_drm_format_properties(image_create_info.format, drm_format_props);
353 if (result != VK_SUCCESS)
355 WSI_LOG_ERROR("Failed to get format properties.");
358 auto is_disjoint = is_disjoint_supported(drm_format_props, modifier);
360 VkExternalImageFormatPropertiesKHR external_props = {};
361 external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR;
363 VkImageFormatProperties2KHR format_props = {};
364 format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
365 format_props.pNext = &external_props;
367 VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {};
368 external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR;
369 external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
371 VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {};
372 drm_mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
373 drm_mod_info.pNext = &external_info;
374 drm_mod_info.drmFormatModifier = modifier;
375 drm_mod_info.sharingMode = image_create_info.sharingMode;
376 drm_mod_info.queueFamilyIndexCount = image_create_info.queueFamilyIndexCount;
377 drm_mod_info.pQueueFamilyIndices = image_create_info.pQueueFamilyIndices;
379 VkPhysicalDeviceImageFormatInfo2KHR info = {};
380 info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR;
381 info.pNext = &drm_mod_info;
382 info.format = image_create_info.format;
383 info.type = image_create_info.imageType;
384 info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
385 info.usage = image_create_info.usage;
386 info.flags = image_create_info.flags;
388 result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_device_data.physical_device,
389 &info, &format_props);
391 if (result != VK_SUCCESS)
393 WSI_LOG_ERROR("Failed to get physical device format support.");
396 if (format_props.imageFormatProperties.maxExtent.width < image_create_info.extent.width ||
397 format_props.imageFormatProperties.maxExtent.height < image_create_info.extent.height ||
398 format_props.imageFormatProperties.maxExtent.depth < image_create_info.extent.depth)
400 WSI_LOG_ERROR("Physical device does not support required extent.");
401 return VK_ERROR_INITIALIZATION_FAILED;
403 if (format_props.imageFormatProperties.maxMipLevels < image_create_info.mipLevels ||
404 format_props.imageFormatProperties.maxArrayLayers < image_create_info.arrayLayers)
406 WSI_LOG_ERROR("Physical device does not support required array layers or mip levels.");
407 return VK_ERROR_INITIALIZATION_FAILED;
409 if ((format_props.imageFormatProperties.sampleCounts & image_create_info.samples) != image_create_info.samples)
411 WSI_LOG_ERROR("Physical device does not support required sample count.");
412 return VK_ERROR_INITIALIZATION_FAILED;
415 if (external_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR)
417 /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
419 if (!(external_props.externalMemoryProperties.externalMemoryFeatures &
420 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))
422 WSI_LOG_ERROR("Export/Import not supported.");
423 return VK_ERROR_INITIALIZATION_FAILED;
427 /* TODO: Handle Dedicated allocation bit. */
428 const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
429 const auto is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
431 const uint64_t format_flags = is_disjoint ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
432 wsialloc_format format = {fourcc, modifier, format_flags};
434 const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
435 wsialloc_allocate_info alloc_info = {
438 image_create_info.extent.width,
439 image_create_info.extent.height,
443 wsialloc_format allocated_format = {0};
444 const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &allocated_format, image_data->stride,
445 image_data->buffer_fd, image_data->offset);
446 if (res != WSIALLOC_ERROR_NONE)
448 WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
449 if(res == WSIALLOC_ERROR_NOT_SUPPORTED)
451 return VK_ERROR_FORMAT_NOT_SUPPORTED;
453 return VK_ERROR_OUT_OF_HOST_MEMORY;
456 for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
458 if (image_data->buffer_fd[plane] == -1)
462 image_data->num_planes++;
466 util::vector<VkSubresourceLayout> image_layout(m_allocator);
467 if (!image_layout.try_resize(image_data->num_planes))
469 return VK_ERROR_OUT_OF_HOST_MEMORY;
472 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
474 assert(image_data->stride[plane] >= 0);
475 image_layout[plane].offset = image_data->offset[plane];
476 image_layout[plane].rowPitch = static_cast<uint32_t>(image_data->stride[plane]);
481 image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
484 VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {};
485 drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
486 drm_mod_info.pNext = image_create_info.pNext;
487 drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
488 drm_mod_info.drmFormatModifierPlaneCount = image_data->num_planes;
489 drm_mod_info.pPlaneLayouts = image_layout.data();
491 VkExternalMemoryImageCreateInfoKHR external_info = {};
492 external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
493 external_info.pNext = &drm_mod_info;
494 external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
496 VkImageCreateInfo image_info = image_create_info;
497 image_info.pNext = &external_info;
498 image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
499 result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image);
501 if (result != VK_SUCCESS)
503 WSI_LOG_ERROR("Image creation failed.");
509 util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(m_allocator);
510 if (!bind_img_mem_infos.try_resize(image_data->num_planes))
512 return VK_ERROR_OUT_OF_HOST_MEMORY;
515 util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(m_allocator);
516 if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
518 return VK_ERROR_OUT_OF_HOST_MEMORY;
521 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
523 const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
524 if (fd_index == plane)
526 result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
527 if (result != VK_SUCCESS)
533 bind_plane_mem_infos[plane].planeAspect = plane_flag_bits[plane];
534 bind_plane_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
535 bind_plane_mem_infos[plane].pNext = NULL;
537 bind_img_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
538 bind_img_mem_infos[plane].pNext = &bind_plane_mem_infos[plane];
539 bind_img_mem_infos[plane].image = *image;
540 bind_img_mem_infos[plane].memory = image_data->memory[fd_index];
543 result = m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(),
544 bind_img_mem_infos.data());
548 /* Make sure one fd has been allocated. */
549 for (uint32_t plane = 1; plane < image_data->num_planes; plane++)
551 if (image_data->buffer_fd[plane] != image_data->buffer_fd[0])
553 WSI_LOG_ERROR("Different fds per plane for a non disjoint image.");
554 return VK_ERROR_INITIALIZATION_FAILED;
558 result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
559 if (result != VK_SUCCESS)
564 result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0);
572 VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image)
574 /* Create image_data */
575 auto image_data = m_allocator.create<wayland_image_data>(1);
576 if (image_data == nullptr)
578 return VK_ERROR_OUT_OF_HOST_MEMORY;
581 std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
583 image.data = image_data;
584 image.status = swapchain_image::FREE;
585 VkResult result = allocate_image(image_create_info, image_data, &image.image);
587 image_status_lock.unlock();
589 if (result != VK_SUCCESS)
591 WSI_LOG_ERROR("Failed to allocate image.");
592 destroy_image(image);
596 /* create a wl_buffer using the dma_buf protocol */
597 auto dmabuf_interface_proxy = make_proxy_with_queue(m_dmabuf_interface.get(), m_surface_queue);
598 if (dmabuf_interface_proxy == nullptr)
600 WSI_LOG_ERROR("Failed to allocate dma-buf interface proxy.");
601 destroy_image(image);
602 return VK_ERROR_INITIALIZATION_FAILED;
605 zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get());
607 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
609 zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd[plane], plane,
610 image_data->offset[plane], image_data->stride[plane], 0, 0);
613 auto res = zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &image_data->buffer);
616 destroy_image(image);
617 return VK_ERROR_INITIALIZATION_FAILED;
619 const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
620 zwp_linux_buffer_params_v1_create(params, image_create_info.extent.width,
621 image_create_info.extent.height, fourcc, 0);
623 /* TODO: don't roundtrip - we should be able to send the create request now,
624 * and only wait for it on first present. only do this once, not for all buffers created */
625 res = wl_display_roundtrip_queue(m_display, m_surface_queue);
628 destroy_image(image);
629 return VK_ERROR_INITIALIZATION_FAILED;
632 /* should now have a wl_buffer */
633 assert(image_data->buffer);
634 zwp_linux_buffer_params_v1_destroy(params);
635 wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(image_data->buffer), m_buffer_queue);
636 res = wl_buffer_add_listener(image_data->buffer, &buffer_listener, this);
639 destroy_image(image);
640 return VK_ERROR_INITIALIZATION_FAILED;
643 /* Initialize presentation fence. */
644 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 };
645 result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence);
646 if (result != VK_SUCCESS)
648 destroy_image(image);
655 static void frame_done(void *data, wl_callback *cb, uint32_t cb_data)
659 bool *present_pending = reinterpret_cast<bool *>(data);
660 assert(present_pending);
662 *present_pending = false;
664 wl_callback_destroy(cb);
667 void swapchain::present_image(uint32_t pendingIndex)
670 wayland_image_data *image_data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[pendingIndex].data);
671 /* if a frame is already pending, wait for a hint to present again */
672 if (m_present_pending)
674 assert(m_present_mode == VK_PRESENT_MODE_FIFO_KHR);
677 /* block waiting for the compositor to return the wl_surface::frame
678 * callback. We may want to change this to timeout after a period of
679 * time if the compositor isn't responding (perhaps because the
682 res = dispatch_queue(m_display, m_surface_queue, -1);
683 } while (res > 0 && m_present_pending);
687 WSI_LOG_ERROR("error waiting for Wayland compositor frame hint");
689 /* try to present anyway */
693 wl_surface_attach(m_surface, image_data->buffer, 0, 0);
694 /* TODO: work out damage */
695 wl_surface_damage(m_surface, 0, 0, INT32_MAX, INT32_MAX);
697 if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
699 /* request a hint when we can present the _next_ frame */
700 auto surface_proxy = make_proxy_with_queue(m_surface, m_surface_queue);
701 if (surface_proxy == nullptr)
703 WSI_LOG_ERROR("failed to create wl_surface proxy");
708 wl_callback *cb = wl_surface_frame(surface_proxy.get());
711 static const wl_callback_listener frame_listener = { frame_done };
712 m_present_pending = true;
713 wl_callback_add_listener(cb, &frame_listener, &m_present_pending);
717 wl_surface_commit(m_surface);
718 res = wl_display_flush(m_display);
721 WSI_LOG_ERROR("error flushing the display");
722 /* Setting the swapchain as invalid */
727 void swapchain::destroy_image(swapchain_image &image)
729 std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
731 if (image.status != swapchain_image::INVALID)
733 if (image.present_fence != VK_NULL_HANDLE)
735 m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
736 image.present_fence = VK_NULL_HANDLE;
739 if (image.image != VK_NULL_HANDLE)
741 m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
742 image.image = VK_NULL_HANDLE;
745 image.status = swapchain_image::INVALID;
748 image_status_lock.unlock();
750 if (image.data != nullptr)
752 auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
753 if (image_data->buffer != nullptr)
755 wl_buffer_destroy(image_data->buffer);
758 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
760 if (image_data->memory[plane] != VK_NULL_HANDLE)
762 m_device_data.disp.FreeMemory(m_device, image_data->memory[plane], get_allocation_callbacks());
764 else if (image_data->buffer_fd[plane] >= 0)
766 const auto same_fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
767 if (same_fd_index == plane)
769 close(image_data->buffer_fd[plane]);
774 m_allocator.destroy(1, image_data);
775 image.data = nullptr;
779 bool swapchain::free_image_found()
781 for (auto &img : m_swapchain_images)
783 if (img.status == swapchain_image::FREE)
791 VkResult swapchain::get_free_buffer(uint64_t *timeout)
795 if (*timeout >= INT_MAX * 1000llu * 1000llu)
797 ms_timeout = INT_MAX;
801 ms_timeout = *timeout / 1000llu / 1000llu;
804 /* The current dispatch_queue implementation will return if any
805 * events are returned, even if no events are dispatched to the buffer
806 * queue. Therefore dispatch repeatedly until a buffer has been freed.
810 res = dispatch_queue(m_display, m_buffer_queue, ms_timeout);
811 } while (!free_image_found() && res > 0);
831 return VK_ERROR_DEVICE_LOST;
835 } // namespace wayland