2 * Copyright © 2016 S-Core Corporation
3 * Copyright © 2016-2017 Samsung Electronics co., Ltd. All Rights Reserved.
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:
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
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.
31 typedef struct vk_swapchain_tdm vk_swapchain_tdm_t;
33 struct vk_swapchain_tdm {
34 tdm_display *tdm_display;
35 tdm_output *tdm_output;
37 const tdm_output_mode *tdm_mode;
38 tdm_output_dpms tdm_dpms;
40 tbm_surface_queue_h tbm_queue;
42 VkPresentModeKHR present_mode;
43 tbm_surface_h *buffers;
44 tbm_surface_h front_buffer;
45 pthread_mutex_t front_mutex;
46 pthread_mutex_t free_queue_mutex;
47 pthread_cond_t free_queue_cond;
50 static int swapchain_tdm_timeline_key;
51 static int swapchain_tdm_timestamp_key;
54 swapchain_tdm_increase_timestamp(tbm_surface_h tbm_surface)
57 if (tbm_surface_internal_get_user_data(tbm_surface,
58 (unsigned long)&swapchain_tdm_timeline_key,
59 (void **)(&timeline))) {
61 if (tbm_sync_timeline_inc(timeline, 1) == 0) {
63 strerror_r(errno, buf, sizeof(buf));
64 VK_ERROR("Failed to increase TBM sync timeline: %d(%s)", errno, buf);
71 swapchain_tdm_output_commit_cb(tdm_output *output, unsigned int sequence,
72 unsigned int tv_sec, unsigned int tv_usec,
75 vk_swapchain_t *chain = user_data;
76 vk_swapchain_tdm_t *swapchain_tdm = chain->backend_data;
78 if (pthread_mutex_lock(&swapchain_tdm->front_mutex))
79 VK_ERROR("pthread_mutex_lock front buffer failed\n");
81 if (swapchain_tdm->front_buffer) {
82 swapchain_tdm_increase_timestamp(swapchain_tdm->front_buffer);
83 swapchain_tdm->front_buffer = NULL;
85 pthread_mutex_unlock(&swapchain_tdm->front_mutex);
89 swapchain_tdm_queue_present_image(VkQueue queue,
90 vk_swapchain_t *chain,
91 tbm_surface_h tbm_surface,
94 const VkRectLayerKHR *rects)
96 tbm_surface_queue_error_e tsq_err;
98 vk_swapchain_tdm_t *swapchain_tdm = chain->backend_data;
101 if (tbm_sync_fence_wait(sync_fd, -1) != 1) {
103 strerror_r(errno, buf, sizeof(buf));
104 VK_ERROR("Failed to wait sync. | error: %d(%s)", errno, buf);
109 tsq_err = tbm_surface_queue_enqueue(swapchain_tdm->tbm_queue, tbm_surface);
110 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
111 "tbm_surface_queue_enqueue failed.\n");
113 tsq_err = tbm_surface_queue_acquire(swapchain_tdm->tbm_queue, &tbm_surface);
114 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
115 "tbm_surface_queue_acquire failed.\n");
117 tdm_err = tdm_layer_set_buffer(swapchain_tdm->tdm_layer, tbm_surface);
118 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
119 "tdm_layer_set_buffer failed.\n");
121 tdm_err = tdm_output_commit(swapchain_tdm->tdm_output, 0,
122 swapchain_tdm_output_commit_cb, chain);
123 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
124 "tdm_output_commit failed.\n");
126 tdm_err = tdm_display_handle_events(swapchain_tdm->tdm_display);
127 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
128 "tdm_display_handle_events failed.\n");
130 if (pthread_mutex_lock(&swapchain_tdm->free_queue_mutex))
131 VK_ERROR("pthread_mutex_lock free queue failed\n");
133 tsq_err = tbm_surface_queue_release(swapchain_tdm->tbm_queue, tbm_surface);
134 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
135 "tbm_surface_queue_release failed.\n");
137 pthread_mutex_unlock(&swapchain_tdm->free_queue_mutex);
138 pthread_cond_signal(&swapchain_tdm->free_queue_cond);
140 if (pthread_mutex_lock(&swapchain_tdm->front_mutex))
141 VK_ERROR("pthread_mutex_lock front buffer failed\n");
142 if (swapchain_tdm->front_buffer)
143 swapchain_tdm_increase_timestamp(swapchain_tdm->front_buffer);
144 swapchain_tdm->front_buffer = tbm_surface;
145 pthread_mutex_unlock(&swapchain_tdm->front_mutex);
151 swapchain_tdm_timeline_destroy_cb(void *user_data)
153 if (((tbm_fd)user_data) != -1)
154 close((tbm_fd)user_data);
158 swapchain_tdm_get_sync_fence(tbm_surface_h tbm_surface)
164 if (tbm_surface_internal_get_user_data(tbm_surface,
165 (unsigned long)&swapchain_tdm_timeline_key,
166 (void **)(&timeline))) {
169 tbm_surface_internal_get_user_data(tbm_surface,
170 (unsigned long)&swapchain_tdm_timestamp_key,
171 (void **)(×tamp));
173 tbm_surface_internal_set_user_data(tbm_surface,
174 (unsigned long)&swapchain_tdm_timestamp_key,
177 snprintf(name, 32, "%d",
178 tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
179 fence = tbm_sync_fence_create(timeline,
184 strerror_r(errno, buf, sizeof(buf));
185 VK_ERROR("Failed to create TBM sync fence: %d(%s)", errno, buf);
188 /* make timeline and timestamp */
189 timeline = tbm_sync_timeline_create();
190 tbm_surface_internal_add_user_data(tbm_surface,
191 (unsigned long)&swapchain_tdm_timeline_key,
192 swapchain_tdm_timeline_destroy_cb);
193 tbm_surface_internal_set_user_data(tbm_surface,
194 (unsigned long)&swapchain_tdm_timeline_key,
196 if (timeline == -1) {
198 strerror_r(errno, buf, sizeof(buf));
199 VK_ERROR("Failed to create TBM sync timeline: %d(%s)", errno, buf);
201 tbm_surface_internal_set_user_data(tbm_surface,
202 (unsigned long)&swapchain_tdm_timestamp_key,
210 swapchain_tdm_acquire_next_image(VkDevice device,
211 vk_swapchain_t *chain,
213 tbm_surface_h *tbm_surface,
216 tbm_surface_queue_error_e tsq_err;
217 vk_swapchain_tdm_t *swapchain_tdm = chain->backend_data;
218 struct timespec abs_time;
220 if (timeout != UINT64_MAX) {
221 clock_gettime(CLOCK_REALTIME, &abs_time);
222 abs_time.tv_sec += (timeout / 1000000000L);
223 abs_time.tv_nsec += (timeout % 1000000000L);
224 if (abs_time.tv_nsec >= 1000000000L) {
225 abs_time.tv_sec += (abs_time.tv_nsec / 1000000000L);
226 abs_time.tv_nsec = (abs_time.tv_nsec % 1000000000L);
230 if (pthread_mutex_lock(&swapchain_tdm->free_queue_mutex))
231 VK_ERROR("pthread_mutex_lock free queue failed\n");
233 while (tbm_surface_queue_can_dequeue(swapchain_tdm->tbm_queue, 0) == 0) {
234 if (timeout != UINT64_MAX) {
236 ret = pthread_cond_timedwait(&swapchain_tdm->free_queue_cond,
237 &swapchain_tdm->free_queue_mutex,
239 if (ret == ETIMEDOUT) {
241 pthread_mutex_unlock(&swapchain_tdm->free_queue_mutex);
245 pthread_cond_wait(&swapchain_tdm->free_queue_cond,
246 &swapchain_tdm->free_queue_mutex);
250 tsq_err = tbm_surface_queue_dequeue(swapchain_tdm->tbm_queue, tbm_surface);
251 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
252 "tbm_surface_queue_dequeue failed.\n");
253 pthread_mutex_unlock(&swapchain_tdm->free_queue_mutex);
256 *sync = swapchain_tdm_get_sync_fence(*tbm_surface);
262 swapchain_tdm_deinit(VkDevice device,
263 vk_swapchain_t *chain)
265 vk_swapchain_tdm_t *swapchain_tdm = chain->backend_data;
268 tdm_output_set_dpms(swapchain_tdm->tdm_output, swapchain_tdm->tdm_dpms);
270 pthread_cond_destroy(&swapchain_tdm->free_queue_cond);
271 pthread_mutex_destroy(&swapchain_tdm->free_queue_mutex);
272 pthread_mutex_destroy(&swapchain_tdm->front_mutex);
274 if (swapchain_tdm->tbm_queue)
275 tbm_surface_queue_destroy(swapchain_tdm->tbm_queue);
277 if (swapchain_tdm->buffers)
278 vk_free(chain->allocator, swapchain_tdm->buffers);
279 vk_free(chain->allocator, swapchain_tdm);
284 swapchain_tdm_get_buffers(VkDevice device,
285 vk_swapchain_t *chain,
286 tbm_surface_h **buffers,
287 uint32_t *buffer_count)
290 tbm_surface_queue_error_e tsq_err;
292 tbm_surface_info_s surf_info;
293 tdm_info_layer tdm_info;
294 vk_swapchain_tdm_t *swapchain_tdm = chain->backend_data;
296 *buffer_count = tbm_surface_queue_get_size(swapchain_tdm->tbm_queue);
297 swapchain_tdm->buffers = vk_alloc(chain->allocator,
298 sizeof(tbm_surface_h) * *buffer_count,
299 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
300 VK_CHECK(swapchain_tdm->buffers, return VK_ERROR_OUT_OF_HOST_MEMORY, "vk_alloc() failed.\n");
302 for (i = 0; i < *buffer_count; i++) {
303 tsq_err = tbm_surface_queue_dequeue(swapchain_tdm->tbm_queue,
304 &swapchain_tdm->buffers[i]);
305 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE,
306 return VK_ERROR_SURFACE_LOST_KHR,
307 "tbm_surface_queue_dequeue failed.\n");
310 for (i = 0; i < *buffer_count; i++) {
311 tsq_err = tbm_surface_queue_release(swapchain_tdm->tbm_queue,
312 swapchain_tdm->buffers[i]);
313 VK_CHECK(tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE,
314 return VK_ERROR_SURFACE_LOST_KHR,
315 "tbm_surface_queue_enqueue failed.\n");
318 *buffers = swapchain_tdm->buffers;
320 tdm_err = tdm_output_get_dpms(swapchain_tdm->tdm_output, &swapchain_tdm->tdm_dpms);
321 tdm_err = tdm_output_set_dpms(swapchain_tdm->tdm_output, TDM_OUTPUT_DPMS_ON);
322 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
323 "tdm_output_set_dpms failed.\n");
325 tdm_err = tdm_output_set_mode(swapchain_tdm->tdm_output,
326 swapchain_tdm->tdm_mode);
327 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
328 "tdm_output_set_mode failed.\n");
330 tbm_surface_get_info((*buffers)[0], &surf_info);
332 /* from enlightenment */
333 tdm_info.src_config.size.h = surf_info.planes[0].stride;
334 tdm_info.src_config.size.v = surf_info.height;
336 tdm_info.src_config.pos.x = 0;
337 tdm_info.src_config.pos.y = 0;
338 tdm_info.src_config.pos.w = surf_info.width;
339 tdm_info.src_config.pos.h = surf_info.height;
341 tdm_info.src_config.format = surf_info.format;
343 tdm_info.dst_pos.x = 0;
344 tdm_info.dst_pos.y = 0;
345 tdm_info.dst_pos.w = surf_info.width;
346 tdm_info.dst_pos.h = surf_info.height;
348 tdm_info.transform = TDM_TRANSFORM_NORMAL;
350 tdm_err = tdm_layer_set_info(swapchain_tdm->tdm_layer, &tdm_info);
351 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
352 "tdm_layer_set_info failed.\n");
354 /* tdm_err = tdm_layer_set_buffer_queue(swapchain_tdm->tdm_layer,
355 swapchain_tdm->tbm_queue);
356 VK_CHECK(tdm_err == TDM_ERROR_NONE, return VK_ERROR_SURFACE_LOST_KHR,
357 "tdm_layer_set_buffer_queue failed.\n");*/
363 swapchain_tdm_init(VkDevice device,
364 const VkSwapchainCreateInfoKHR *info,
365 vk_swapchain_t *chain,
368 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *)(uintptr_t)info->surface;
369 vk_display_mode_t *disp_mode = (vk_display_mode_t *)(uintptr_t)surface->displayMode;
370 vk_display_t *disp = disp_mode->display;
371 vk_swapchain_tdm_t *swapchain_tdm;
373 swapchain_tdm = vk_alloc(chain->allocator, sizeof(vk_swapchain_tdm_t),
374 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
375 VK_CHECK(swapchain_tdm, return VK_ERROR_OUT_OF_HOST_MEMORY, "vk_alloc() failed.\n");
377 memset(swapchain_tdm, 0x00, sizeof(*swapchain_tdm));
378 chain->backend_data = swapchain_tdm;
380 swapchain_tdm->tdm_display = disp->pdev->tdm_display;
381 swapchain_tdm->tdm_output = disp->tdm_output;
382 swapchain_tdm->tdm_layer = disp->pdev->planes[surface->planeIndex].tdm_layer;
384 swapchain_tdm->tbm_queue =
385 /* tbm_surface_queue_sequence_create(info->minImageCount,
386 info->imageExtent.width,
387 info->imageExtent.height,
388 format, TBM_BO_SCANOUT);*/
389 tbm_surface_queue_create(info->minImageCount,
390 info->imageExtent.width,
391 info->imageExtent.height,
392 format, TBM_BO_SCANOUT);
394 VK_CHECK(swapchain_tdm->tbm_queue, return VK_ERROR_SURFACE_LOST_KHR,
395 "tbm_surface_queue_create failed.\n");
397 if (pthread_mutex_init(&swapchain_tdm->front_mutex, NULL))
398 VK_ERROR("pthread_mutex_init front buffer failed\n");
399 if (pthread_mutex_init(&swapchain_tdm->free_queue_mutex, NULL))
400 VK_ERROR("pthread_mutex_init free queue failed\n");
401 if (pthread_cond_init(&swapchain_tdm->free_queue_cond, NULL))
402 VK_ERROR("pthread_cond_init free queue failed\n");
404 swapchain_tdm->present_mode = info->presentMode;
405 swapchain_tdm->tdm_mode = disp_mode->tdm_mode;
406 swapchain_tdm->tdm_dpms = TDM_OUTPUT_DPMS_OFF;
408 chain->get_buffers = swapchain_tdm_get_buffers;
409 chain->deinit = swapchain_tdm_deinit;
410 chain->acquire_image = swapchain_tdm_acquire_next_image;
411 chain->present_image = swapchain_tdm_queue_present_image;