2 Copyright (C) 2015 Samsung Electronics co., Ltd. All Rights Reserved.
5 SooChan Lim <sc1.lim@samsung.com>,
6 Sangjin Lee <lsj119@samsung.com>,
7 Boram Park <boram1288.park@samsung.com>,
8 Changyeon Lee <cyeon.lee@samsung.com>
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the "Software"),
12 to deal in the Software without restriction, including without limitation
13 the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 and/or sell copies of the Software, and to permit persons to whom the
15 Software is furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice (including the next
18 paragraph) shall be included in all copies or substantial portions of the
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
39 #include <tbm_surface.h>
40 #include <tbm_surface_queue.h>
41 #include <tbm_surface_internal.h>
44 #include "wayland-tbm-client.h"
45 #include "wayland-tbm-client-protocol.h"
46 #include "wayland-tbm-int.h"
48 struct wayland_tbm_client {
49 struct wl_display *dpy;
50 struct wl_tbm *wl_tbm;
54 struct wl_list queue_info_list;
56 struct wl_event_queue *event_queue;
59 struct wayland_tbm_buffer {
60 struct wl_buffer *wl_buffer;
61 tbm_surface_h tbm_surface;
67 struct wl_tbm_queue *wl_tbm_queue;
71 struct wayland_tbm_surface_queue {
72 struct wl_tbm_queue *wl_tbm_queue;
81 struct wl_surface *wl_surface;
86 struct wl_list attach_bufs;
88 tbm_surface_queue_h tbm_queue;
90 struct wl_tbm *wl_tbm;
94 static struct wl_tbm_monitor *tbm_monitor;
98 #define WL_TBM_TRACE(fmt, ...) if (bTrace) WL_TBM_C_LOG(fmt, ##__VA_ARGS__)
100 #define WL_TBM_TRACE(fmt, ...)
103 struct wayland_tbm_buffer *
104 _wayland_tbm_client_find_tbm_buffer_wl_buffer(struct wayland_tbm_client *tbm_client,
105 struct wl_buffer *wl_buffer);
108 _wayland_tbm_client_create_surface_from_param(tbm_bufmgr bufmgr,
116 struct wl_array *plane_buf_idx,
117 struct wl_array *plane_offset,
118 struct wl_array *plane_stride,
119 struct wl_array *plane_size,
127 handle_tbm_buffer_import_with_id(void *data,
128 struct wl_tbm *wl_tbm,
129 struct wl_buffer *wl_buffer,
136 struct wl_array *plane_buf_idx,
137 struct wl_array *plane_offset,
138 struct wl_array *plane_stride,
139 struct wl_array *plane_size,
146 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
147 tbm_surface_h tbm_surface;
148 char debug_id[64] = {0, };
150 tbm_surface = _wayland_tbm_client_create_surface_from_param(tbm_client->bufmgr, 0,
151 width, height, format, bpp, size,
153 plane_buf_idx, plane_offset, plane_stride, plane_size,
157 WL_TBM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
158 wl_buffer_set_user_data(wl_buffer, tbm_surface);
160 snprintf(debug_id, sizeof(debug_id), "%u", (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
161 tbm_surface_internal_set_debug_data(tbm_surface, "id", debug_id);
164 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), wl_buffer, tbm_surface);
171 wl_buffer_destroy(wl_buffer);
175 handle_tbm_buffer_import_with_fd(void *data,
176 struct wl_tbm *wl_tbm,
177 struct wl_buffer *wl_buffer,
184 struct wl_array *plane_buf_idx,
185 struct wl_array *plane_offset,
186 struct wl_array *plane_stride,
187 struct wl_array *plane_size,
194 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
195 tbm_surface_h tbm_surface;
196 char debug_id[64] = {0, };
198 tbm_surface = _wayland_tbm_client_create_surface_from_param(tbm_client->bufmgr, 1,
199 width, height, format, bpp, size,
201 plane_buf_idx, plane_offset, plane_stride, plane_size,
205 WL_TBM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
207 wl_buffer_set_user_data(wl_buffer, tbm_surface);
209 snprintf(debug_id, sizeof(debug_id), "%u", (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
210 tbm_surface_internal_set_debug_data(tbm_surface, "id", debug_id);
213 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), wl_buffer, tbm_surface);
220 wl_buffer_destroy(wl_buffer);
224 handle_buffer_destroy(void *data,
225 struct wl_tbm *wl_tbm,
226 struct wl_buffer *wl_buffer)
228 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
229 tbm_surface_h tbm_surface;
230 struct wayland_tbm_buffer *buffer = NULL;
233 WL_TBM_TRACE(" pid:%d wl_buffer:%p", getpid(), wl_buffer);
236 buffer = _wayland_tbm_client_find_tbm_buffer_wl_buffer(tbm_client, wl_buffer);
238 buffer->wl_buffer = NULL;
240 tbm_surface = wl_buffer_get_user_data(wl_buffer);
242 tbm_surface_internal_unref(tbm_surface);
244 wl_buffer_set_user_data(wl_buffer, NULL);
245 wl_buffer_destroy(wl_buffer);
250 static const struct wl_tbm_listener wl_tbm_client_listener = {
251 handle_tbm_buffer_import_with_id,
252 handle_tbm_buffer_import_with_fd,
253 handle_buffer_destroy,
256 void _waylend_tbm_monitor_client_print_show_to_file(char* show_str)
262 snprintf(tmp_file, sizeof(tmp_file), "/tmp/tbm_debug_show_%d%d", getpid(), c++);
263 if ((f = fopen(tmp_file, "a+")) != NULL) {
264 fprintf(f, "%s", show_str);
269 void _waylend_tbm_monitor_client_show(int argc, char *argv[],
270 char *reply, int *len, struct wayland_tbm_client *tbm_client)
272 struct wayland_tbm_monitor_path path = {0};
275 _wayland_tbm_util_show_path_parse(argv[2], 0, &path);
278 tbm_bufmgr_debug_show(tbm_client->bufmgr);
280 /* we have to save result to some file as reply can be very long */
281 show_str = tbm_bufmgr_debug_tbm_info_get(tbm_client->bufmgr);
283 _waylend_tbm_monitor_client_print_show_to_file(show_str);
288 /* send empty string to close the session */
289 WL_TBM_MONITOR_SNPRINTF(reply, *len, "\n");
292 void _waylend_tbm_monitor_client_dump_snapshot(int argc, char *argv[],
293 char *reply, int *len, struct wayland_tbm_client *tbm_client)
298 for (i = 1; i < argc; i++) {
299 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
303 _waylend_tbm_util_dump_snapshot(tbm_client->bufmgr, scale);
304 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): snapshot dump is done\n", getpid());
307 void _waylend_tbm_monitor_client_dump_queue(int argc, char *argv[],
308 char *reply, int *len, struct wayland_tbm_client *tbm_client)
314 st = _waylend_tbm_util_proc_state_parse(argv[1]);
316 for (i = 2; i < argc; i++) {
317 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
321 st = _waylend_tbm_util_dump_queue(st, tbm_client->bufmgr, scale);
322 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): queue dump state: %s\n", getpid(),
326 void _waylend_tbm_monitor_client_trace(int argc, char *argv[],
327 char *reply, int *len, struct wayland_tbm_client *tbm_client)
331 st = _waylend_tbm_util_trace(_waylend_tbm_util_proc_state_parse(argv[1]), tbm_client->bufmgr);
332 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): trace state: %s\n", getpid() ,
338 void (*func)(int argc, char *argv[], char *reply, int *len, struct wayland_tbm_client *tbm_client);
342 _waylend_tbm_monitor_client_show,
346 _waylend_tbm_monitor_client_dump_snapshot,
350 _waylend_tbm_monitor_client_dump_queue,
354 _waylend_tbm_monitor_client_trace,
359 handle_tbm_monitor_client_done(void *data, struct wl_tbm_monitor *wl_tbm_monitor, const char *message)
364 handle_tbm_monitor_client_request_to_client(void *data, struct wl_tbm_monitor *wl_tbm_monitor,
365 const char * options, const char * request_id)
367 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
369 char *argv[WL_TBM_MONITOR_ARGS_MAX] = {0};
372 char message[WL_TBM_MONITOR_REPLY_MSG_LEN] = {0,};
373 int len = sizeof(message);
374 char *reply = message;
379 snprintf(temp, sizeof(temp), "%s", options);
381 argv[argc] = strtok_r(temp, " ", &end);
384 if (argc == WL_TBM_MONITOR_ARGS_MAX)
386 argv[argc] = strtok_r(NULL, " ", &end);
390 WL_TBM_TRACE("receive request_id:%s argc:%d [%s %s] options:'%s'", request_id, argc, argv[0], argv[1], temp);
394 for (i = 0; i < sizeof(option_proc) / sizeof(option_proc[0]); i++) {
395 if (argv[0][0] == '-' && !strncmp(argv[0] + 1, option_proc[i].opt, 32)) {
396 if (option_proc[i].func) {
397 option_proc[i].func(argc, argv, reply, &len, tbm_client);
404 wl_tbm_monitor_responce_to_server(tbm_monitor, message, request_id);
407 static const struct wl_tbm_monitor_listener wl_tbm_monitor_listener = {
408 handle_tbm_monitor_client_done,
409 handle_tbm_monitor_client_request_to_client,
413 _wayland_tbm_client_registry_handle_global(void *data,
414 struct wl_registry *registry, uint32_t name,
415 const char *interface, uint32_t version)
417 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
419 if (!strcmp(interface, "wl_tbm")) {
420 tbm_client->wl_tbm = wl_registry_bind(registry, name, &wl_tbm_interface,
422 WL_TBM_RETURN_IF_FAIL(tbm_client->wl_tbm != NULL);
424 wl_tbm_add_listener(tbm_client->wl_tbm, &wl_tbm_client_listener, tbm_client);
426 if (!tbm_client->bufmgr) {
427 tbm_client->bufmgr = tbm_bufmgr_init(-1);
428 if (!tbm_client->bufmgr) {
429 WL_TBM_LOG("failed to get auth_info");
430 wl_tbm_destroy(tbm_client->wl_tbm);
431 tbm_client->wl_tbm = NULL;
435 } else if (!strcmp(interface, "wl_tbm_monitor")) {
436 /*Create wl_monotor proxy by sington*/
440 tbm_monitor = wl_registry_bind(registry, name, &wl_tbm_monitor_interface, version);
441 WL_TBM_RETURN_IF_FAIL(tbm_monitor != NULL);
443 wl_proxy_set_queue((struct wl_proxy *)tbm_monitor, NULL);
445 wl_tbm_monitor_add_listener(tbm_monitor, &wl_tbm_monitor_listener, tbm_client);
449 static const struct wl_registry_listener registry_listener = {
450 _wayland_tbm_client_registry_handle_global,
455 wayland_tbm_client_set_event_queue(struct wayland_tbm_client *tbm_client, struct wl_event_queue *queue)
457 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
459 wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, queue);
460 tbm_client->event_queue = queue;
465 struct wayland_tbm_client *
466 wayland_tbm_client_init(struct wl_display *display)
468 WL_TBM_RETURN_VAL_IF_FAIL(display != NULL, NULL);
470 struct wl_display *display_wrapper;
471 struct wayland_tbm_client *tbm_client;
472 struct wl_event_queue *wl_queue;
473 struct wl_registry *wl_registry;
475 _wayland_tbm_check_dlog_enable();
479 tbm_client = calloc(1, sizeof(struct wayland_tbm_client));
480 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
482 tbm_client->dpy = display;
484 display_wrapper = wl_proxy_create_wrapper(display);
485 if (!display_wrapper) {
486 WL_TBM_LOG("Failed to create display_wrapper.");
491 wl_queue = wl_display_create_queue(display);
493 WL_TBM_LOG("Failed to create queue.");
494 wl_proxy_wrapper_destroy(display_wrapper);
499 wl_proxy_set_queue((struct wl_proxy *)display_wrapper, wl_queue);
501 wl_registry = wl_display_get_registry(display_wrapper);
502 wl_proxy_wrapper_destroy(display_wrapper);
504 WL_TBM_LOG("Failed to get registry");
506 wl_event_queue_destroy(wl_queue);
511 wl_registry_add_listener(wl_registry, ®istry_listener, tbm_client);
512 if (wl_display_roundtrip_queue(display, wl_queue) < 0) {
513 WL_TBM_LOG("Failed to wl_display_roundtrip_queue");
515 wl_registry_destroy(wl_registry);
516 wl_event_queue_destroy(wl_queue);
521 wl_event_queue_destroy(wl_queue);
522 wl_registry_destroy(wl_registry);
525 if (!tbm_client->wl_tbm) {
526 WL_TBM_LOG("failed to create wl_tbm");
527 wayland_tbm_client_deinit(tbm_client);
532 * wl_tbm's queue is destroyed above. We should make wl_tbm's queue to
533 * use display's default_queue.
535 wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, NULL);
537 /* queue_info list */
538 wl_list_init(&tbm_client->queue_info_list);
544 wayland_tbm_client_deinit(struct wayland_tbm_client *tbm_client)
549 if (tbm_client->bufmgr)
550 tbm_bufmgr_deinit(tbm_client->bufmgr);
552 if (tbm_client->wl_tbm) {
553 wl_tbm_set_user_data(tbm_client->wl_tbm, NULL);
554 wl_tbm_destroy(tbm_client->wl_tbm);
558 && (tbm_client == wl_tbm_monitor_get_user_data(tbm_monitor))) {
559 wl_tbm_monitor_destroy(tbm_monitor);
566 struct wayland_tbm_buffer *
567 _wayland_tbm_client_find_tbm_buffer_wl_buffer(struct wayland_tbm_client *tbm_client,
568 struct wl_buffer *wl_buffer)
570 struct wayland_tbm_surface_queue *queue_info = NULL;
572 if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
574 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
575 struct wayland_tbm_buffer *buffer = NULL;
577 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
578 if (buffer->wl_buffer == wl_buffer)
586 struct wayland_tbm_buffer *
587 _wayland_tbm_client_find_tbm_buffer_surface(struct wayland_tbm_client *tbm_client,
588 tbm_surface_h surface)
590 struct wayland_tbm_surface_queue *queue_info = NULL;
592 if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
594 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
595 struct wayland_tbm_buffer *buffer = NULL;
597 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
598 if (buffer->tbm_surface == surface)
607 wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
608 tbm_surface_h surface)
610 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
611 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
613 int bufs[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
614 struct wl_buffer *wl_buffer = NULL;
615 struct wayland_tbm_buffer *buffer = NULL;
616 int num_buf, is_fd = -1, i;
617 char debug_id[64] = {0, };
618 tbm_surface_info_s info;
620 struct wl_array plane_buf_idx, plane_offset, plane_stride, plane_size;
624 * if the surface is the attached surface from display server,
625 * return the wl_buffer of the attached surface
628 buffer = _wayland_tbm_client_find_tbm_buffer_surface(tbm_client, surface);
630 return buffer->wl_buffer;
632 if (tbm_surface_get_info(surface, &info) != TBM_SURFACE_ERROR_NONE) {
633 WL_TBM_LOG("Failed to create buffer from surface");
637 if (info.num_planes > 3) {
638 WL_TBM_LOG("invalid num_planes(%d)", info.num_planes);
642 num_buf = tbm_surface_internal_get_num_bos(surface);
644 WL_TBM_LOG("surface doesn't have any bo.");
648 for (i = 0; i < num_buf; i++) {
649 tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
651 WL_TBM_LOG("Failed to get bo from surface");
655 /* try to get fd first */
656 if (is_fd == -1 || is_fd == 1) {
657 bufs[i] = tbm_bo_export_fd(bo);
658 if (is_fd == -1 && bufs[i] >= 0)
662 /* if fail to get fd, try to get name second */
663 if (is_fd == -1 || is_fd == 0) {
664 bufs[i] = tbm_bo_export(bo);
665 if (is_fd == -1 && bufs[i] > 0)
670 (is_fd == 1 && bufs[i] < 0) ||
671 (is_fd == 0 && bufs[i] <= 0)) {
672 WL_TBM_LOG("Failed to export(is_fd:%d, bufs:%d)", is_fd, bufs[i]);
677 wl_array_init(&plane_buf_idx);
678 wl_array_init(&plane_offset);
679 wl_array_init(&plane_stride);
680 wl_array_init(&plane_size);
682 for (i = 0; i < 3; i++) {
683 p = wl_array_add(&plane_buf_idx, sizeof(int));
684 *p = tbm_surface_internal_get_plane_bo_idx(surface, i);
685 p = wl_array_add(&plane_offset, sizeof(int));
686 *p = info.planes[i].offset;
687 p = wl_array_add(&plane_stride, sizeof(int));
688 *p = info.planes[i].stride;
689 p = wl_array_add(&plane_size, sizeof(int));
690 *p = info.planes[i].size;
694 wl_buffer = wl_tbm_create_buffer_with_fd(tbm_client->wl_tbm,
695 info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
696 &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
697 flags, num_buf, bufs[0],
698 (bufs[1] == -1) ? bufs[0] : bufs[1],
699 (bufs[2] == -1) ? bufs[0] : bufs[2]);
701 wl_buffer = wl_tbm_create_buffer(tbm_client->wl_tbm,
702 info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
703 &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
705 num_buf, bufs[0], bufs[1], bufs[2]);
707 wl_array_release(&plane_buf_idx);
708 wl_array_release(&plane_offset);
709 wl_array_release(&plane_stride);
710 wl_array_release(&plane_size);
713 WL_TBM_LOG("Failed to create wl_buffer");
717 for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
718 if (is_fd == 1 && (bufs[i] >= 0))
722 wl_buffer_set_user_data(wl_buffer, surface);
724 snprintf(debug_id, sizeof(debug_id), "%u",
725 (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
726 tbm_surface_internal_set_debug_data(surface, "id", debug_id);
729 WL_TBM_TRACE(" pid:%d wl_buffer:%p tbm_surface:%p", getpid(),
736 for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
737 if (is_fd == 1 && (bufs[i] >= 0))
745 wayland_tbm_client_destroy_buffer(struct wayland_tbm_client *tbm_client,
746 struct wl_buffer *wl_buffer)
748 struct wayland_tbm_buffer *buffer = NULL;
750 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
751 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
753 // TODO: valid check if the buffer is from this tbm_client???
756 WL_TBM_TRACE(" pid:%d wl_buffer:%p", getpid(), wl_buffer);
759 buffer = _wayland_tbm_client_find_tbm_buffer_wl_buffer(tbm_client, wl_buffer);
761 buffer->wl_buffer = NULL;
763 wl_buffer_set_user_data(wl_buffer, NULL);
764 wl_buffer_destroy(wl_buffer);
768 wayland_tbm_client_set_sync_timeline(struct wayland_tbm_client *tbm_client,
769 struct wl_buffer *wl_buffer, tbm_fd timeline)
771 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
772 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
774 wl_tbm_set_sync_timeline(tbm_client->wl_tbm, wl_buffer, timeline);
778 wayland_tbm_client_set_buffer_transform(struct wayland_tbm_client *tbm_client,
779 struct wl_buffer *wl_buffer, int transform)
781 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
782 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
783 WL_TBM_RETURN_IF_FAIL(transform >= 0);
785 wl_tbm_set_buffer_transform(tbm_client->wl_tbm, wl_buffer, transform);
789 wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client)
791 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
793 return (void *)tbm_client->bufmgr;
797 _wayland_tbm_client_queue_destroy_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
799 struct wayland_tbm_buffer *buffer, *tmp;
801 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
803 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
805 if (buffer->wl_buffer) {
806 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
808 if (!buffer->reuse) {
810 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
812 wl_buffer_destroy(buffer->wl_buffer);
813 buffer->wl_buffer = NULL;
817 tbm_surface_internal_unref(buffer->tbm_surface);
818 wl_list_remove(&buffer->link);
824 _wayland_tbm_client_queue_destroy_unused_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
826 struct wayland_tbm_buffer *buffer, *tmp;
828 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
829 if (buffer->allocated) continue;
831 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
833 if (buffer->wl_buffer) {
834 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
836 if (!buffer->reuse) {
838 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
840 wl_buffer_destroy(buffer->wl_buffer);
841 buffer->wl_buffer = NULL;
845 tbm_surface_internal_unref(buffer->tbm_surface);
846 wl_list_remove(&buffer->link);
852 _wayland_tbm_client_surface_queue_flush(struct wayland_tbm_surface_queue *queue_info)
855 WL_TBM_TRACE("pid:%d", getpid());
858 _wayland_tbm_client_queue_destroy_unused_attach_bufs(queue_info);
859 tbm_surface_queue_set_size(queue_info->tbm_queue, queue_info->queue_size, 1);
863 _wayland_tbm_client_create_surface_from_param(tbm_bufmgr bufmgr,
871 struct wl_array *plane_buf_idx,
872 struct wl_array *plane_offset,
873 struct wl_array *plane_stride,
874 struct wl_array *plane_size,
881 int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
882 tbm_surface_info_s info = { 0, };
883 tbm_bo bos[TBM_SURF_PLANE_MAX];
884 int i, numPlane, numName;
885 tbm_surface_h tbm_surface;
887 numPlane = tbm_surface_internal_get_num_planes(format);
888 WL_TBM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
891 info.height = height;
892 info.format = format;
895 info.num_planes = numPlane;
898 for (i = 0; i < numPlane; i++) {
899 info.planes[i].offset = *WL_TBM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
900 info.planes[i].stride = *WL_TBM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
901 info.planes[i].size = *WL_TBM_ARRAY_NTH_DATA(plane_size, int32_t, i);
910 for (i = 0; i < numName; i++) {
912 bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
914 bos[i] = tbm_bo_import(bufmgr, names[i]);
917 tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
918 if (tbm_surface == NULL) {
933 for (i = 0; i < numName; i++)
934 tbm_bo_unref(bos[i]);
940 _wayland_tbm_client_is_valid_attach_bufs(struct wayland_tbm_surface_queue *queue_info,
941 struct wayland_tbm_buffer *buffer)
943 int width, height, format;
945 width = tbm_surface_get_width(buffer->tbm_surface);
946 height = tbm_surface_get_height(buffer->tbm_surface);
947 format = tbm_surface_get_format(buffer->tbm_surface);
949 if (queue_info->width != width ||
950 queue_info->height != height ||
951 queue_info->format != format)
958 __wayland_tbm_client_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *data)
960 struct wayland_tbm_surface_queue *queue_info =
961 (struct wayland_tbm_surface_queue *)data;
962 struct wayland_tbm_buffer *buffer;
963 tbm_surface_h surface = NULL;
965 if (queue_info->is_active && queue_info->active_flush) {
966 wl_list_for_each_reverse(buffer, &queue_info->attach_bufs, link) {
967 if (!buffer->allocated && buffer->usable) {
968 if (_wayland_tbm_client_is_valid_attach_bufs(queue_info, buffer)) {
969 surface = buffer->tbm_surface;
970 /* ref.. pair of __wayland_tbm_client_surface_free_cb */
971 tbm_surface_internal_ref(surface);
972 buffer->allocated = 1;
974 WL_TBM_TRACE(" pid:%d wl_buffer:%p tbm_surface:%p ACTIVE", getpid(), buffer->wl_buffer, buffer->tbm_surface);
977 surface = tbm_surface_internal_create_with_flags(queue_info->width,
982 WL_TBM_TRACE(" pid:%d tbm_surface:%p invalid attach_bufs fallback", getpid(), surface);
990 /* ref.. pair of __wayland_tbm_client_surface_free_cb */
991 surface = tbm_surface_internal_create_with_flags(queue_info->width,
997 WL_TBM_TRACE(" pid:%d tbm_surface:%p DEACTIVE", getpid(), surface);
1005 __wayland_tbm_client_surface_free_cb(tbm_surface_queue_h surface_queue, void *data,
1006 tbm_surface_h surface)
1009 WL_TBM_TRACE(" pid:%d tbm_surface:%p", getpid(), surface);
1011 struct wayland_tbm_surface_queue *queue_info =
1012 (struct wayland_tbm_surface_queue *)data;
1013 struct wayland_tbm_buffer *buffer, *tmp;
1015 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
1016 if (buffer->tbm_surface != surface) continue;
1017 if (!buffer->allocated) continue;
1019 buffer->allocated = 0;
1022 if (queue_info->is_active) continue;
1023 if (buffer->wl_buffer)
1024 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
1026 tbm_surface_internal_unref(buffer->tbm_surface);
1027 wl_list_remove(&buffer->link);
1031 /* unref.. pair of __wayland_tbm_client_surface_alloc_cb */
1032 tbm_surface_internal_unref(surface);
1036 handle_tbm_queue_buffer_attached(void *data,
1037 struct wl_tbm_queue *wl_tbm_queue,
1038 struct wl_buffer *wl_buffer,
1041 struct wayland_tbm_surface_queue *queue_info =
1042 (struct wayland_tbm_surface_queue *)data;
1043 struct wayland_tbm_buffer *buffer;
1045 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1047 buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
1048 WL_TBM_GOTO_IF_FAIL(buffer != NULL, fail_alloc);
1050 wl_list_init(&buffer->link);
1052 buffer->wl_tbm_queue = wl_tbm_queue;
1053 buffer->wl_buffer = wl_buffer;
1054 buffer->allocated = 0;
1056 buffer->tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1057 WL_TBM_GOTO_IF_FAIL(buffer->tbm_surface != NULL, fail_get_data);
1058 buffer->flags = flags;
1060 wl_list_insert(&queue_info->attach_bufs, &buffer->link);
1063 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1064 getpid(), buffer->wl_buffer, buffer->tbm_surface);
1072 wl_buffer_destroy(wl_buffer);
1076 handle_tbm_queue_active(void *data,
1077 struct wl_tbm_queue *wl_tbm_queue,
1079 uint32_t queue_size,
1080 uint32_t need_flush)
1082 struct wayland_tbm_surface_queue *queue_info =
1083 (struct wayland_tbm_surface_queue *)data;
1085 WL_TBM_LOG("active queue");
1087 if (queue_info->is_active) {
1088 WL_TBM_C_LOG("warning: queue_info is already activated");
1092 WL_TBM_TRACE(" pid:%d", getpid());
1095 queue_info->is_active = 1;
1096 queue_info->usage = usage;
1099 /* flush the allocated surfaces at the client */
1100 queue_info->active_flush = need_flush;
1101 tbm_surface_queue_set_size(queue_info->tbm_queue, queue_size, 1);
1106 handle_tbm_queue_deactive(void *data,
1107 struct wl_tbm_queue *wl_tbm_queue)
1109 struct wayland_tbm_surface_queue *queue_info =
1110 (struct wayland_tbm_surface_queue *)data;
1113 WL_TBM_TRACE(" pid:%d", getpid());
1116 WL_TBM_LOG("deactive queue");
1118 if (!queue_info->is_active) {
1119 WL_TBM_C_LOG("warning: queue_info is already deactivated");
1123 queue_info->is_active = 0;
1125 if (queue_info->active_flush) {
1126 queue_info->active_flush = 0;
1127 /* flush the attached surfaces */
1128 _wayland_tbm_client_surface_queue_flush(queue_info);
1133 handle_tbm_queue_flush(void *data,
1134 struct wl_tbm_queue *wl_tbm_queue)
1136 struct wayland_tbm_surface_queue *queue_info =
1137 (struct wayland_tbm_surface_queue *)data;
1140 WL_TBM_TRACE("pid:%d", getpid());
1142 WL_TBM_LOG("flush queue");
1144 if (queue_info->is_active && queue_info->active_flush) {
1145 WL_TBM_C_LOG("warning: Cannot flush the tbm_surface_queueu. The queue is activate.");
1149 /* flush the allocated surfaces at the client */
1150 tbm_surface_queue_flush(queue_info->tbm_queue);
1154 handle_tbm_queue_buffer_usable(void *data,
1155 struct wl_tbm_queue *wl_tbm_queue,
1156 struct wl_buffer *wl_buffer)
1158 struct wayland_tbm_surface_queue *queue_info =
1159 (struct wayland_tbm_surface_queue *)data;
1160 struct wayland_tbm_buffer *buffer;
1162 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1164 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1165 if (buffer->wl_buffer == wl_buffer)
1170 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1171 getpid(), buffer->wl_buffer, buffer->tbm_surface);
1174 tbm_surface_queue_notify_dequeuable(queue_info->tbm_queue);
1179 const struct wl_tbm_queue_listener wl_tbm_queue_listener = {
1180 handle_tbm_queue_buffer_attached,
1181 handle_tbm_queue_active,
1182 handle_tbm_queue_deactive,
1183 handle_tbm_queue_flush,
1184 handle_tbm_queue_buffer_usable,
1187 static struct wayland_tbm_surface_queue *
1188 _wayland_tbm_client_find_queue_info_wl_surface(struct wayland_tbm_client *tbm_client,
1189 struct wl_surface *surface)
1191 /* set the debug_pid to the surface for debugging */
1192 if (!wl_list_empty(&tbm_client->queue_info_list)) {
1193 struct wayland_tbm_surface_queue *queue_info = NULL;
1195 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1196 if (queue_info->wl_surface == surface)
1204 static struct wayland_tbm_surface_queue *
1205 _wayland_tbm_client_find_queue_info_queue(struct wayland_tbm_client *tbm_client,
1206 tbm_surface_queue_h queue)
1208 /* set the debug_pid to the surface for debugging */
1209 if (!wl_list_empty(&tbm_client->queue_info_list)) {
1210 struct wayland_tbm_surface_queue *queue_info = NULL;
1212 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1213 if (queue_info->tbm_queue == queue)
1223 _handle_tbm_surface_queue_destroy_notify(tbm_surface_queue_h surface_queue,
1226 struct wayland_tbm_surface_queue *queue_info =
1227 (struct wayland_tbm_surface_queue *)data;
1230 WL_TBM_TRACE(" pid:%d", getpid());
1233 /* remove the attach_bufs int the queue_info */
1234 _wayland_tbm_client_queue_destroy_attach_bufs(queue_info);
1236 if (queue_info->wl_tbm_queue)
1237 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1239 wl_list_remove(&queue_info->link);
1244 _handle_tbm_surface_queue_reset_notify(tbm_surface_queue_h surface_queue,
1247 struct wayland_tbm_surface_queue *queue_info = data;
1253 WL_TBM_TRACE(" pid:%d", getpid());
1256 width = tbm_surface_queue_get_width(surface_queue);
1257 height = tbm_surface_queue_get_height(surface_queue);
1258 format = tbm_surface_queue_get_format(surface_queue);
1260 queue_info->width = width;
1261 queue_info->height = height;
1262 queue_info->format = format;
1266 _handle_tbm_surface_queue_can_dequeue_notify(tbm_surface_queue_h surface_queue,
1269 struct wayland_tbm_surface_queue *queue_info = data;
1270 struct wayland_tbm_client *tbm_client = NULL;
1272 WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1274 if (!queue_info->is_active || !queue_info->active_flush) return;
1276 tbm_client = wl_tbm_get_user_data(queue_info->wl_tbm);
1277 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
1279 if (!tbm_client->event_queue) return;
1281 if (wl_display_roundtrip_queue(tbm_client->dpy, tbm_client->event_queue) == -1) {
1284 WL_TBM_LOG_E("failed to wl_display_roundtrip_queue errno:%d", errno);
1286 dpy_err = wl_display_get_error(tbm_client->dpy);
1287 if (dpy_err == EPROTO) {
1288 const struct wl_interface *interface;
1289 uint32_t proxy_id, code;
1290 code = wl_display_get_protocol_error(tbm_client->dpy, &interface, &proxy_id);
1291 WL_TBM_LOG_E("protocol error interface:%s code:%d proxy_id:%d",
1292 interface->name, code, proxy_id);
1298 _handle_tbm_surface_queue_trace_notify(tbm_surface_queue_h surface_queue,
1299 tbm_surface_h tbm_surface, tbm_surface_queue_trace trace, void *data)
1301 struct wayland_tbm_surface_queue *queue_info = data;
1302 struct wl_buffer *wl_buffer = NULL;
1303 struct wayland_tbm_buffer *buffer = NULL;
1305 WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1307 if (trace != TBM_SURFACE_QUEUE_TRACE_DEQUEUE) return;
1308 if (!queue_info->is_active || !queue_info->active_flush) return;
1310 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1311 if (buffer->tbm_surface == tbm_surface)
1312 wl_buffer = buffer->wl_buffer;
1315 if (!wl_buffer) return;
1317 wl_tbm_queue_dequeue_buffer(queue_info->wl_tbm_queue, wl_buffer);
1321 wayland_tbm_client_create_surface_queue(struct wayland_tbm_client *tbm_client,
1322 struct wl_surface *surface,
1324 int width, int height, tbm_format format)
1326 struct wayland_tbm_surface_queue *queue_info;
1327 struct wl_tbm_queue *queue;
1330 WL_TBM_TRACE(" pid:%d", getpid());
1333 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1334 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1336 queue_info = calloc(1, sizeof(struct wayland_tbm_surface_queue));
1337 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1339 queue_info->wl_tbm = tbm_client->wl_tbm;
1340 queue_info->bufmgr = tbm_client->bufmgr;
1341 queue_info->wl_surface = surface;
1342 wl_list_init(&queue_info->attach_bufs);
1344 queue = wl_tbm_create_surface_queue(tbm_client->wl_tbm, surface);
1345 WL_TBM_GOTO_IF_FAIL(queue != NULL, fail);
1347 queue_info->wl_tbm_queue = queue;
1349 wl_tbm_queue_add_listener(queue, &wl_tbm_queue_listener, queue_info);
1351 queue_info->width = width;
1352 queue_info->height = height;
1353 queue_info->format = format;
1354 queue_info->flag = 0;
1355 queue_info->queue_size = queue_size;
1357 queue_info->tbm_queue = tbm_surface_queue_sequence_create(queue_size,
1358 width, height, format, 0);
1359 WL_TBM_GOTO_IF_FAIL(queue_info->tbm_queue != NULL, fail);
1361 tbm_surface_queue_set_alloc_cb(queue_info->tbm_queue,
1362 __wayland_tbm_client_surface_alloc_cb,
1363 __wayland_tbm_client_surface_free_cb,
1366 tbm_surface_queue_add_destroy_cb(queue_info->tbm_queue,
1367 _handle_tbm_surface_queue_destroy_notify,
1370 tbm_surface_queue_add_reset_cb(queue_info->tbm_queue,
1371 _handle_tbm_surface_queue_reset_notify, queue_info);
1373 tbm_surface_queue_add_can_dequeue_cb(queue_info->tbm_queue,
1374 _handle_tbm_surface_queue_can_dequeue_notify, queue_info);
1376 tbm_surface_queue_add_trace_cb(queue_info->tbm_queue,
1377 _handle_tbm_surface_queue_trace_notify, queue_info);
1380 WL_TBM_C_LOG("INFO cur(%dx%d fmt:0x%x num:%d) new(%dx%d fmt:0x%x num:%d)",
1381 queue_info->width, queue_info->height,
1382 queue_info->format, queue_info->num_bufs,
1383 width, height, format, queue_size);
1386 /* add queue_info to the list */
1387 wl_list_insert(&tbm_client->queue_info_list, &queue_info->link);
1389 return queue_info->tbm_queue;
1392 if (queue_info->wl_tbm_queue)
1393 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1398 struct wl_tbm_queue *
1399 wayland_tbm_client_get_wl_tbm_queue(struct wayland_tbm_client *tbm_client, struct wl_surface *surface)
1401 struct wayland_tbm_surface_queue *queue_info = NULL;
1403 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1404 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1406 queue_info = _wayland_tbm_client_find_queue_info_wl_surface(tbm_client, surface);
1407 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1408 WL_TBM_RETURN_VAL_IF_FAIL(queue_info->wl_tbm_queue != NULL, NULL);
1410 return queue_info->wl_tbm_queue;
1414 wayland_tbm_client_get_wl_tbm(struct wayland_tbm_client *tbm_client)
1416 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1418 return tbm_client->wl_tbm;
1422 wayland_tbm_client_queue_check_activate(struct wayland_tbm_client *tbm_client, tbm_surface_queue_h queue)
1424 struct wayland_tbm_surface_queue *queue_info = NULL;
1426 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1427 WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1429 queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1430 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);
1432 if (queue_info->is_active) return 1;
1438 wayland_tbm_client_queue_get_surfaces(struct wayland_tbm_client *tbm_client,
1439 tbm_surface_queue_h queue, tbm_surface_h *surfaces, int *num)
1441 struct wayland_tbm_surface_queue *queue_info = NULL;
1442 tbm_surface_h surface = NULL;
1443 struct wayland_tbm_buffer *buffer = NULL;
1444 tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
1445 tbm_surface_h *get_surfaces;
1446 int get_num = 0, dequeued_num = 0, index = 0;
1449 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1450 WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1452 queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1453 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);;
1455 if (!surfaces && !num) {
1456 WL_TBM_LOG_E("invalid parameter");
1461 if (queue_info->is_active && queue_info->active_flush)
1462 *num = wl_list_length(&queue_info->attach_bufs);
1464 *num = queue_info->queue_size;
1468 if (queue_info->is_active && queue_info->active_flush) {
1469 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1470 surfaces[index] = buffer->tbm_surface;
1474 get_surfaces = (tbm_surface_h *)calloc(queue_info->queue_size, sizeof(tbm_surface_h));
1475 if (!get_surfaces) {
1476 WL_TBM_LOG_E("failed to alloc get_surfaces");
1480 tsq_err = tbm_surface_queue_get_surfaces(queue, get_surfaces, &get_num);
1481 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1482 WL_TBM_LOG_E("failed to tbm_surface_queue_get_surfaces");
1486 for (i = 0; i < get_num; i++) {
1487 surfaces[index] = get_surfaces[i];
1491 if (get_num < queue_info->queue_size) {
1492 for (i = 0; i < queue_info->queue_size - get_num; i++) {
1493 tsq_err = tbm_surface_queue_dequeue(queue, &surface);
1494 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1495 WL_TBM_LOG_E("failed to tbm_surface_queue_dequeue");
1500 surfaces[index] = surface;
1505 for (i = 0; i < dequeued_num; i++) {
1506 tsq_err = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1507 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1508 WL_TBM_LOG_E("failed to tbm_surface_queue_release");
1522 for (i = 0; i < dequeued_num; i++) {
1523 tsq_err = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1524 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1525 WL_TBM_LOG_E("failed to tbm_surface_queue_release");