Fix potential hang on swapchain inheritance
[platform/core/uifw/vulkan-wsi-tizen.git] / wsi / wayland / swapchain.cpp
1 /*
2  * Copyright (c) 2017-2019, 2021 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
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
22  * SOFTWARE.
23  */
24
25 #define VK_USE_PLATFORM_WAYLAND_KHR 1
26
27 #include "swapchain.hpp"
28 #include "wl_helpers.hpp"
29
30 #include <stdint.h>
31 #include <cstring>
32 #include <cassert>
33 #include <unistd.h>
34 #include <cstdlib>
35 #include <cerrno>
36 #include <cstdio>
37 #include <climits>
38 #include <functional>
39
40 #include "util/drm/drm_utils.hpp"
41 #include "util/log.hpp"
42
43 #define MAX_PLANES 4
44
45 namespace wsi
46 {
47 namespace wayland
48 {
49
50 template <typename T>
51 static std::unique_ptr<T, std::function<void(T *)>>
52 make_proxy_with_queue(T *object, wl_event_queue *queue)
53 {
54    auto proxy = reinterpret_cast<T *>(wl_proxy_create_wrapper(object));
55    if (proxy != nullptr)
56    {
57       wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(proxy), queue);
58    }
59
60    auto delete_proxy = [](T *proxy)
61    {
62       wl_proxy_wrapper_destroy(reinterpret_cast<wl_proxy *>(proxy));
63    };
64
65    return std::unique_ptr<T, std::function<void(T *)>>(proxy, delete_proxy);
66 }
67
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,
73 };
74
75 struct swapchain::wayland_image_data
76 {
77    int buffer_fd[MAX_PLANES];
78    int stride[MAX_PLANES];
79    uint32_t offset[MAX_PLANES];
80
81    wl_buffer *buffer;
82    VkDeviceMemory memory[MAX_PLANES];
83
84    uint32_t num_planes;
85 };
86
87 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
88    : swapchain_base(dev_data, pAllocator)
89    , m_display(nullptr)
90    , m_surface(nullptr)
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)
96 {
97 }
98
99 swapchain::~swapchain()
100 {
101    teardown();
102
103    wsialloc_delete(m_wsi_allocator);
104    m_wsi_allocator = nullptr;
105    if (m_surface_queue != nullptr)
106    {
107       wl_event_queue_destroy(m_surface_queue);
108    }
109    if (m_buffer_queue != nullptr)
110    {
111       wl_event_queue_destroy(m_buffer_queue);
112    }
113 }
114
115 struct display_queue
116 {
117    wl_display *display;
118    wl_event_queue *queue;
119 };
120
121 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
122 {
123    VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(pSwapchainCreateInfo->surface);
124
125    m_display = vk_surf->display;
126    m_surface = vk_surf->surface;
127
128    m_surface_queue = wl_display_create_queue(m_display);
129
130    if (m_surface_queue == nullptr)
131    {
132       WSI_LOG_ERROR("Failed to create wl surface display_queue.");
133       return VK_ERROR_INITIALIZATION_FAILED;
134    }
135
136    m_buffer_queue = wl_display_create_queue(m_display);
137    if (m_buffer_queue == nullptr)
138    {
139       WSI_LOG_ERROR("Failed to create wl buffer display_queue.");
140       return VK_ERROR_INITIALIZATION_FAILED;
141    }
142
143    auto display_proxy = make_proxy_with_queue(m_display, m_surface_queue);
144    if (display_proxy == nullptr)
145    {
146       WSI_LOG_ERROR("Failed to create wl display proxy.");
147       return VK_ERROR_INITIALIZATION_FAILED;
148    }
149
150    auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) };
151    if (registry == nullptr)
152    {
153       WSI_LOG_ERROR("Failed to get wl display registry.");
154       return VK_ERROR_INITIALIZATION_FAILED;
155    }
156
157    const wl_registry_listener registry_listener = { registry_handler };
158    int res = wl_registry_add_listener(registry.get(), &registry_listener, &m_dmabuf_interface);
159    if (res < 0)
160    {
161       WSI_LOG_ERROR("Failed to add registry listener.");
162       return VK_ERROR_INITIALIZATION_FAILED;
163    }
164
165    res = wl_display_roundtrip_queue(m_display, m_surface_queue);
166    if (res < 0)
167    {
168       WSI_LOG_ERROR("Roundtrip failed.");
169       return VK_ERROR_INITIALIZATION_FAILED;
170    }
171
172    if (m_dmabuf_interface.get() == nullptr)
173    {
174       return VK_ERROR_INITIALIZATION_FAILED;
175    }
176
177    if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
178    {
179       WSI_LOG_ERROR("Failed to create wsi allocator.");
180       return VK_ERROR_INITIALIZATION_FAILED;
181    }
182
183    return VK_SUCCESS;
184 }
185
186 extern "C" void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
187                                  struct wl_buffer *buffer)
188 {
189    auto wayland_buffer = reinterpret_cast<wl_buffer **>(data);
190    *wayland_buffer = buffer;
191 }
192
193 static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL };
194
195 extern "C" void buffer_release(void *data, struct wl_buffer *wayl_buffer)
196 {
197    auto sc = reinterpret_cast<swapchain *>(data);
198    sc->release_buffer(wayl_buffer);
199 }
200
201 void swapchain::release_buffer(struct wl_buffer *wayl_buffer)
202 {
203    uint32_t i;
204    for (i = 0; i < m_swapchain_images.size(); i++)
205    {
206       auto data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[i].data);
207       if (data->buffer == wayl_buffer)
208       {
209          unpresent_image(i);
210          break;
211       }
212    }
213
214    /* check we found a buffer to unpresent */
215    assert(i < m_swapchain_images.size());
216 }
217
218 static struct wl_buffer_listener buffer_listener = { buffer_release };
219
220 VkResult swapchain::allocate_plane_memory(int fd, VkDeviceMemory *memory)
221 {
222    uint32_t mem_index = -1;
223    VkResult result = get_fd_mem_type_index(fd, mem_index);
224    if (result != VK_SUCCESS)
225    {
226       return result;
227    }
228
229    const off_t dma_buf_size = lseek(fd, 0, SEEK_END);
230    if (dma_buf_size < 0)
231    {
232       WSI_LOG_ERROR("Failed to get DMA Buf size.");
233       return VK_ERROR_OUT_OF_HOST_MEMORY;
234    }
235
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;
240
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;
246
247    result = m_device_data.disp.AllocateMemory(
248       m_device, &alloc_info, get_allocation_callbacks(), memory);
249
250    if (result != VK_SUCCESS)
251    {
252       WSI_LOG_ERROR("Failed to import memory.");
253       return result;
254    }
255
256    return VK_SUCCESS;
257 }
258
259 VkResult swapchain::get_fd_mem_type_index(int fd, uint32_t &mem_idx)
260 {
261    VkMemoryFdPropertiesKHR mem_props = {};
262    mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
263
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)
267    {
268       WSI_LOG_ERROR("Error querying Fd properties.");
269       return result;
270    }
271
272    for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
273    {
274       if (mem_props.memoryTypeBits & (1 << mem_idx))
275       {
276          break;
277       }
278    }
279
280    assert(mem_idx < VK_MAX_MEMORY_TYPES);
281
282    return VK_SUCCESS;
283 }
284
285 VkResult swapchain::get_drm_format_properties(
286    VkFormat format, util::vector<VkDrmFormatModifierPropertiesEXT> &format_props_list)
287 {
288    VkDrmFormatModifierPropertiesListEXT format_modifier_props = {};
289    format_modifier_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
290
291    VkFormatProperties2KHR format_props = {};
292    format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
293    format_props.pNext = &format_modifier_props;
294
295    m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
296       m_device_data.physical_device, format, &format_props);
297
298    if (!format_props_list.try_resize(format_modifier_props.drmFormatModifierCount))
299    {
300       return VK_ERROR_OUT_OF_HOST_MEMORY;
301    }
302
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);
306
307    return VK_SUCCESS;
308 }
309
310 static bool is_disjoint_supported(
311    const util::vector<VkDrmFormatModifierPropertiesEXT> &format_props, uint64_t modifier)
312 {
313    for (const auto &prop : format_props)
314    {
315       if (prop.drmFormatModifier == modifier &&
316           prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT)
317       {
318          return true;
319       }
320    }
321
322    return false;
323 }
324
325 static uint32_t get_same_fd_index(int fd, int const *fds)
326 {
327    uint32_t index = 0;
328    while (fd != fds[index])
329    {
330       index++;
331    }
332
333    return index;
334 }
335
336 VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
337                                    VkImage *image)
338 {
339    VkResult result = VK_SUCCESS;
340    const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
341
342    image_data->buffer = nullptr;
343    image_data->num_planes = 0;
344    for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
345    {
346       image_data->buffer_fd[plane] = -1;
347       image_data->memory[plane] = VK_NULL_HANDLE;
348    }
349
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)
354    {
355       WSI_LOG_ERROR("Failed to get format properties.");
356       return result;
357    }
358    auto is_disjoint = is_disjoint_supported(drm_format_props, modifier);
359
360    VkExternalImageFormatPropertiesKHR external_props = {};
361    external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR;
362
363    VkImageFormatProperties2KHR format_props = {};
364    format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
365    format_props.pNext = &external_props;
366    {
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;
370
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;
378
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;
387
388       result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_device_data.physical_device,
389                                                                                            &info, &format_props);
390    }
391    if (result != VK_SUCCESS)
392    {
393       WSI_LOG_ERROR("Failed to get physical device format support.");
394       return result;
395    }
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)
399    {
400       WSI_LOG_ERROR("Physical device does not support required extent.");
401       return VK_ERROR_INITIALIZATION_FAILED;
402    }
403    if (format_props.imageFormatProperties.maxMipLevels < image_create_info.mipLevels ||
404        format_props.imageFormatProperties.maxArrayLayers < image_create_info.arrayLayers)
405    {
406       WSI_LOG_ERROR("Physical device does not support required array layers or mip levels.");
407       return VK_ERROR_INITIALIZATION_FAILED;
408    }
409    if ((format_props.imageFormatProperties.sampleCounts & image_create_info.samples) != image_create_info.samples)
410    {
411       WSI_LOG_ERROR("Physical device does not support required sample count.");
412       return VK_ERROR_INITIALIZATION_FAILED;
413    }
414
415    if (external_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR)
416    {
417       /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
418    }
419    if (!(external_props.externalMemoryProperties.externalMemoryFeatures &
420          VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))
421    {
422       WSI_LOG_ERROR("Export/Import not supported.");
423       return VK_ERROR_INITIALIZATION_FAILED;
424    }
425    else
426    {
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;
430
431       const uint64_t format_flags = is_disjoint ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
432       wsialloc_format format = {fourcc, modifier, format_flags};
433
434       const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
435       wsialloc_allocate_info alloc_info = {
436          &format,
437          1,
438          image_create_info.extent.width,
439          image_create_info.extent.height,
440          allocation_flags
441       };
442
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)
447       {
448          WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
449          if(res == WSIALLOC_ERROR_NOT_SUPPORTED)
450          {
451             return VK_ERROR_FORMAT_NOT_SUPPORTED;
452          }
453          return VK_ERROR_OUT_OF_HOST_MEMORY;
454       }
455
456       for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
457       {
458          if (image_data->buffer_fd[plane] == -1)
459          {
460             break;
461          }
462          image_data->num_planes++;
463       }
464
465       {
466          util::vector<VkSubresourceLayout> image_layout(m_allocator);
467          if (!image_layout.try_resize(image_data->num_planes))
468          {
469             return VK_ERROR_OUT_OF_HOST_MEMORY;
470          }
471
472          for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
473          {
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]);
477          }
478
479          if (is_disjoint)
480          {
481             image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
482          }
483
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();
490
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;
495
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);
500       }
501       if (result != VK_SUCCESS)
502       {
503          WSI_LOG_ERROR("Image creation failed.");
504          return result;
505       }
506       {
507          if (is_disjoint)
508          {
509             util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(m_allocator);
510             if (!bind_img_mem_infos.try_resize(image_data->num_planes))
511             {
512                return VK_ERROR_OUT_OF_HOST_MEMORY;
513             }
514
515             util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(m_allocator);
516             if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
517             {
518                return VK_ERROR_OUT_OF_HOST_MEMORY;
519             }
520
521             for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
522             {
523                const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
524                if (fd_index == plane)
525                {
526                   result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
527                   if (result != VK_SUCCESS)
528                   {
529                      return result;
530                   }
531                }
532
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;
536
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];
541             }
542
543             result = m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(),
544                                                             bind_img_mem_infos.data());
545          }
546          else
547          {
548             /* Make sure one fd has been allocated. */
549             for (uint32_t plane = 1; plane < image_data->num_planes; plane++)
550             {
551                if (image_data->buffer_fd[plane] != image_data->buffer_fd[0])
552                {
553                   WSI_LOG_ERROR("Different fds per plane for a non disjoint image.");
554                   return VK_ERROR_INITIALIZATION_FAILED;
555                }
556             }
557
558             result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
559             if (result != VK_SUCCESS)
560             {
561                return result;
562             }
563
564             result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0);
565          }
566       }
567    }
568
569    return result;
570 }
571
572 VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image)
573 {
574    /* Create image_data */
575    auto image_data = m_allocator.create<wayland_image_data>(1);
576    if (image_data == nullptr)
577    {
578       return VK_ERROR_OUT_OF_HOST_MEMORY;
579    }
580
581    std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
582
583    image.data = image_data;
584    image.status = swapchain_image::FREE;
585    VkResult result = allocate_image(image_create_info, image_data, &image.image);
586
587    image_status_lock.unlock();
588
589    if (result != VK_SUCCESS)
590    {
591       WSI_LOG_ERROR("Failed to allocate image.");
592       destroy_image(image);
593       return result;
594    }
595
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)
599    {
600       WSI_LOG_ERROR("Failed to allocate dma-buf interface proxy.");
601       destroy_image(image);
602       return VK_ERROR_INITIALIZATION_FAILED;
603    }
604
605    zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get());
606
607    for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
608    {
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);
611    }
612
613    auto res = zwp_linux_buffer_params_v1_add_listener(params, &params_listener, &image_data->buffer);
614    if (res < 0)
615    {
616       destroy_image(image);
617       return VK_ERROR_INITIALIZATION_FAILED;
618    }
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);
622
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);
626    if (res < 0)
627    {
628       destroy_image(image);
629       return VK_ERROR_INITIALIZATION_FAILED;
630    }
631
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);
637    if (res < 0)
638    {
639       destroy_image(image);
640       return VK_ERROR_INITIALIZATION_FAILED;
641    }
642
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)
647    {
648       destroy_image(image);
649       return result;
650    }
651
652    return VK_SUCCESS;
653 }
654
655 static void frame_done(void *data, wl_callback *cb, uint32_t cb_data)
656 {
657    (void)cb_data;
658
659    bool *present_pending = reinterpret_cast<bool *>(data);
660    assert(present_pending);
661
662    *present_pending = false;
663
664    wl_callback_destroy(cb);
665 }
666
667 void swapchain::present_image(uint32_t pendingIndex)
668 {
669    int res;
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)
673    {
674       assert(m_present_mode == VK_PRESENT_MODE_FIFO_KHR);
675       do
676       {
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
680           * window is hidden).
681           */
682          res = dispatch_queue(m_display, m_surface_queue, -1);
683       } while (res > 0 && m_present_pending);
684
685       if (res <= 0)
686       {
687          WSI_LOG_ERROR("error waiting for Wayland compositor frame hint");
688          m_is_valid = false;
689          /* try to present anyway */
690       }
691    }
692
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);
696
697    if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
698    {
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)
702       {
703          WSI_LOG_ERROR("failed to create wl_surface proxy");
704          m_is_valid = false;
705          return;
706       }
707
708       wl_callback *cb = wl_surface_frame(surface_proxy.get());
709       if (cb != nullptr)
710       {
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);
714       }
715    }
716
717    wl_surface_commit(m_surface);
718    res = wl_display_flush(m_display);
719    if (res < 0)
720    {
721       WSI_LOG_ERROR("error flushing the display");
722       /* Setting the swapchain as invalid */
723       m_is_valid = false;
724    }
725 }
726
727 void swapchain::destroy_image(swapchain_image &image)
728 {
729    std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
730
731    if (image.status != swapchain_image::INVALID)
732    {
733       if (image.present_fence != VK_NULL_HANDLE)
734       {
735          m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
736          image.present_fence = VK_NULL_HANDLE;
737       }
738
739       if (image.image != VK_NULL_HANDLE)
740       {
741          m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
742          image.image = VK_NULL_HANDLE;
743       }
744
745       image.status = swapchain_image::INVALID;
746    }
747
748    image_status_lock.unlock();
749
750    if (image.data != nullptr)
751    {
752       auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
753       if (image_data->buffer != nullptr)
754       {
755          wl_buffer_destroy(image_data->buffer);
756       }
757
758       for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
759       {
760          if (image_data->memory[plane] != VK_NULL_HANDLE)
761          {
762             m_device_data.disp.FreeMemory(m_device, image_data->memory[plane], get_allocation_callbacks());
763          }
764          else if (image_data->buffer_fd[plane] >= 0)
765          {
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)
768             {
769                close(image_data->buffer_fd[plane]);
770             }
771          }
772       }
773
774       m_allocator.destroy(1, image_data);
775       image.data = nullptr;
776    }
777 }
778
779 bool swapchain::free_image_found()
780 {
781    for (auto &img : m_swapchain_images)
782    {
783       if (img.status == swapchain_image::FREE)
784       {
785          return true;
786       }
787    }
788    return false;
789 }
790
791 VkResult swapchain::get_free_buffer(uint64_t *timeout)
792 {
793    int ms_timeout, res;
794
795    if (*timeout >= INT_MAX * 1000llu * 1000llu)
796    {
797       ms_timeout = INT_MAX;
798    }
799    else
800    {
801       ms_timeout = *timeout / 1000llu / 1000llu;
802    }
803
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.
807     */
808    do
809    {
810       res = dispatch_queue(m_display, m_buffer_queue, ms_timeout);
811    } while (!free_image_found() && res > 0);
812
813    if (res > 0)
814    {
815       *timeout = 0;
816       return VK_SUCCESS;
817    }
818    else if (res == 0)
819    {
820       if (*timeout == 0)
821       {
822          return VK_NOT_READY;
823       }
824       else
825       {
826          return VK_TIMEOUT;
827       }
828    }
829    else
830    {
831       return VK_ERROR_DEVICE_LOST;
832    }
833 }
834
835 } // namespace wayland
836 } // namespace wsi