spec: Add support for VK_KHR_incremental_present
[platform/core/uifw/vulkan-wsi-tizen.git] / src / wsi / swapchain_tpl.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
27 #include <string.h>
28 #include <unistd.h>
29
30 typedef struct vk_swapchain_tpl vk_swapchain_tpl_t;
31
32 struct vk_swapchain_tpl {
33         tpl_display_t                   *tpl_display;
34         tpl_surface_t                   *tpl_surface;
35         tbm_surface_h                   *buffers;
36 };
37
38 struct swap_region
39 {
40         int num_rects;
41         int *rects;
42 };
43 static VkResult
44 swapchain_tpl_queue_present_image(VkQueue                                        queue,
45                                                                   vk_swapchain_t                        *chain,
46                                                                   tbm_surface_h                          tbm_surface,
47                                                                   int                                            sync_fd,
48                                                                   int num_rects,
49                                                                   const VkRectLayerKHR *rects)
50 {
51         tpl_result_t             res;
52         vk_swapchain_tpl_t      *swapchain_tpl = chain->backend_data;
53         struct swap_region *region = NULL;
54
55         if (chain->is_retired == VK_TRUE) {
56                 res = tpl_surface_cancel_dequeued_buffer(swapchain_tpl->tpl_surface, tbm_surface);
57                 if (res != TPL_ERROR_NONE)
58                         VK_ERROR("failed to cancel_dequeued_buffer. tpl_surface(%p) tbm_surface(%p)\n",
59                                          swapchain_tpl->tpl_surface, tbm_surface);
60                 close(sync_fd);
61                 return VK_ERROR_OUT_OF_DATE_KHR;
62         }
63
64         if (num_rects >= 1) {
65                 region = (struct swap_region *)malloc(sizeof(struct swap_region));
66                 if (!region)
67                 {
68                         VK_ERROR("Failed to allocate swap_region");
69                         return VK_ERROR_DEVICE_LOST;
70                 }
71
72                 region->num_rects = num_rects;
73
74                 region->rects = (int *)malloc(sizeof(int) * 4 * num_rects);
75                 if (!region->rects)
76                 {
77                         VK_ERROR("Failed to allocate swap_region->rects.");
78                         free(region);
79                         return VK_ERROR_DEVICE_LOST;
80                 }
81
82                 for (int i = 0; i < num_rects; i++) {
83                         VkRectLayerKHR *pRects = &rects[i];
84                         //copy first 4 ints from VkRectLayerKHR
85                         memcpy((char *)region->rects + sizeof(int)*4*i, (char *)pRects, sizeof(int) * 4);
86                 }
87
88         }
89         res = tpl_surface_enqueue_buffer_with_damage_and_sync(swapchain_tpl->tpl_surface,
90                                                                                                                   tbm_surface, region ? region->num_rects : 0, region ? region->rects : NULL, sync_fd);
91         if (res == TPL_ERROR_NONE && chain->oldSwapchain != VK_NULL_HANDLE) {
92                 chain->oldSwapchain->is_retired = VK_TRUE;
93                 chain->oldSwapchain = VK_NULL_HANDLE;
94         }
95
96         if (region) {
97                 if (region->rects) free(region->rects);
98
99                 free(region);
100         }
101         return res == TPL_ERROR_NONE ? VK_SUCCESS : VK_ERROR_DEVICE_LOST;
102 }
103
104 static VkResult
105 swapchain_tpl_acquire_next_image(VkDevice                        device,
106                                                                  vk_swapchain_t         *chain,
107                                                                  uint64_t                        timeout,
108                                                                  tbm_surface_h          *tbm_surface,
109                                                                  int                            *sync)
110 {
111         vk_swapchain_tpl_t      *swapchain_tpl = chain->backend_data;
112
113         *tbm_surface = tpl_surface_dequeue_buffer_with_sync(swapchain_tpl->tpl_surface,
114                                                                                                                 timeout, sync);
115
116         if (*tbm_surface == NULL && !tpl_surface_validate(swapchain_tpl->tpl_surface)) {
117                 /* Returning VK_ERROR_OUT_OF_DATE_KHR calls swapchain_tpl_deinit
118                  * to destroy the existing swapchain, but does not want the existing
119                  * tpl_surface and tpl_display to be destroyed. */
120                 tpl_object_reference((tpl_object_t *)swapchain_tpl->tpl_display);
121                 tpl_object_reference((tpl_object_t *)swapchain_tpl->tpl_surface);
122                 return VK_ERROR_OUT_OF_DATE_KHR;
123         }
124
125         if (*tbm_surface == NULL) {
126                 if (timeout == 0)
127                         return VK_NOT_READY;
128                 else if (timeout != UINT64_MAX)
129                         return VK_TIMEOUT;
130                 else
131                         return VK_ERROR_SURFACE_LOST_KHR;
132         }
133
134         return VK_SUCCESS;
135 }
136
137 static void
138 swapchain_tpl_deinit(VkDevice            device,
139                                          vk_swapchain_t *chain)
140 {
141         vk_swapchain_tpl_t      *swapchain_tpl = chain->backend_data;
142
143         if (swapchain_tpl) {
144                 tpl_surface_destroy_swapchain(swapchain_tpl->tpl_surface);
145
146                 if (swapchain_tpl->tpl_surface)
147                         tpl_object_unreference((tpl_object_t *)swapchain_tpl->tpl_surface);
148
149                 if (swapchain_tpl->tpl_display)
150                         tpl_object_unreference((tpl_object_t *)swapchain_tpl->tpl_display);
151
152                 if (swapchain_tpl->buffers)
153                         free(swapchain_tpl->buffers);
154                 vk_free(chain->allocator, swapchain_tpl);
155         }
156 }
157
158 static VkResult
159 swapchain_tpl_get_buffers(VkDevice                       device,
160                                                   vk_swapchain_t        *chain,
161                                                   tbm_surface_h    **buffers,
162                                                   uint32_t                      *buffer_count)
163 {
164         tpl_result_t             res;
165         int                                      buffer_cnt;
166         VkResult                         error = VK_SUCCESS;
167         vk_swapchain_tpl_t      *swapchain_tpl = chain->backend_data;
168
169         /* Initialize swapchain buffers. */
170         res = tpl_surface_get_swapchain_buffers(swapchain_tpl->tpl_surface,
171                                                                                         &swapchain_tpl->buffers, &buffer_cnt);
172         VK_CHECK(res == TPL_ERROR_NONE, goto done, "tpl_surface_get_swapchain_buffers() failed.\n");
173
174         *buffers = swapchain_tpl->buffers;
175         *buffer_count = buffer_cnt;
176
177 done:
178         if (res == TPL_ERROR_OUT_OF_MEMORY)
179                 error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
180         else if (res != TPL_ERROR_NONE)
181                 error = VK_ERROR_SURFACE_LOST_KHR;
182
183         return error;
184 }
185
186 VkResult
187 swapchain_tpl_init(VkDevice                                                      device,
188                                    const VkSwapchainCreateInfoKHR       *info,
189                                    vk_swapchain_t                                       *chain,
190                                    tbm_format                                            format)
191 {
192         tpl_result_t             res;
193         VkIcdSurfaceBase        *surface = (VkIcdSurfaceBase *)(uintptr_t)info->surface;
194         vk_swapchain_tpl_t      *swapchain_tpl;
195         tpl_handle_t             native_window;
196         int                                      tpl_present_mode;
197         vk_bool_t                        need_to_create = VK_TRUE;
198
199         VkResult error = VK_ERROR_DEVICE_LOST;
200
201         swapchain_tpl = vk_alloc(chain->allocator, sizeof(vk_swapchain_tpl_t),
202                                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
203         VK_CHECK(swapchain_tpl, goto error, "vk_alloc() failed.\n");
204         memset(swapchain_tpl, 0x00, sizeof(*swapchain_tpl));
205         chain->backend_data = swapchain_tpl;
206
207         /* Don't check NULL for display and window. There might be default ones for some systems. */
208
209         swapchain_tpl->tpl_display = vk_get_tpl_display(surface);
210         VK_CHECK(swapchain_tpl->tpl_display, goto error, "vk_get_tpl_display() failed.\n");
211         native_window = vk_get_tpl_native_window(surface);
212
213         swapchain_tpl->tpl_surface = tpl_surface_get(swapchain_tpl->tpl_display,
214                                                                                                  native_window);
215         if (swapchain_tpl->tpl_surface) {
216                 if (chain->oldSwapchain != VK_NULL_HANDLE) {
217                         vk_swapchain_tpl_t *oldSwapchain_tpl =
218                                 (vk_swapchain_tpl_t *)chain->oldSwapchain->backend_data;
219                         if (tpl_surface_validate(oldSwapchain_tpl->tpl_surface))
220                                 need_to_create = VK_TRUE;
221                         else
222                                 need_to_create = VK_FALSE;
223                 } else {
224                         need_to_create = VK_FALSE;
225                 }
226         }
227
228         if (need_to_create)
229                 swapchain_tpl->tpl_surface = tpl_surface_create(swapchain_tpl->tpl_display,
230                                                                                                                 native_window,
231                                                                                                                 TPL_SURFACE_TYPE_WINDOW, format);
232         else
233                 tpl_object_reference((tpl_object_t *)swapchain_tpl->tpl_surface);
234
235
236         VK_CHECK(swapchain_tpl->tpl_surface, goto error, "tpl_surface_create() failed.\n");
237
238         switch(info->presentMode) {
239                 case VK_PRESENT_MODE_IMMEDIATE_KHR:
240                         tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_IMMEDIATE;
241                         break;
242                 case VK_PRESENT_MODE_MAILBOX_KHR:
243                         tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_MAILBOX;
244                         break;
245                 case VK_PRESENT_MODE_FIFO_KHR:
246                         tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO;
247                         break;
248                 case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
249                         tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED;
250                         break;
251                 default:
252                         VK_DEBUG("Unsupported present mode: 0x%x\n", info->presentMode);
253                         goto error;
254         }
255
256         res = tpl_surface_create_swapchain(swapchain_tpl->tpl_surface, format,
257                                                                            info->imageExtent.width, info->imageExtent.height,
258                                                                            info->minImageCount, tpl_present_mode);
259         if (res == TPL_ERROR_OUT_OF_MEMORY) {
260                 error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
261                 VK_ERROR("tpl_surface_create_swapchain() failed.\n");
262                 goto error;
263         }
264         VK_CHECK(res == TPL_ERROR_NONE, goto error, "tpl_surface_create_swapchain() failed.\n");
265
266         chain->get_buffers = swapchain_tpl_get_buffers;
267         chain->deinit = swapchain_tpl_deinit;
268         chain->acquire_image = swapchain_tpl_acquire_next_image;
269         chain->present_image = swapchain_tpl_queue_present_image;
270
271         return VK_SUCCESS;
272
273 error:
274         if (swapchain_tpl) {
275                 if (swapchain_tpl->tpl_display)
276                         tpl_object_unreference((tpl_object_t *)swapchain_tpl->tpl_display);
277
278                 if (swapchain_tpl->tpl_surface)
279                         tpl_object_unreference((tpl_object_t *)swapchain_tpl->tpl_surface);
280
281                 vk_free(chain->allocator, swapchain_tpl);
282         } else {
283                 error = VK_ERROR_OUT_OF_HOST_MEMORY;
284         }
285
286         return error;
287 }