swapchain: added return case of VK_ERROR_OUT_OF_DEVICE_MEMORY on vk_CreateSwapchainKHR()
[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         if (res == TPL_ERROR_OUT_OF_MEMORY) {
132                 error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
133                 VK_ERROR("tpl_surface_create_swapchain() failed.\n");
134                 goto error;
135         }
136         VK_CHECK(res == TPL_ERROR_NONE, goto error, "tpl_surface_create_swapchain() failed.\n");
137
138         /* Initialize swapchain buffers. */
139         res = tpl_surface_get_swapchain_buffers(chain->tpl_surface, &buffers, &buffer_count);
140         if (res == TPL_ERROR_OUT_OF_MEMORY) {
141                 error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
142                 VK_ERROR("tpl_surface_get_swapchain_buffers() failed.\n");
143                 goto error_get_buffers;
144         }
145         VK_CHECK(res == TPL_ERROR_NONE, goto error_get_buffers, "tpl_surface_get_swapchain_buffers() failed.\n");
146
147         chain->buffers = vk_alloc(allocator, buffer_count * sizeof(vk_buffer_t),
148                                                           VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
149         VK_CHECK(chain->buffers, goto error_mem_alloc, "vk_alloc() failed.\n");
150
151         for (i = 0; i < buffer_count; i++) {
152                 VkImageCreateInfo image_info = {
153                         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
154                         NULL,
155                         0,
156                         VK_IMAGE_TYPE_2D,
157                         info->imageFormat,
158                         { info->imageExtent.width, info->imageExtent.height, 1 },
159                         1, /* mip level. */
160                         info->imageArrayLayers,
161                         VK_SAMPLE_COUNT_1_BIT,
162                         VK_IMAGE_TILING_LINEAR,
163                         info->imageUsage,
164                         info->imageSharingMode,
165                         info->queueFamilyIndexCount,
166                         info->pQueueFamilyIndices,
167                         VK_IMAGE_LAYOUT_UNDEFINED,
168                 };
169
170                 chain->buffers[i].tbm = buffers[i];
171                 icd->create_presentable_image(device, buffers[i], &image_info, allocator,
172                                                                           &chain->buffers[i].image);
173         }
174
175         chain->buffer_count = buffer_count;
176         *swapchain = (VkSwapchainKHR)(uintptr_t)chain;
177         return VK_SUCCESS;
178
179 error_mem_alloc:
180         error = VK_ERROR_OUT_OF_HOST_MEMORY;
181
182 error_get_buffers:
183         tpl_surface_destroy_swapchain(chain->tpl_surface);
184
185 error:
186         if (chain->tpl_display)
187                 tpl_object_unreference((tpl_object_t *)chain->tpl_display);
188
189         if (chain->tpl_surface)
190                 tpl_object_unreference((tpl_object_t *)chain->tpl_surface);
191
192         if (chain->buffers)
193                 vk_free(allocator, chain->buffers);
194
195         vk_free(allocator, chain);
196         *swapchain = VK_NULL_HANDLE;
197         return error;
198 }
199
200 VKAPI_ATTR VkResult VKAPI_CALL
201 vk_CreateSharedSwapchainsKHR(VkDevice                                            device,
202                                                          uint32_t                                                swapchain_count,
203                                                          const VkSwapchainCreateInfoKHR *infos,
204                                                          const VkAllocationCallbacks    *allocator,
205                                                          VkSwapchainKHR                                 *swapchains)
206 {
207         /* TODO: */
208         return VK_SUCCESS;
209 }
210
211 VKAPI_ATTR void VKAPI_CALL
212 vk_DestroySwapchainKHR(VkDevice                                          device,
213                                            VkSwapchainKHR                                swapchain,
214                                            const VkAllocationCallbacks  *allocator)
215 {
216         vk_swapchain_t *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
217
218         tpl_surface_destroy_swapchain(chain->tpl_surface);
219         free(chain->buffers);
220
221         if (chain->tpl_surface)
222                 tpl_object_unreference((tpl_object_t *)chain->tpl_surface);
223
224         if (chain->tpl_display)
225                 tpl_object_unreference((tpl_object_t *)chain->tpl_display);
226
227         vk_free(&chain->allocator, chain);
228 }
229
230 VKAPI_ATTR VkResult VKAPI_CALL
231 vk_GetSwapchainImagesKHR(VkDevice                device,
232                                                  VkSwapchainKHR  swapchain,
233                                                  uint32_t               *image_count,
234                                                  VkImage                *images)
235 {
236         vk_swapchain_t *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
237
238         if (images) {
239                 uint32_t i;
240
241                 *image_count = MIN(*image_count, chain->buffer_count);
242
243                 for (i = 0; i < *image_count; i++)
244                         images[i] = chain->buffers[i].image;
245
246                 if (*image_count < chain->buffer_count)
247                         return VK_INCOMPLETE;
248         } else {
249                 *image_count = chain->buffer_count;
250         }
251
252         return VK_SUCCESS;
253 }
254
255 VKAPI_ATTR VkResult VKAPI_CALL
256 vk_AcquireNextImageKHR(VkDevice                  device,
257                                            VkSwapchainKHR        swapchain,
258                                            uint64_t                      timeout,
259                                            VkSemaphore           semaphore,
260                                            VkFence                       fence,
261                                            uint32_t                     *image_index)
262 {
263         vk_icd_t                *icd = vk_get_icd();
264         uint32_t                 i;
265         tbm_surface_h    next;
266         vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
267         int sync_fd = -1;
268
269         if (icd->acquire_image) {
270                 next = tpl_surface_dequeue_buffer_with_sync(chain->tpl_surface, timeout, &sync_fd);
271
272                 if (next == NULL)
273                         return VK_TIMEOUT;
274         } else {
275                 next = tpl_surface_dequeue_buffer(chain->tpl_surface);
276                 VK_CHECK(next, return VK_ERROR_SURFACE_LOST_KHR, "tpl_surface_dequeue_buffers() failed\n.");
277         }
278
279         for (i = 0; i < chain->buffer_count; i++) {
280                 if (next == chain->buffers[i].tbm) {
281                         *image_index = i;
282                         if (icd->acquire_image)
283                                 icd->acquire_image(device, chain->buffers[i].image, sync_fd, semaphore, fence);
284
285                         /* TODO: We can do optimization here by returning buffer index immediatly despite the
286                          * buffer is not released yet. The fence or semaphore will be signaled when
287                          * wl_buffer.release actually arrives. */
288
289                         return VK_SUCCESS;
290                 }
291         }
292
293         return VK_ERROR_SURFACE_LOST_KHR;
294 }
295
296 VKAPI_ATTR VkResult VKAPI_CALL
297 vk_QueuePresentKHR(VkQueue                                       queue,
298                                    const VkPresentInfoKHR       *info)
299 {
300         vk_icd_t        *icd = vk_get_icd();
301         uint32_t         i;
302
303         for (i = 0; i < info->swapchainCount; i++) {
304                 int sync_fd = -1;
305                 tpl_result_t res;
306                 vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)info->pSwapchains[i];
307
308                 if (icd->queue_signal_release_image)
309                         icd->queue_signal_release_image(queue, info->waitSemaphoreCount, info->pWaitSemaphores,
310                                                                                         chain->buffers[info->pImageIndices[i]].image, &sync_fd);
311
312                 res = tpl_surface_enqueue_buffer_with_damage_and_sync(chain->tpl_surface,
313                                                                                                                           chain->buffers[info->pImageIndices[i]].tbm,
314                                                                                                                           0, NULL, sync_fd);
315
316                 if (info->pResults != NULL)
317                         info->pResults[i] = res == TPL_ERROR_NONE ? VK_SUCCESS : VK_ERROR_DEVICE_LOST;
318         }
319
320         return VK_SUCCESS;
321 }