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"
29 #include "surface_properties.hpp"
41 #include "util/drm/drm_utils.hpp"
42 #include "util/log.hpp"
51 const VkImageAspectFlagBits plane_flag_bits[MAX_PLANES] = {
52 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
53 VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
54 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
55 VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
58 struct swapchain::wayland_image_data
60 int buffer_fd[MAX_PLANES];
61 int stride[MAX_PLANES];
62 uint32_t offset[MAX_PLANES];
65 VkDeviceMemory memory[MAX_PLANES];
70 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator,
72 : swapchain_base(dev_data, pAllocator)
73 , m_display(wsi_surface.get_wl_display())
74 , m_surface(wsi_surface.get_wl_surface())
75 , m_dmabuf_interface(wsi_surface.get_dmabuf_interface())
76 , m_swapchain_queue(nullptr)
77 , m_buffer_queue(nullptr)
78 , m_wsi_allocator(nullptr)
79 , m_present_pending(false)
83 swapchain::~swapchain()
87 wsialloc_delete(m_wsi_allocator);
88 m_wsi_allocator = nullptr;
89 if (m_swapchain_queue != nullptr)
91 wl_event_queue_destroy(m_swapchain_queue);
93 if (m_buffer_queue != nullptr)
95 wl_event_queue_destroy(m_buffer_queue);
99 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
101 if ((m_display == nullptr) || (m_surface == nullptr) || (m_dmabuf_interface == nullptr))
103 return VK_ERROR_INITIALIZATION_FAILED;
106 m_swapchain_queue = wl_display_create_queue(m_display);
108 if (m_swapchain_queue == nullptr)
110 WSI_LOG_ERROR("Failed to create swapchain wl queue.");
111 return VK_ERROR_INITIALIZATION_FAILED;
114 m_buffer_queue = wl_display_create_queue(m_display);
115 if (m_buffer_queue == nullptr)
117 WSI_LOG_ERROR("Failed to create buffer wl queue.");
118 return VK_ERROR_INITIALIZATION_FAILED;
121 if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
123 WSI_LOG_ERROR("Failed to create wsi allocator.");
124 return VK_ERROR_INITIALIZATION_FAILED;
130 extern "C" void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
131 struct wl_buffer *buffer)
133 auto wayland_buffer = reinterpret_cast<wl_buffer **>(data);
134 *wayland_buffer = buffer;
137 static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL };
139 extern "C" void buffer_release(void *data, struct wl_buffer *wayl_buffer)
141 auto sc = reinterpret_cast<swapchain *>(data);
142 sc->release_buffer(wayl_buffer);
145 void swapchain::release_buffer(struct wl_buffer *wayl_buffer)
148 for (i = 0; i < m_swapchain_images.size(); i++)
150 auto data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[i].data);
151 if (data->buffer == wayl_buffer)
158 /* check we found a buffer to unpresent */
159 assert(i < m_swapchain_images.size());
162 static struct wl_buffer_listener buffer_listener = { buffer_release };
164 VkResult swapchain::allocate_plane_memory(int fd, VkDeviceMemory *memory)
166 uint32_t mem_index = -1;
167 VkResult result = get_fd_mem_type_index(fd, mem_index);
168 if (result != VK_SUCCESS)
173 const off_t dma_buf_size = lseek(fd, 0, SEEK_END);
174 if (dma_buf_size < 0)
176 WSI_LOG_ERROR("Failed to get DMA Buf size.");
177 return VK_ERROR_OUT_OF_HOST_MEMORY;
180 VkImportMemoryFdInfoKHR import_mem_info = {};
181 import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
182 import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
183 import_mem_info.fd = fd;
185 VkMemoryAllocateInfo alloc_info = {};
186 alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
187 alloc_info.pNext = &import_mem_info;
188 alloc_info.allocationSize = static_cast<uint64_t>(dma_buf_size);
189 alloc_info.memoryTypeIndex = mem_index;
191 result = m_device_data.disp.AllocateMemory(
192 m_device, &alloc_info, get_allocation_callbacks(), memory);
194 if (result != VK_SUCCESS)
196 WSI_LOG_ERROR("Failed to import memory.");
203 VkResult swapchain::get_fd_mem_type_index(int fd, uint32_t &mem_idx)
205 VkMemoryFdPropertiesKHR mem_props = {};
206 mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
208 VkResult result = m_device_data.disp.GetMemoryFdPropertiesKHR(
209 m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, fd, &mem_props);
210 if (result != VK_SUCCESS)
212 WSI_LOG_ERROR("Error querying Fd properties.");
216 for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
218 if (mem_props.memoryTypeBits & (1 << mem_idx))
224 assert(mem_idx < VK_MAX_MEMORY_TYPES);
229 VkResult swapchain::get_drm_format_properties(
230 VkFormat format, util::vector<VkDrmFormatModifierPropertiesEXT> &format_props_list)
232 VkDrmFormatModifierPropertiesListEXT format_modifier_props = {};
233 format_modifier_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
235 VkFormatProperties2KHR format_props = {};
236 format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
237 format_props.pNext = &format_modifier_props;
239 m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
240 m_device_data.physical_device, format, &format_props);
242 if (!format_props_list.try_resize(format_modifier_props.drmFormatModifierCount))
244 return VK_ERROR_OUT_OF_HOST_MEMORY;
247 format_modifier_props.pDrmFormatModifierProperties = format_props_list.data();
248 m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
249 m_device_data.physical_device, format, &format_props);
254 static bool is_disjoint_supported(
255 const util::vector<VkDrmFormatModifierPropertiesEXT> &format_props, uint64_t modifier)
257 for (const auto &prop : format_props)
259 if (prop.drmFormatModifier == modifier &&
260 prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT)
269 static uint32_t get_same_fd_index(int fd, int const *fds)
272 while (fd != fds[index])
280 VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
283 VkResult result = VK_SUCCESS;
284 const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
286 image_data->buffer = nullptr;
287 image_data->num_planes = 0;
288 for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
290 image_data->buffer_fd[plane] = -1;
291 image_data->memory[plane] = VK_NULL_HANDLE;
294 /* Query support for disjoint images. */
295 util::vector<VkDrmFormatModifierPropertiesEXT> drm_format_props(m_allocator);
296 result = get_drm_format_properties(image_create_info.format, drm_format_props);
297 if (result != VK_SUCCESS)
299 WSI_LOG_ERROR("Failed to get format properties.");
302 auto is_disjoint = is_disjoint_supported(drm_format_props, modifier);
304 VkExternalImageFormatPropertiesKHR external_props = {};
305 external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR;
307 VkImageFormatProperties2KHR format_props = {};
308 format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
309 format_props.pNext = &external_props;
311 VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {};
312 external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR;
313 external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
315 VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {};
316 drm_mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
317 drm_mod_info.pNext = &external_info;
318 drm_mod_info.drmFormatModifier = modifier;
319 drm_mod_info.sharingMode = image_create_info.sharingMode;
320 drm_mod_info.queueFamilyIndexCount = image_create_info.queueFamilyIndexCount;
321 drm_mod_info.pQueueFamilyIndices = image_create_info.pQueueFamilyIndices;
323 VkPhysicalDeviceImageFormatInfo2KHR info = {};
324 info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR;
325 info.pNext = &drm_mod_info;
326 info.format = image_create_info.format;
327 info.type = image_create_info.imageType;
328 info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
329 info.usage = image_create_info.usage;
330 info.flags = image_create_info.flags;
332 result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_device_data.physical_device,
333 &info, &format_props);
335 if (result != VK_SUCCESS)
337 WSI_LOG_ERROR("Failed to get physical device format support.");
340 if (format_props.imageFormatProperties.maxExtent.width < image_create_info.extent.width ||
341 format_props.imageFormatProperties.maxExtent.height < image_create_info.extent.height ||
342 format_props.imageFormatProperties.maxExtent.depth < image_create_info.extent.depth)
344 WSI_LOG_ERROR("Physical device does not support required extent.");
345 return VK_ERROR_INITIALIZATION_FAILED;
347 if (format_props.imageFormatProperties.maxMipLevels < image_create_info.mipLevels ||
348 format_props.imageFormatProperties.maxArrayLayers < image_create_info.arrayLayers)
350 WSI_LOG_ERROR("Physical device does not support required array layers or mip levels.");
351 return VK_ERROR_INITIALIZATION_FAILED;
353 if ((format_props.imageFormatProperties.sampleCounts & image_create_info.samples) != image_create_info.samples)
355 WSI_LOG_ERROR("Physical device does not support required sample count.");
356 return VK_ERROR_INITIALIZATION_FAILED;
359 if (external_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR)
361 /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
363 if (!(external_props.externalMemoryProperties.externalMemoryFeatures &
364 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))
366 WSI_LOG_ERROR("Export/Import not supported.");
367 return VK_ERROR_INITIALIZATION_FAILED;
371 /* TODO: Handle Dedicated allocation bit. */
372 const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
373 const auto is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
375 const uint64_t format_flags = is_disjoint ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
376 wsialloc_format format = {fourcc, modifier, format_flags};
378 const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
379 wsialloc_allocate_info alloc_info = {
382 image_create_info.extent.width,
383 image_create_info.extent.height,
387 wsialloc_format allocated_format = {0};
388 const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &allocated_format, image_data->stride,
389 image_data->buffer_fd, image_data->offset);
390 if (res != WSIALLOC_ERROR_NONE)
392 WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
393 if(res == WSIALLOC_ERROR_NOT_SUPPORTED)
395 return VK_ERROR_FORMAT_NOT_SUPPORTED;
397 return VK_ERROR_OUT_OF_HOST_MEMORY;
400 for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
402 if (image_data->buffer_fd[plane] == -1)
406 image_data->num_planes++;
410 util::vector<VkSubresourceLayout> image_layout(m_allocator);
411 if (!image_layout.try_resize(image_data->num_planes))
413 return VK_ERROR_OUT_OF_HOST_MEMORY;
416 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
418 assert(image_data->stride[plane] >= 0);
419 image_layout[plane].offset = image_data->offset[plane];
420 image_layout[plane].rowPitch = static_cast<uint32_t>(image_data->stride[plane]);
425 image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
428 VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {};
429 drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
430 drm_mod_info.pNext = image_create_info.pNext;
431 drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
432 drm_mod_info.drmFormatModifierPlaneCount = image_data->num_planes;
433 drm_mod_info.pPlaneLayouts = image_layout.data();
435 VkExternalMemoryImageCreateInfoKHR external_info = {};
436 external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
437 external_info.pNext = &drm_mod_info;
438 external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
440 VkImageCreateInfo image_info = image_create_info;
441 image_info.pNext = &external_info;
442 image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
443 result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image);
445 if (result != VK_SUCCESS)
447 WSI_LOG_ERROR("Image creation failed.");
453 util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(m_allocator);
454 if (!bind_img_mem_infos.try_resize(image_data->num_planes))
456 return VK_ERROR_OUT_OF_HOST_MEMORY;
459 util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(m_allocator);
460 if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
462 return VK_ERROR_OUT_OF_HOST_MEMORY;
465 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
467 const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
468 if (fd_index == plane)
470 result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
471 if (result != VK_SUCCESS)
477 bind_plane_mem_infos[plane].planeAspect = plane_flag_bits[plane];
478 bind_plane_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
479 bind_plane_mem_infos[plane].pNext = NULL;
481 bind_img_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
482 bind_img_mem_infos[plane].pNext = &bind_plane_mem_infos[plane];
483 bind_img_mem_infos[plane].image = *image;
484 bind_img_mem_infos[plane].memory = image_data->memory[fd_index];
487 result = m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(),
488 bind_img_mem_infos.data());
492 /* Make sure one fd has been allocated. */
493 for (uint32_t plane = 1; plane < image_data->num_planes; plane++)
495 if (image_data->buffer_fd[plane] != image_data->buffer_fd[0])
497 WSI_LOG_ERROR("Different fds per plane for a non disjoint image.");
498 return VK_ERROR_INITIALIZATION_FAILED;
502 result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
503 if (result != VK_SUCCESS)
508 result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0);
516 VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image)
518 /* Create image_data */
519 auto image_data = m_allocator.create<wayland_image_data>(1);
520 if (image_data == nullptr)
522 return VK_ERROR_OUT_OF_HOST_MEMORY;
525 std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
527 image.data = image_data;
528 image.status = swapchain_image::FREE;
529 VkResult result = allocate_image(image_create_info, image_data, &image.image);
531 image_status_lock.unlock();
533 if (result != VK_SUCCESS)
535 WSI_LOG_ERROR("Failed to allocate image.");
536 destroy_image(image);
540 /* create a wl_buffer using the dma_buf protocol */
541 auto dmabuf_interface_proxy = make_proxy_with_queue(m_dmabuf_interface, m_swapchain_queue);
542 if (dmabuf_interface_proxy == nullptr)
544 WSI_LOG_ERROR("Failed to allocate dma-buf interface proxy.");
545 destroy_image(image);
546 return VK_ERROR_INITIALIZATION_FAILED;
549 zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get());
551 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
553 zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd[plane], plane,
554 image_data->offset[plane], image_data->stride[plane], 0, 0);
557 auto res = zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &image_data->buffer);
560 destroy_image(image);
561 return VK_ERROR_INITIALIZATION_FAILED;
563 const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format);
564 zwp_linux_buffer_params_v1_create(params, image_create_info.extent.width,
565 image_create_info.extent.height, fourcc, 0);
567 /* TODO: don't roundtrip - we should be able to send the create request now,
568 * and only wait for it on first present. only do this once, not for all buffers created */
569 res = wl_display_roundtrip_queue(m_display, m_swapchain_queue);
572 destroy_image(image);
573 return VK_ERROR_INITIALIZATION_FAILED;
576 /* should now have a wl_buffer */
577 assert(image_data->buffer);
578 zwp_linux_buffer_params_v1_destroy(params);
579 wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(image_data->buffer), m_buffer_queue);
580 res = wl_buffer_add_listener(image_data->buffer, &buffer_listener, this);
583 destroy_image(image);
584 return VK_ERROR_INITIALIZATION_FAILED;
587 /* Initialize presentation fence. */
588 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 };
589 result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence);
590 if (result != VK_SUCCESS)
592 destroy_image(image);
599 static void frame_done(void *data, wl_callback *cb, uint32_t cb_data)
603 bool *present_pending = reinterpret_cast<bool *>(data);
604 assert(present_pending);
606 *present_pending = false;
608 wl_callback_destroy(cb);
611 void swapchain::present_image(uint32_t pendingIndex)
614 wayland_image_data *image_data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[pendingIndex].data);
615 /* if a frame is already pending, wait for a hint to present again */
616 if (m_present_pending)
618 assert(m_present_mode == VK_PRESENT_MODE_FIFO_KHR);
621 /* block waiting for the compositor to return the wl_surface::frame
622 * callback. We may want to change this to timeout after a period of
623 * time if the compositor isn't responding (perhaps because the
626 res = dispatch_queue(m_display, m_swapchain_queue, -1);
627 } while (res > 0 && m_present_pending);
631 WSI_LOG_ERROR("error waiting for Wayland compositor frame hint");
633 /* try to present anyway */
637 wl_surface_attach(m_surface, image_data->buffer, 0, 0);
638 /* TODO: work out damage */
639 wl_surface_damage(m_surface, 0, 0, INT32_MAX, INT32_MAX);
641 if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
643 /* request a hint when we can present the _next_ frame */
644 auto surface_proxy = make_proxy_with_queue(m_surface, m_swapchain_queue);
645 if (surface_proxy == nullptr)
647 WSI_LOG_ERROR("failed to create wl_surface proxy");
652 wl_callback *cb = wl_surface_frame(surface_proxy.get());
655 static const wl_callback_listener frame_listener = { frame_done };
656 m_present_pending = true;
657 wl_callback_add_listener(cb, &frame_listener, &m_present_pending);
661 wl_surface_commit(m_surface);
662 res = wl_display_flush(m_display);
665 WSI_LOG_ERROR("error flushing the display");
666 /* Setting the swapchain as invalid */
671 void swapchain::destroy_image(swapchain_image &image)
673 std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
675 if (image.status != swapchain_image::INVALID)
677 if (image.present_fence != VK_NULL_HANDLE)
679 m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
680 image.present_fence = VK_NULL_HANDLE;
683 if (image.image != VK_NULL_HANDLE)
685 m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
686 image.image = VK_NULL_HANDLE;
689 image.status = swapchain_image::INVALID;
692 image_status_lock.unlock();
694 if (image.data != nullptr)
696 auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
697 if (image_data->buffer != nullptr)
699 wl_buffer_destroy(image_data->buffer);
702 for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
704 if (image_data->memory[plane] != VK_NULL_HANDLE)
706 m_device_data.disp.FreeMemory(m_device, image_data->memory[plane], get_allocation_callbacks());
708 else if (image_data->buffer_fd[plane] >= 0)
710 const auto same_fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
711 if (same_fd_index == plane)
713 close(image_data->buffer_fd[plane]);
718 m_allocator.destroy(1, image_data);
719 image.data = nullptr;
723 bool swapchain::free_image_found()
725 for (auto &img : m_swapchain_images)
727 if (img.status == swapchain_image::FREE)
735 VkResult swapchain::get_free_buffer(uint64_t *timeout)
739 if (*timeout >= INT_MAX * 1000llu * 1000llu)
741 ms_timeout = INT_MAX;
745 ms_timeout = *timeout / 1000llu / 1000llu;
748 /* The current dispatch_queue implementation will return if any
749 * events are returned, even if no events are dispatched to the buffer
750 * queue. Therefore dispatch repeatedly until a buffer has been freed.
754 res = dispatch_queue(m_display, m_buffer_queue, ms_timeout);
755 } while (!free_image_found() && res > 0);
775 return VK_ERROR_DEVICE_LOST;
779 } // namespace wayland