8d5be3337681042b9b13d4259a8035ceb2bc2d1d
[platform/core/uifw/vulkan-wsi-tizen.git] / src / wsi / swapchain.c
1 /*
2  * Copyright © 2016 S-Core Corporation
3  * Copyright © 2016-2017 Samsung Electronics co., Ltd. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * 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
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24
25 #include "wsi.h"
26 #include <string.h>
27 #include <unistd.h>
28 #include <tbm_sync.h>
29
30 #define TBM_FORMAT_0    0
31
32 #define RETURN_FORMAT(comp, opaque, pre, post, inherit)                                 \
33         do {                                                                                                                            \
34                 if (comp == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)                                  \
35                         return TBM_FORMAT_##opaque;                                                                     \
36                 else if (comp == VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)             \
37                         return TBM_FORMAT_##pre;                                                                        \
38                 else if (comp == VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)    \
39                         return TBM_FORMAT_##post;                                                                       \
40                 else if (comp == VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)                    \
41                         return TBM_FORMAT_##inherit;                                                            \
42                 else                                                                                                                    \
43                         return 0;                                                                                                       \
44         } while (0)
45
46 static inline tbm_format
47 get_tbm_format(VkFormat format, VkCompositeAlphaFlagBitsKHR comp)
48 {
49         switch (format) {
50         /* 4 4 4 4 */
51         case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
52                 RETURN_FORMAT(comp, RGBX4444, RGBA4444, 0, RGBA4444);
53         case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
54                 RETURN_FORMAT(comp, BGRX4444, BGRA4444, 0, BGRA4444);
55         /* 5 6 5 */
56         case VK_FORMAT_R5G6B5_UNORM_PACK16:
57                 RETURN_FORMAT(comp, RGB565, RGB565, RGB565, RGB565);
58         case VK_FORMAT_B5G6R5_UNORM_PACK16:
59                 RETURN_FORMAT(comp, BGR565, BGR565, BGR565, BGR565);
60         /* 5 5 5 1 */
61         case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
62                 RETURN_FORMAT(comp, RGBX5551, RGBA5551, 0, RGBA5551);
63         case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
64                 RETURN_FORMAT(comp, BGRX5551, BGRA5551, 0, BGRA5551);
65         case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
66                 RETURN_FORMAT(comp, XRGB1555, ARGB1555, 0, ARGB1555);
67         /* 8 8 8 */
68         case VK_FORMAT_R8G8B8_UNORM:
69                 RETURN_FORMAT(comp, BGR888, BGR888, BGR888, BGR888);
70         case VK_FORMAT_B8G8R8_UNORM:
71                 RETURN_FORMAT(comp, RGB888, RGB888, RGB888, RGB888);
72         /* 8 8 8 8 */
73         case VK_FORMAT_B8G8R8A8_UNORM:
74                 RETURN_FORMAT(comp, XRGB8888, ARGB8888, 0, ARGB8888);
75         case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
76                 RETURN_FORMAT(comp, XBGR8888, ABGR8888, 0, ABGR8888);
77         /* 2 10 10 10 */
78         case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
79                 RETURN_FORMAT(comp, XRGB2101010, ARGB2101010, 0, ARGB2101010);
80         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
81                 RETURN_FORMAT(comp, XBGR2101010, ABGR2101010, 0, ABGR2101010);
82         default:
83                 break;
84         }
85
86         return 0;
87 }
88
89 VKAPI_ATTR VkResult VKAPI_CALL
90 vk_CreateSwapchainKHR(VkDevice                                                   device,
91                                           const VkSwapchainCreateInfoKHR        *info,
92                                           const VkAllocationCallbacks           *allocator,
93                                           VkSwapchainKHR                                        *swapchain)
94 {
95         vk_icd_t                        *icd = vk_get_icd();
96         vk_swapchain_t          *chain;
97         tbm_format                       format;
98         tpl_result_t             res;
99         VkIcdSurfaceWayland     *surface = (VkIcdSurfaceWayland *)(uintptr_t)info->surface;
100         int                                      buffer_count, i;
101         tbm_surface_h           *buffers;
102         VkResult error = VK_ERROR_DEVICE_LOST;
103
104         VK_ASSERT(surface->base.platform == VK_ICD_WSI_PLATFORM_WAYLAND);
105
106         format = get_tbm_format(info->imageFormat, info->compositeAlpha);
107         VK_CHECK(format, return VK_ERROR_SURFACE_LOST_KHR, "Not supported image format.\n");
108
109         allocator = vk_get_allocator(device, allocator);
110
111         chain = vk_alloc(allocator, sizeof(vk_swapchain_t), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
112         VK_CHECK(chain, return VK_ERROR_OUT_OF_HOST_MEMORY, "vk_alloc() failed.\n");
113
114         memset(chain, 0x00, sizeof(vk_swapchain_t));
115
116         chain->allocator = *allocator;
117         chain->surface = info->surface;
118
119         /* Don't check NULL for display and window. There might be default ones for some systems. */
120
121         chain->tpl_display = vk_get_tpl_display(surface->display);
122         VK_CHECK(chain->tpl_display, goto error, "vk_get_tpl_display() failed.\n");
123
124         chain->tpl_surface = tpl_surface_create(chain->tpl_display, surface->surface,
125                                                                                         TPL_SURFACE_TYPE_WINDOW, format);
126         VK_CHECK(chain->tpl_surface, goto error, "tpl_surface_create() failed.\n");
127
128         res = tpl_surface_create_swapchain(chain->tpl_surface, format,
129                                                                            info->imageExtent.width, info->imageExtent.height,
130                                                                            info->minImageCount);
131         VK_CHECK(res == TPL_ERROR_NONE, goto error, "tpl_surface_create_swapchain() failed.\n");
132
133         /* Initialize swapchain buffers. */
134         res = tpl_surface_get_swapchain_buffers(chain->tpl_surface, &buffers, &buffer_count);
135         VK_CHECK(res == TPL_ERROR_NONE, goto error_get_buffers, "tpl_surface_get_swapchain_buffers() failed.\n");
136
137         chain->buffers = vk_alloc(allocator, buffer_count * sizeof(vk_buffer_t),
138                                                           VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
139         VK_CHECK(chain->buffers, goto error_mem_alloc, "vk_alloc() failed.\n");
140
141         for (i = 0; i < buffer_count; i++) {
142                 VkImageCreateInfo image_info = {
143                         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
144                         NULL,
145                         0,
146                         VK_IMAGE_TYPE_2D,
147                         info->imageFormat,
148                         { info->imageExtent.width, info->imageExtent.height, 1 },
149                         1, /* mip level. */
150                         info->imageArrayLayers,
151                         VK_SAMPLE_COUNT_1_BIT,
152                         VK_IMAGE_TILING_LINEAR,
153                         info->imageUsage,
154                         info->imageSharingMode,
155                         info->queueFamilyIndexCount,
156                         info->pQueueFamilyIndices,
157                         VK_IMAGE_LAYOUT_UNDEFINED,
158                 };
159
160                 chain->buffers[i].tbm = buffers[i];
161                 icd->create_presentable_image(device, buffers[i], &image_info, allocator,
162                                                                           &chain->buffers[i].image);
163         }
164
165         chain->buffer_count = buffer_count;
166         *swapchain = (VkSwapchainKHR)(uintptr_t)chain;
167         return VK_SUCCESS;
168
169 error_mem_alloc:
170         error = VK_ERROR_OUT_OF_HOST_MEMORY;
171
172 error_get_buffers:
173         tpl_surface_destroy_swapchain(chain->tpl_surface);
174
175 error:
176         if (chain->tpl_display)
177                 tpl_object_unreference((tpl_object_t *)chain->tpl_display);
178
179         if (chain->tpl_surface)
180                 tpl_object_unreference((tpl_object_t *)chain->tpl_surface);
181
182         if (chain->buffers)
183                 vk_free(allocator, chain->buffers);
184
185         vk_free(allocator, chain);
186         *swapchain = VK_NULL_HANDLE;
187         return error;
188 }
189
190 VKAPI_ATTR VkResult VKAPI_CALL
191 vk_CreateSharedSwapchainsKHR(VkDevice                                            device,
192                                                          uint32_t                                                swapchain_count,
193                                                          const VkSwapchainCreateInfoKHR *infos,
194                                                          const VkAllocationCallbacks    *allocator,
195                                                          VkSwapchainKHR                                 *swapchains)
196 {
197         /* TODO: */
198         return VK_SUCCESS;
199 }
200
201 VKAPI_ATTR void VKAPI_CALL
202 vk_DestroySwapchainKHR(VkDevice                                          device,
203                                            VkSwapchainKHR                                swapchain,
204                                            const VkAllocationCallbacks  *allocator)
205 {
206         vk_swapchain_t *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
207
208         tpl_surface_destroy_swapchain(chain->tpl_surface);
209         free(chain->buffers);
210
211         if (chain->tpl_surface)
212                 tpl_object_unreference((tpl_object_t *)chain->tpl_surface);
213
214         if (chain->tpl_display)
215                 tpl_object_unreference((tpl_object_t *)chain->tpl_display);
216
217         vk_free(&chain->allocator, chain);
218 }
219
220 VKAPI_ATTR VkResult VKAPI_CALL
221 vk_GetSwapchainImagesKHR(VkDevice                device,
222                                                  VkSwapchainKHR  swapchain,
223                                                  uint32_t               *image_count,
224                                                  VkImage                *images)
225 {
226         vk_swapchain_t *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
227
228         if (images) {
229                 uint32_t i;
230
231                 *image_count = MIN(*image_count, chain->buffer_count);
232
233                 for (i = 0; i < *image_count; i++)
234                         images[i] = chain->buffers[i].image;
235
236                 if (*image_count < chain->buffer_count)
237                         return VK_INCOMPLETE;
238         } else {
239                 *image_count = chain->buffer_count;
240         }
241
242         return VK_SUCCESS;
243 }
244
245 VKAPI_ATTR VkResult VKAPI_CALL
246 vk_AcquireNextImageKHR(VkDevice                  device,
247                                            VkSwapchainKHR        swapchain,
248                                            uint64_t                      timeout,
249                                            VkSemaphore           semaphore,
250                                            VkFence                       fence,
251                                            uint32_t                     *image_index)
252 {
253         vk_icd_t                *icd = vk_get_icd();
254         uint32_t                 i;
255         tbm_surface_h    next;
256         vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
257         int sync_fd = -1;
258
259         if (icd->acquire_image) {
260                 next = tpl_surface_dequeue_buffer_with_sync(chain->tpl_surface, timeout, &sync_fd);
261
262                 if (next == NULL)
263                         return VK_TIMEOUT;
264         } else {
265                 next = tpl_surface_dequeue_buffer(chain->tpl_surface);
266                 VK_CHECK(next, return VK_ERROR_SURFACE_LOST_KHR, "tpl_surface_dequeue_buffers() failed\n.");
267         }
268
269         for (i = 0; i < chain->buffer_count; i++) {
270                 if (next == chain->buffers[i].tbm) {
271                         *image_index = i;
272                         if (icd->acquire_image)
273                                 icd->acquire_image(device, chain->buffers[i].image, sync_fd, semaphore, fence);
274
275                         /* TODO: We can do optimization here by returning buffer index immediatly despite the
276                          * buffer is not released yet. The fence or semaphore will be signaled when
277                          * wl_buffer.release actually arrives. */
278
279                         return VK_SUCCESS;
280                 }
281         }
282
283         return VK_ERROR_SURFACE_LOST_KHR;
284 }
285
286 VKAPI_ATTR VkResult VKAPI_CALL
287 vk_QueuePresentKHR(VkQueue                                       queue,
288                                    const VkPresentInfoKHR       *info)
289 {
290         vk_icd_t        *icd = vk_get_icd();
291         uint32_t         i;
292
293         for (i = 0; i < info->swapchainCount; i++) {
294                 int sync_fd = -1;
295                 tpl_result_t res;
296                 vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)info->pSwapchains[i];
297
298                 if (icd->queue_signal_release_image)
299                         icd->queue_signal_release_image(queue, info->waitSemaphoreCount, info->pWaitSemaphores,
300                                                                                         chain->buffers[info->pImageIndices[i]].image, &sync_fd);
301
302                 res = tpl_surface_enqueue_buffer_with_damage_and_sync(chain->tpl_surface,
303                                                                                                                           chain->buffers[info->pImageIndices[i]].tbm,
304                                                                                                                           0, NULL, sync_fd);
305
306                 if (info->pResults != NULL)
307                         info->pResults[i] = res == TPL_ERROR_NONE ? VK_SUCCESS : VK_ERROR_DEVICE_LOST;
308         }
309
310         return VK_SUCCESS;
311 }