wsi: Move common objects to the wayland wsi::surface
[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 #include "surface_properties.hpp"
30
31 #include <stdint.h>
32 #include <cstring>
33 #include <cassert>
34 #include <unistd.h>
35 #include <cstdlib>
36 #include <cerrno>
37 #include <cstdio>
38 #include <climits>
39 #include <functional>
40
41 #include "util/drm/drm_utils.hpp"
42 #include "util/log.hpp"
43
44 #define MAX_PLANES 4
45
46 namespace wsi
47 {
48 namespace wayland
49 {
50
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,
56 };
57
58 struct swapchain::wayland_image_data
59 {
60    int buffer_fd[MAX_PLANES];
61    int stride[MAX_PLANES];
62    uint32_t offset[MAX_PLANES];
63
64    wl_buffer *buffer;
65    VkDeviceMemory memory[MAX_PLANES];
66
67    uint32_t num_planes;
68 };
69
70 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator,
71                      surface &wsi_surface)
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)
80 {
81 }
82
83 swapchain::~swapchain()
84 {
85    teardown();
86
87    wsialloc_delete(m_wsi_allocator);
88    m_wsi_allocator = nullptr;
89    if (m_swapchain_queue != nullptr)
90    {
91       wl_event_queue_destroy(m_swapchain_queue);
92    }
93    if (m_buffer_queue != nullptr)
94    {
95       wl_event_queue_destroy(m_buffer_queue);
96    }
97 }
98
99 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
100 {
101    if ((m_display == nullptr) || (m_surface == nullptr) || (m_dmabuf_interface == nullptr))
102    {
103       return VK_ERROR_INITIALIZATION_FAILED;
104    }
105
106    m_swapchain_queue = wl_display_create_queue(m_display);
107
108    if (m_swapchain_queue == nullptr)
109    {
110       WSI_LOG_ERROR("Failed to create swapchain wl queue.");
111       return VK_ERROR_INITIALIZATION_FAILED;
112    }
113
114    m_buffer_queue = wl_display_create_queue(m_display);
115    if (m_buffer_queue == nullptr)
116    {
117       WSI_LOG_ERROR("Failed to create buffer wl queue.");
118       return VK_ERROR_INITIALIZATION_FAILED;
119    }
120
121    if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
122    {
123       WSI_LOG_ERROR("Failed to create wsi allocator.");
124       return VK_ERROR_INITIALIZATION_FAILED;
125    }
126
127    return VK_SUCCESS;
128 }
129
130 extern "C" void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
131                                  struct wl_buffer *buffer)
132 {
133    auto wayland_buffer = reinterpret_cast<wl_buffer **>(data);
134    *wayland_buffer = buffer;
135 }
136
137 static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL };
138
139 extern "C" void buffer_release(void *data, struct wl_buffer *wayl_buffer)
140 {
141    auto sc = reinterpret_cast<swapchain *>(data);
142    sc->release_buffer(wayl_buffer);
143 }
144
145 void swapchain::release_buffer(struct wl_buffer *wayl_buffer)
146 {
147    uint32_t i;
148    for (i = 0; i < m_swapchain_images.size(); i++)
149    {
150       auto data = reinterpret_cast<wayland_image_data *>(m_swapchain_images[i].data);
151       if (data->buffer == wayl_buffer)
152       {
153          unpresent_image(i);
154          break;
155       }
156    }
157
158    /* check we found a buffer to unpresent */
159    assert(i < m_swapchain_images.size());
160 }
161
162 static struct wl_buffer_listener buffer_listener = { buffer_release };
163
164 VkResult swapchain::allocate_plane_memory(int fd, VkDeviceMemory *memory)
165 {
166    uint32_t mem_index = -1;
167    VkResult result = get_fd_mem_type_index(fd, mem_index);
168    if (result != VK_SUCCESS)
169    {
170       return result;
171    }
172
173    const off_t dma_buf_size = lseek(fd, 0, SEEK_END);
174    if (dma_buf_size < 0)
175    {
176       WSI_LOG_ERROR("Failed to get DMA Buf size.");
177       return VK_ERROR_OUT_OF_HOST_MEMORY;
178    }
179
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;
184
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;
190
191    result = m_device_data.disp.AllocateMemory(
192       m_device, &alloc_info, get_allocation_callbacks(), memory);
193
194    if (result != VK_SUCCESS)
195    {
196       WSI_LOG_ERROR("Failed to import memory.");
197       return result;
198    }
199
200    return VK_SUCCESS;
201 }
202
203 VkResult swapchain::get_fd_mem_type_index(int fd, uint32_t &mem_idx)
204 {
205    VkMemoryFdPropertiesKHR mem_props = {};
206    mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
207
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)
211    {
212       WSI_LOG_ERROR("Error querying Fd properties.");
213       return result;
214    }
215
216    for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
217    {
218       if (mem_props.memoryTypeBits & (1 << mem_idx))
219       {
220          break;
221       }
222    }
223
224    assert(mem_idx < VK_MAX_MEMORY_TYPES);
225
226    return VK_SUCCESS;
227 }
228
229 VkResult swapchain::get_drm_format_properties(
230    VkFormat format, util::vector<VkDrmFormatModifierPropertiesEXT> &format_props_list)
231 {
232    VkDrmFormatModifierPropertiesListEXT format_modifier_props = {};
233    format_modifier_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
234
235    VkFormatProperties2KHR format_props = {};
236    format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
237    format_props.pNext = &format_modifier_props;
238
239    m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR(
240       m_device_data.physical_device, format, &format_props);
241
242    if (!format_props_list.try_resize(format_modifier_props.drmFormatModifierCount))
243    {
244       return VK_ERROR_OUT_OF_HOST_MEMORY;
245    }
246
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);
250
251    return VK_SUCCESS;
252 }
253
254 static bool is_disjoint_supported(
255    const util::vector<VkDrmFormatModifierPropertiesEXT> &format_props, uint64_t modifier)
256 {
257    for (const auto &prop : format_props)
258    {
259       if (prop.drmFormatModifier == modifier &&
260           prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT)
261       {
262          return true;
263       }
264    }
265
266    return false;
267 }
268
269 static uint32_t get_same_fd_index(int fd, int const *fds)
270 {
271    uint32_t index = 0;
272    while (fd != fds[index])
273    {
274       index++;
275    }
276
277    return index;
278 }
279
280 VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data,
281                                    VkImage *image)
282 {
283    VkResult result = VK_SUCCESS;
284    const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
285
286    image_data->buffer = nullptr;
287    image_data->num_planes = 0;
288    for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
289    {
290       image_data->buffer_fd[plane] = -1;
291       image_data->memory[plane] = VK_NULL_HANDLE;
292    }
293
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)
298    {
299       WSI_LOG_ERROR("Failed to get format properties.");
300       return result;
301    }
302    auto is_disjoint = is_disjoint_supported(drm_format_props, modifier);
303
304    VkExternalImageFormatPropertiesKHR external_props = {};
305    external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR;
306
307    VkImageFormatProperties2KHR format_props = {};
308    format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
309    format_props.pNext = &external_props;
310    {
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;
314
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;
322
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;
331
332       result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_device_data.physical_device,
333                                                                                            &info, &format_props);
334    }
335    if (result != VK_SUCCESS)
336    {
337       WSI_LOG_ERROR("Failed to get physical device format support.");
338       return result;
339    }
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)
343    {
344       WSI_LOG_ERROR("Physical device does not support required extent.");
345       return VK_ERROR_INITIALIZATION_FAILED;
346    }
347    if (format_props.imageFormatProperties.maxMipLevels < image_create_info.mipLevels ||
348        format_props.imageFormatProperties.maxArrayLayers < image_create_info.arrayLayers)
349    {
350       WSI_LOG_ERROR("Physical device does not support required array layers or mip levels.");
351       return VK_ERROR_INITIALIZATION_FAILED;
352    }
353    if ((format_props.imageFormatProperties.sampleCounts & image_create_info.samples) != image_create_info.samples)
354    {
355       WSI_LOG_ERROR("Physical device does not support required sample count.");
356       return VK_ERROR_INITIALIZATION_FAILED;
357    }
358
359    if (external_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR)
360    {
361       /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */
362    }
363    if (!(external_props.externalMemoryProperties.externalMemoryFeatures &
364          VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))
365    {
366       WSI_LOG_ERROR("Export/Import not supported.");
367       return VK_ERROR_INITIALIZATION_FAILED;
368    }
369    else
370    {
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;
374
375       const uint64_t format_flags = is_disjoint ? 0 : WSIALLOC_FORMAT_NON_DISJOINT;
376       wsialloc_format format = {fourcc, modifier, format_flags};
377
378       const uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
379       wsialloc_allocate_info alloc_info = {
380          &format,
381          1,
382          image_create_info.extent.width,
383          image_create_info.extent.height,
384          allocation_flags
385       };
386
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)
391       {
392          WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
393          if(res == WSIALLOC_ERROR_NOT_SUPPORTED)
394          {
395             return VK_ERROR_FORMAT_NOT_SUPPORTED;
396          }
397          return VK_ERROR_OUT_OF_HOST_MEMORY;
398       }
399
400       for (uint32_t plane = 0; plane < MAX_PLANES; plane++)
401       {
402          if (image_data->buffer_fd[plane] == -1)
403          {
404             break;
405          }
406          image_data->num_planes++;
407       }
408
409       {
410          util::vector<VkSubresourceLayout> image_layout(m_allocator);
411          if (!image_layout.try_resize(image_data->num_planes))
412          {
413             return VK_ERROR_OUT_OF_HOST_MEMORY;
414          }
415
416          for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
417          {
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]);
421          }
422
423          if (is_disjoint)
424          {
425             image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
426          }
427
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();
434
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;
439
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);
444       }
445       if (result != VK_SUCCESS)
446       {
447          WSI_LOG_ERROR("Image creation failed.");
448          return result;
449       }
450       {
451          if (is_disjoint)
452          {
453             util::vector<VkBindImageMemoryInfo> bind_img_mem_infos(m_allocator);
454             if (!bind_img_mem_infos.try_resize(image_data->num_planes))
455             {
456                return VK_ERROR_OUT_OF_HOST_MEMORY;
457             }
458
459             util::vector<VkBindImagePlaneMemoryInfo> bind_plane_mem_infos(m_allocator);
460             if (!bind_plane_mem_infos.try_resize(image_data->num_planes))
461             {
462                return VK_ERROR_OUT_OF_HOST_MEMORY;
463             }
464
465             for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
466             {
467                const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd);
468                if (fd_index == plane)
469                {
470                   result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]);
471                   if (result != VK_SUCCESS)
472                   {
473                      return result;
474                   }
475                }
476
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;
480
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];
485             }
486
487             result = m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(),
488                                                             bind_img_mem_infos.data());
489          }
490          else
491          {
492             /* Make sure one fd has been allocated. */
493             for (uint32_t plane = 1; plane < image_data->num_planes; plane++)
494             {
495                if (image_data->buffer_fd[plane] != image_data->buffer_fd[0])
496                {
497                   WSI_LOG_ERROR("Different fds per plane for a non disjoint image.");
498                   return VK_ERROR_INITIALIZATION_FAILED;
499                }
500             }
501
502             result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]);
503             if (result != VK_SUCCESS)
504             {
505                return result;
506             }
507
508             result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0);
509          }
510       }
511    }
512
513    return result;
514 }
515
516 VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image)
517 {
518    /* Create image_data */
519    auto image_data = m_allocator.create<wayland_image_data>(1);
520    if (image_data == nullptr)
521    {
522       return VK_ERROR_OUT_OF_HOST_MEMORY;
523    }
524
525    std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
526
527    image.data = image_data;
528    image.status = swapchain_image::FREE;
529    VkResult result = allocate_image(image_create_info, image_data, &image.image);
530
531    image_status_lock.unlock();
532
533    if (result != VK_SUCCESS)
534    {
535       WSI_LOG_ERROR("Failed to allocate image.");
536       destroy_image(image);
537       return result;
538    }
539
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)
543    {
544       WSI_LOG_ERROR("Failed to allocate dma-buf interface proxy.");
545       destroy_image(image);
546       return VK_ERROR_INITIALIZATION_FAILED;
547    }
548
549    zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get());
550
551    for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
552    {
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);
555    }
556
557    auto res = zwp_linux_buffer_params_v1_add_listener(params, &params_listener, &image_data->buffer);
558    if (res < 0)
559    {
560       destroy_image(image);
561       return VK_ERROR_INITIALIZATION_FAILED;
562    }
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);
566
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);
570    if (res < 0)
571    {
572       destroy_image(image);
573       return VK_ERROR_INITIALIZATION_FAILED;
574    }
575
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);
581    if (res < 0)
582    {
583       destroy_image(image);
584       return VK_ERROR_INITIALIZATION_FAILED;
585    }
586
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)
591    {
592       destroy_image(image);
593       return result;
594    }
595
596    return VK_SUCCESS;
597 }
598
599 static void frame_done(void *data, wl_callback *cb, uint32_t cb_data)
600 {
601    (void)cb_data;
602
603    bool *present_pending = reinterpret_cast<bool *>(data);
604    assert(present_pending);
605
606    *present_pending = false;
607
608    wl_callback_destroy(cb);
609 }
610
611 void swapchain::present_image(uint32_t pendingIndex)
612 {
613    int res;
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)
617    {
618       assert(m_present_mode == VK_PRESENT_MODE_FIFO_KHR);
619       do
620       {
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
624           * window is hidden).
625           */
626          res = dispatch_queue(m_display, m_swapchain_queue, -1);
627       } while (res > 0 && m_present_pending);
628
629       if (res <= 0)
630       {
631          WSI_LOG_ERROR("error waiting for Wayland compositor frame hint");
632          m_is_valid = false;
633          /* try to present anyway */
634       }
635    }
636
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);
640
641    if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
642    {
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)
646       {
647          WSI_LOG_ERROR("failed to create wl_surface proxy");
648          m_is_valid = false;
649          return;
650       }
651
652       wl_callback *cb = wl_surface_frame(surface_proxy.get());
653       if (cb != nullptr)
654       {
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);
658       }
659    }
660
661    wl_surface_commit(m_surface);
662    res = wl_display_flush(m_display);
663    if (res < 0)
664    {
665       WSI_LOG_ERROR("error flushing the display");
666       /* Setting the swapchain as invalid */
667       m_is_valid = false;
668    }
669 }
670
671 void swapchain::destroy_image(swapchain_image &image)
672 {
673    std::unique_lock<std::recursive_mutex> image_status_lock(m_image_status_mutex);
674
675    if (image.status != swapchain_image::INVALID)
676    {
677       if (image.present_fence != VK_NULL_HANDLE)
678       {
679          m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
680          image.present_fence = VK_NULL_HANDLE;
681       }
682
683       if (image.image != VK_NULL_HANDLE)
684       {
685          m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
686          image.image = VK_NULL_HANDLE;
687       }
688
689       image.status = swapchain_image::INVALID;
690    }
691
692    image_status_lock.unlock();
693
694    if (image.data != nullptr)
695    {
696       auto image_data = reinterpret_cast<wayland_image_data *>(image.data);
697       if (image_data->buffer != nullptr)
698       {
699          wl_buffer_destroy(image_data->buffer);
700       }
701
702       for (uint32_t plane = 0; plane < image_data->num_planes; plane++)
703       {
704          if (image_data->memory[plane] != VK_NULL_HANDLE)
705          {
706             m_device_data.disp.FreeMemory(m_device, image_data->memory[plane], get_allocation_callbacks());
707          }
708          else if (image_data->buffer_fd[plane] >= 0)
709          {
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)
712             {
713                close(image_data->buffer_fd[plane]);
714             }
715          }
716       }
717
718       m_allocator.destroy(1, image_data);
719       image.data = nullptr;
720    }
721 }
722
723 bool swapchain::free_image_found()
724 {
725    for (auto &img : m_swapchain_images)
726    {
727       if (img.status == swapchain_image::FREE)
728       {
729          return true;
730       }
731    }
732    return false;
733 }
734
735 VkResult swapchain::get_free_buffer(uint64_t *timeout)
736 {
737    int ms_timeout, res;
738
739    if (*timeout >= INT_MAX * 1000llu * 1000llu)
740    {
741       ms_timeout = INT_MAX;
742    }
743    else
744    {
745       ms_timeout = *timeout / 1000llu / 1000llu;
746    }
747
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.
751     */
752    do
753    {
754       res = dispatch_queue(m_display, m_buffer_queue, ms_timeout);
755    } while (!free_image_found() && res > 0);
756
757    if (res > 0)
758    {
759       *timeout = 0;
760       return VK_SUCCESS;
761    }
762    else if (res == 0)
763    {
764       if (*timeout == 0)
765       {
766          return VK_NOT_READY;
767       }
768       else
769       {
770          return VK_TIMEOUT;
771       }
772    }
773    else
774    {
775       return VK_ERROR_DEVICE_LOST;
776    }
777 }
778
779 } // namespace wayland
780 } // namespace wsi