spec: Add support for VK_KHR_incremental_present
[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 <stdio.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         VkResult (*init)(VkDevice, const VkSwapchainCreateInfoKHR *,
96                                          vk_swapchain_t *, tbm_format);
97         vk_swapchain_t          *chain;
98         VkResult                         error;
99         uint32_t                         i;
100         uint32_t                         cnt_success = 0;
101         tbm_surface_h           *buffers;
102         tbm_format                       format;
103         vk_icd_t                        *icd = vk_get_icd();
104
105         switch(((VkIcdSurfaceBase *)(uintptr_t)info->surface)->platform) {
106 #pragma GCC diagnostic push
107 #pragma GCC diagnostic ignored "-Wswitch"
108                 case VK_ICD_WSI_PLATFORM_TBM_QUEUE:
109 #pragma GCC diagnostic pop
110                 case VK_ICD_WSI_PLATFORM_WAYLAND:
111                         init = swapchain_tpl_init;
112                         break;
113                 case VK_ICD_WSI_PLATFORM_DISPLAY:
114                         init = swapchain_tdm_init;
115                         break;
116                 default:
117                         return VK_ERROR_EXTENSION_NOT_PRESENT;
118         }
119
120         if (allocator == VK_NULL_HANDLE)
121                 allocator = vk_get_allocator(device, allocator);
122
123         chain = vk_alloc(allocator, sizeof(vk_swapchain_t), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
124         VK_CHECK(chain, return VK_ERROR_OUT_OF_HOST_MEMORY, "vk_alloc() failed.\n");
125
126         memset(chain, 0x00, sizeof(vk_swapchain_t));
127
128         chain->allocator = allocator;
129         chain->surface = info->surface;
130         chain->buffers = NULL;
131         chain->oldSwapchain = (vk_swapchain_t *)(uintptr_t)info->oldSwapchain;
132         chain->is_retired = VK_FALSE;
133
134         format = get_tbm_format(info->imageFormat, info->compositeAlpha);
135         VK_CHECK(format, return VK_ERROR_SURFACE_LOST_KHR, "Not supported image format.\n");
136
137         error = init(device, info, chain, format);
138         VK_CHECK(error == VK_SUCCESS, goto done, "swapchain backend init failed.\n");
139
140         error = chain->get_buffers(device, chain, &buffers, &chain->buffer_count);
141         VK_CHECK(error == VK_SUCCESS, goto done, "swapchain backend get buffers failed.\n");
142         VK_CHECK(chain->buffer_count >= info->minImageCount, goto error_mem_alloc,
143                          "Insufficient buffer_count(%d >= %d)\n", chain->buffer_count, info->minImageCount);
144
145         chain->buffers = vk_alloc(allocator, chain->buffer_count * sizeof(vk_buffer_t),
146                                                           VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
147         VK_CHECK(chain->buffers, goto error_mem_alloc, "vk_alloc() failed.\n");
148
149         for (i = 0; i < chain->buffer_count; i++) {
150                 VkImageCreateInfo image_info = {
151                         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
152                         NULL,
153                         0,
154                         VK_IMAGE_TYPE_2D,
155                         info->imageFormat,
156                         { info->imageExtent.width, info->imageExtent.height, 1 },
157                         1, /* mip level. */
158                         info->imageArrayLayers,
159                         VK_SAMPLE_COUNT_1_BIT,
160                         VK_IMAGE_TILING_LINEAR,
161                         info->imageUsage,
162                         info->imageSharingMode,
163                         info->queueFamilyIndexCount,
164                         info->pQueueFamilyIndices,
165                         VK_IMAGE_LAYOUT_UNDEFINED,
166                 };
167
168                 chain->buffers[i].tbm = buffers[i];
169                 error = icd->create_presentable_image(device, chain->buffers[i].tbm, &image_info,
170                                                                                           allocator, &chain->buffers[i].image);
171                 VK_CHECK(error == VK_SUCCESS, goto done, "create_presentable_image failed.\n");
172
173                 cnt_success++;
174         }
175         goto done;
176
177 error_mem_alloc:
178         error = VK_ERROR_OUT_OF_HOST_MEMORY;
179
180 done:
181         if (error != VK_SUCCESS) {
182                 if (cnt_success > 0) {
183                         PFN_vkGetDeviceProcAddr  icd_gdpa = (PFN_vkGetDeviceProcAddr)icd->get_proc_addr(NULL, "vkGetDeviceProcAddr");
184                         if (icd_gdpa != VK_NULL_HANDLE) {
185                                 PFN_vkDestroyImage               destroy_image = (PFN_vkDestroyImage)icd_gdpa(device, "vkDestroyImage");
186                                 if (destroy_image != VK_NULL_HANDLE) {
187                                         for (i = 0; i < cnt_success; i++)
188                                                 destroy_image(device, chain->buffers[i].image, allocator);
189                                 }
190                         }
191                 }
192
193                 if (chain->buffers) {
194                         vk_free(allocator, chain->buffers);
195                         chain->buffers = NULL;
196                 }
197
198                 if (chain->deinit)
199                         chain->deinit(device, chain);
200
201                 if (chain) {
202                         vk_free(allocator, chain);
203                         chain = NULL;
204                 }
205
206                 *swapchain = VK_NULL_HANDLE;
207         } else {
208                 *swapchain = (VkSwapchainKHR)(uintptr_t)chain;
209         }
210
211         return error;
212 }
213
214 VKAPI_ATTR VkResult VKAPI_CALL
215 vk_CreateSharedSwapchainsKHR(VkDevice                                            device,
216                                                          uint32_t                                                swapchain_count,
217                                                          const VkSwapchainCreateInfoKHR *infos,
218                                                          const VkAllocationCallbacks    *allocator,
219                                                          VkSwapchainKHR                                 *swapchains)
220 {
221         /* TODO: */
222         return VK_SUCCESS;
223 }
224
225 VKAPI_ATTR void VKAPI_CALL
226 vk_DestroySwapchainKHR(VkDevice                                          device,
227                                            VkSwapchainKHR                                swapchain,
228                                            const VkAllocationCallbacks  *allocator)
229 {
230         vk_swapchain_t                  *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
231         vk_icd_t                                *icd = vk_get_icd();
232         PFN_vkGetDeviceProcAddr  icd_gdpa = (PFN_vkGetDeviceProcAddr)icd->get_proc_addr(NULL, "vkGetDeviceProcAddr");
233
234         if (chain != VK_NULL_HANDLE) {
235                 if (allocator == VK_NULL_HANDLE) {
236                         if (chain->allocator == VK_NULL_HANDLE)
237                                 allocator = vk_get_allocator(NULL, NULL);
238                         else
239                                 allocator = chain->allocator;
240                 }
241
242                 if (icd_gdpa != VK_NULL_HANDLE) {
243                         PFN_vkDestroyImage               destroy_image = (PFN_vkDestroyImage)icd_gdpa(device, "vkDestroyImage");
244                         if (destroy_image != VK_NULL_HANDLE) {
245                                 uint32_t                 i;
246
247                                 for (i = 0; i < chain->buffer_count; i++)
248                                         destroy_image(device, chain->buffers[i].image, allocator);
249                         }
250                 }
251
252                 chain->deinit(device, chain);
253                 vk_free(allocator, chain->buffers);
254                 vk_free(allocator, chain);
255         }
256 }
257
258 VKAPI_ATTR VkResult VKAPI_CALL
259 vk_GetSwapchainImagesKHR(VkDevice                device,
260                                                  VkSwapchainKHR  swapchain,
261                                                  uint32_t               *image_count,
262                                                  VkImage                *images)
263 {
264         vk_swapchain_t *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
265
266         if (images) {
267                 uint32_t i;
268
269                 *image_count = MIN(*image_count, chain->buffer_count);
270
271                 for (i = 0; i < *image_count; i++)
272                         images[i] = chain->buffers[i].image;
273
274                 if (*image_count < chain->buffer_count)
275                         return VK_INCOMPLETE;
276         } else {
277                 *image_count = chain->buffer_count;
278         }
279
280         return VK_SUCCESS;
281 }
282
283 VKAPI_ATTR VkResult VKAPI_CALL
284 vk_AcquireNextImageKHR(VkDevice                  device,
285                                            VkSwapchainKHR        swapchain,
286                                            uint64_t                      timeout,
287                                            VkSemaphore           semaphore,
288                                            VkFence                       fence,
289                                            uint32_t                     *image_index)
290 {
291         VkResult                 res;
292         vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)swapchain;
293         vk_icd_t                *icd = vk_get_icd();
294         tbm_surface_h    tbm_surface;
295         int                              sync = -1;
296         uint32_t                 i;
297
298         if (icd->acquire_image && fence != VK_NULL_HANDLE)
299                 res = chain->acquire_image(device, chain, timeout, &tbm_surface, &sync);
300         else
301                 res = chain->acquire_image(device, chain, timeout, &tbm_surface, NULL);
302         VK_CHECK(res == VK_SUCCESS, return res, "backend acquire image failed\n.");
303
304         for (i = 0; i < chain->buffer_count; i++) {
305                 if (tbm_surface == chain->buffers[i].tbm) {
306                         *image_index = i;
307                         if (icd->acquire_image)
308                                 icd->acquire_image(device, chain->buffers[i].image, sync, semaphore, fence);
309
310                         /* TODO: We can do optimization here by returning buffer index immediatly despite the
311                          * buffer is not released yet. The fence or semaphore will be signaled when
312                          * wl_buffer.release actually arrives. */
313
314                         return VK_SUCCESS;
315                 }
316         }
317
318         return VK_ERROR_SURFACE_LOST_KHR;
319 }
320
321 VKAPI_ATTR VkResult VKAPI_CALL
322 vk_QueuePresentKHR(VkQueue                                       queue,
323                                    const VkPresentInfoKHR       *info)
324 {
325         uint32_t         i;
326         vk_icd_t        *icd = vk_get_icd();
327         VkResult         res = VK_SUCCESS;
328         VkPresentRegionsKHR *region_info = NULL;
329         const VkPresentRegionKHR *regions = NULL;
330
331         for (i = 0; i < info->swapchainCount; i++) {
332                 int                              sync_fd = -1;
333                 vk_swapchain_t  *chain = (vk_swapchain_t *)(uintptr_t)info->pSwapchains[i];
334
335                 if (icd->queue_signal_release_image)
336                         res = icd->queue_signal_release_image(queue, info->waitSemaphoreCount,
337                                                                                                   info->pWaitSemaphores,
338                                                                                                   chain->buffers[info->pImageIndices[i]].image,
339                                                                                                   &sync_fd);
340                 if (res != VK_SUCCESS)
341                         VK_ERROR("Failed to queue_signal_release_image. res(%d)", res);
342
343
344                 region_info = info->pNext;
345                 if (region_info) {
346                         if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR != region_info->sType || region_info->swapchainCount <= 0) {
347                                 VK_ERROR("issue in using extension (%s)", VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
348                                 res = VK_ERROR_DEVICE_LOST;//TODO return proper error code
349                         }
350
351                         if (VK_SUCCESS == res) {
352                                 regions = region_info->pRegions;
353                         }
354
355                 }
356                 res = chain->present_image(queue, chain,
357                                                                    chain->buffers[info->pImageIndices[i]].tbm, sync_fd, regions ? regions->rectangleCount : 0, regions ? regions->pRectangles : NULL);
358
359                 if (info->pResults != NULL)
360                         info->pResults[i] = res;
361         }
362
363         return res;
364 }