Implement WSI layer swapchain functions for Tizen:
[platform/core/uifw/vulkan-wsi-tizen.git] / wsi / tizen / 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
29 #include <cstring>
30 #include <cassert>
31 #include <unistd.h>
32 #include <cstdlib>
33 #include <cerrno>
34 #include <cstdio>
35 #include <climits>
36 #include <drm_fourcc.h>
37
38 #if VULKAN_WSI_DEBUG > 0
39 #define WSI_PRINT_ERROR(fmt, ...) fprintf(stderr, "[%s:%d - %s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__)
40 #else
41 #define WSI_PRINT_ERROR(...) (void)0
42 #endif
43
44 namespace wsi
45 {
46 namespace tizen
47 {
48
49 struct swapchain::tizen_image_data
50 {
51    int buffer_fd;
52    tbm_surface_h tbm_buffer;
53
54    int stride;
55    uint32_t offset;
56
57    VkDeviceMemory memory;
58 };
59
60 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
61    : swapchain_base(dev_data, pAllocator)
62 {
63 }
64
65 swapchain::~swapchain()
66 {
67    teardown();
68    destroy_image();
69    tpl_surface_destroy_swapchain(m_tpl_surface);
70    tpl_object_unreference((tpl_object_t *)m_tpl_surface);
71    tpl_object_unreference((tpl_object_t *)m_tpl_display);
72 }
73
74 #define TBM_FORMAT_0    0
75 #define RETURN_FORMAT(comp, opaque, pre, post, inherit)                                 \
76         do {                                                                                                                            \
77                 if (comp == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)                                  \
78                         return TBM_FORMAT_##opaque;                                                                     \
79                 else if (comp == VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)             \
80                         return TBM_FORMAT_##pre;                                                                        \
81                 else if (comp == VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)    \
82                         return TBM_FORMAT_##post;                                                                       \
83                 else if (comp == VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)                    \
84                         return TBM_FORMAT_##inherit;                                                            \
85                 else                                                                                                                    \
86                         return 0;                                                                                                       \
87         } while (0)
88
89
90 static inline tbm_format
91 wsi_tizen_get_tbm_format(VkFormat format, VkCompositeAlphaFlagBitsKHR comp)
92 {
93         switch (format) {
94         /* 4 4 4 4 */
95         case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
96                 RETURN_FORMAT(comp, RGBX4444, RGBA4444, 0, RGBA4444);
97         case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
98                 RETURN_FORMAT(comp, BGRX4444, BGRA4444, 0, BGRA4444);
99         /* 5 6 5 */
100         case VK_FORMAT_R5G6B5_UNORM_PACK16:
101                 RETURN_FORMAT(comp, RGB565, RGB565, RGB565, RGB565);
102         case VK_FORMAT_B5G6R5_UNORM_PACK16:
103                 RETURN_FORMAT(comp, BGR565, BGR565, BGR565, BGR565);
104         /* 5 5 5 1 */
105         case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
106                 RETURN_FORMAT(comp, RGBX5551, RGBA5551, 0, RGBA5551);
107         case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
108                 RETURN_FORMAT(comp, BGRX5551, BGRA5551, 0, BGRA5551);
109         case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
110                 RETURN_FORMAT(comp, XRGB1555, ARGB1555, 0, ARGB1555);
111         /* 8 8 8 */
112         case VK_FORMAT_R8G8B8_UNORM:
113                 RETURN_FORMAT(comp, BGR888, BGR888, BGR888, BGR888);
114         case VK_FORMAT_B8G8R8_UNORM:
115                 RETURN_FORMAT(comp, RGB888, RGB888, RGB888, RGB888);
116         /* 8 8 8 8 */
117         case VK_FORMAT_B8G8R8A8_UNORM:
118                 RETURN_FORMAT(comp, XRGB8888, ARGB8888, 0, ARGB8888);
119         case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
120                 RETURN_FORMAT(comp, XBGR8888, ABGR8888, 0, ABGR8888);
121         /* 2 10 10 10 */
122         case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
123                 RETURN_FORMAT(comp, XRGB2101010, ARGB2101010, 0, ARGB2101010);
124         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
125                 RETURN_FORMAT(comp, XBGR2101010, ABGR2101010, 0, ABGR2101010);
126         default:
127                 break;
128         }
129
130         return 0;
131 }
132
133 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
134 {
135    VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(pSwapchainCreateInfo->surface);
136    tbm_format format;
137    int tpl_present_mode;
138    tpl_result_t res;
139
140    m_tpl_display = tpl_display_create(TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD, vk_surf->display);
141    if (m_tpl_display == NULL) {
142       WSI_PRINT_ERROR("create tpl display failed\n");
143           return VK_ERROR_INITIALIZATION_FAILED;
144    }
145    tpl_object_reference((tpl_object_t *)m_tpl_display);
146
147    format = wsi_tizen_get_tbm_format(pSwapchainCreateInfo->imageFormat, pSwapchainCreateInfo->compositeAlpha);
148    m_tpl_surface = tpl_surface_get(m_tpl_display, vk_surf->surface);
149    if (m_tpl_surface == NULL)
150       m_tpl_surface = tpl_surface_create(m_tpl_display, vk_surf->surface, TPL_SURFACE_TYPE_WINDOW, format);
151
152    if (m_tpl_surface == NULL) {
153       WSI_PRINT_ERROR("create tpl surface failed\n");
154           return VK_ERROR_INITIALIZATION_FAILED;
155    }
156    tpl_object_reference((tpl_object_t *)m_tpl_surface);
157
158    switch(pSwapchainCreateInfo->presentMode) {
159       case VK_PRESENT_MODE_IMMEDIATE_KHR:
160          tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_IMMEDIATE;
161          break;
162       case VK_PRESENT_MODE_MAILBOX_KHR:
163          tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_MAILBOX;
164          break;
165       case VK_PRESENT_MODE_FIFO_KHR:
166          tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO;
167          break;
168       case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
169          tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED;
170          break;
171       default:
172          WSI_PRINT_ERROR("unsupported present mode, presentMode[%d].", pSwapchainCreateInfo->presentMode);
173          return VK_ERROR_INITIALIZATION_FAILED;
174    }
175
176    res = tpl_surface_create_swapchain(m_tpl_surface, format,
177                                                                            pSwapchainCreateInfo->imageExtent.width, pSwapchainCreateInfo->imageExtent.height,
178                                                                            pSwapchainCreateInfo->minImageCount, tpl_present_mode);
179    if (res != TPL_ERROR_NONE) {
180            WSI_PRINT_ERROR("create swapchain failed, ret[%d].\n", res);
181            return VK_ERROR_INITIALIZATION_FAILED;
182    }
183
184    return VK_SUCCESS;
185 }
186
187 VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, tizen_image_data *image_data,
188                                    VkImage *image)
189 {
190    VkResult result = VK_SUCCESS;
191
192    assert(image_data->stride >= 0);
193    VkSubresourceLayout image_layout = {};
194    image_layout.offset = image_data->offset;
195    image_layout.rowPitch = static_cast<uint32_t>(image_data->stride);
196    VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {};
197    drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
198    drm_mod_info.pNext = image_create_info.pNext;
199    drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
200    drm_mod_info.drmFormatModifierPlaneCount = 1;
201    drm_mod_info.pPlaneLayouts = &image_layout;
202
203    VkExternalMemoryImageCreateInfoKHR external_info = {};
204    external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
205    external_info.pNext = &drm_mod_info;
206    external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
207
208    VkImageCreateInfo image_info = image_create_info;
209    image_info.pNext = &external_info;
210    image_info.tiling = VK_IMAGE_TILING_LINEAR;
211    result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image);
212    if (result != VK_SUCCESS)
213    {
214       WSI_PRINT_ERROR("Image creation failed.\n");
215       return result;
216    }
217
218    VkMemoryFdPropertiesKHR mem_props = {};
219    mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
220
221    result = m_device_data.disp.GetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
222                                                      image_data->buffer_fd, &mem_props);
223    if (result != VK_SUCCESS)
224    {
225       WSI_PRINT_ERROR("Error querying Fd properties.\n");
226       return result;
227    }
228
229    uint32_t mem_idx;
230    for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
231    {
232       if (mem_props.memoryTypeBits & (1 << mem_idx))
233       {
234          break;
235       }
236    }
237    off_t dma_buf_size = lseek(image_data->buffer_fd, 0, SEEK_END);
238    if (dma_buf_size < 0)
239    {
240       WSI_PRINT_ERROR("Failed to get DMA Buf size.\n");
241       return VK_ERROR_OUT_OF_HOST_MEMORY;
242    }
243
244    VkImportMemoryFdInfoKHR import_mem_info = {};
245    import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
246    import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
247    import_mem_info.fd = image_data->buffer_fd;
248
249    VkMemoryAllocateInfo alloc_info = {};
250    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
251    alloc_info.pNext = &import_mem_info;
252    alloc_info.allocationSize = static_cast<uint64_t>(dma_buf_size);
253    alloc_info.memoryTypeIndex = mem_idx;
254
255    result = m_device_data.disp.AllocateMemory(m_device, &alloc_info, get_allocation_callbacks(), &image_data->memory);
256
257    if (result != VK_SUCCESS)
258    {
259       WSI_PRINT_ERROR("Failed to import memory.\n");
260       return result;
261    }
262    result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory, 0);
263
264    return result;
265 }
266
267 VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info)
268 {
269    VkResult result = VK_SUCCESS;
270    tpl_result_t res;
271    tbm_surface_h *buffers;
272    int tbm_buf_cnt, i = 0;
273
274    res = tpl_surface_get_swapchain_buffers(m_tpl_surface, &buffers, &tbm_buf_cnt);
275    if (res == TPL_ERROR_OUT_OF_MEMORY)
276       return VK_ERROR_OUT_OF_HOST_MEMORY;
277    else if (res != TPL_ERROR_NONE)
278       return VK_ERROR_INITIALIZATION_FAILED;
279
280    if (!m_swapchain_images.try_resize(tbm_buf_cnt))
281       return VK_ERROR_OUT_OF_HOST_MEMORY;
282
283    i = 0;
284    for (auto &image: m_swapchain_images) {
285       tizen_image_data *image_data = nullptr;
286           if (get_allocation_callbacks() != nullptr)
287       {
288          image_data = static_cast<tizen_image_data *>(
289             get_allocation_callbacks()->pfnAllocation(get_allocation_callbacks()->pUserData, sizeof(tizen_image_data),
290                                                       alignof(tizen_image_data), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
291       } else {
292          image_data = static_cast<tizen_image_data *>(malloc(sizeof(tizen_image_data)));
293       }
294
295       tbm_surface_info_s info;
296       tbm_bo bo = tbm_surface_internal_get_bo(buffers[i], 0);
297       tbm_bo_handle bo_handle = tbm_bo_get_handle(bo, TBM_DEVICE_3D);
298       tbm_surface_get_info(buffers[i], &info);
299
300           image_data->tbm_buffer = buffers[i];
301       image_data->buffer_fd = bo_handle.u32;
302       image_data->stride = info.planes[0].stride;
303       image_data->offset = info.planes[0].offset;
304           image_data->memory = VK_NULL_HANDLE;
305
306           image.data = static_cast<void *>(image_data);
307
308       result = allocate_image(image_create_info, image_data, &image.image);
309       if (result != VK_SUCCESS)
310       {
311          WSI_PRINT_ERROR("Failed to allocate image.\n");
312          goto out;
313       }
314
315           /* Initialize presentation fence. */
316           VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 };
317       result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence);
318
319           i++;
320    }
321
322    return VK_SUCCESS;
323
324 out:
325
326    destroy_image();
327
328    return result;
329 }
330
331 VkResult swapchain::acquire_image(uint32_t *image_index)
332 {
333    tbm_surface_h tbm_buf = tpl_surface_dequeue_buffer_with_sync(m_tpl_surface, UINT64_MAX, NULL);
334
335    if (tbm_buf == NULL)
336       return VK_ERROR_SURFACE_LOST_KHR;
337
338    for (unsigned int i = 0; i < m_swapchain_images.size(); i++) {
339       tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(m_swapchain_images[i].data);
340       if (image_data->tbm_buffer == tbm_buf) {
341          *image_index = i;
342          return VK_SUCCESS;
343       }
344    }
345
346    return VK_ERROR_SURFACE_LOST_KHR;
347 }
348
349 void swapchain::present_image(uint32_t pendingIndex)
350 {
351    tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(m_swapchain_images[pendingIndex].data);
352    tpl_surface_enqueue_buffer_with_damage_and_sync(m_tpl_surface, image_data->tbm_buffer, 0, NULL, -1);
353 }
354
355 void swapchain::destroy_image(void)
356 {
357    for (auto &image: m_swapchain_images) {
358       if (image.present_fence != VK_NULL_HANDLE)
359       {
360          m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
361          image.present_fence = VK_NULL_HANDLE;
362       }
363       if (image.image != VK_NULL_HANDLE)
364       {
365          m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
366          image.image = VK_NULL_HANDLE;
367       }
368       if (image.data != nullptr)
369       {
370          tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(image.data);
371          if (image_data->memory != VK_NULL_HANDLE)
372          {
373             m_device_data.disp.FreeMemory(m_device, image_data->memory, get_allocation_callbacks());
374          }
375          else if (image_data->buffer_fd >= 0)
376          {
377             close(image_data->buffer_fd);
378          }
379          if (get_allocation_callbacks() != nullptr)
380          {
381             get_allocation_callbacks()->pfnFree(get_allocation_callbacks()->pUserData, image_data);
382          }
383          else
384          {
385             free(image_data);
386          }
387          image.data = nullptr;
388       }
389    }
390 }
391
392 } // namespace wayland
393 } // namespace wsi