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)
299 for (i = 1; i < argc; i++) {
300 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
304 path = _wayland_tbm_dump_directory_make();
305 _waylend_tbm_util_dump_snapshot(tbm_client->bufmgr, scale, path);
306 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): snapshot dump is done. path=%s\n", getpid(), path);
310 void _waylend_tbm_monitor_client_dump_queue(int argc, char *argv[],
311 char *reply, int *len, struct wayland_tbm_client *tbm_client)
317 st = _waylend_tbm_util_proc_state_parse(argv[1]);
319 for (i = 2; i < argc; i++) {
320 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
324 st = _waylend_tbm_util_dump_queue(st, tbm_client->bufmgr, scale);
325 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): queue dump state: %s\n", getpid(),
329 void _waylend_tbm_monitor_client_trace(int argc, char *argv[],
330 char *reply, int *len, struct wayland_tbm_client *tbm_client)
334 st = _waylend_tbm_util_trace(_waylend_tbm_util_proc_state_parse(argv[1]), tbm_client->bufmgr);
335 WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): trace state: %s\n", getpid() ,
341 void (*func)(int argc, char *argv[], char *reply, int *len, struct wayland_tbm_client *tbm_client);
345 _waylend_tbm_monitor_client_show,
349 _waylend_tbm_monitor_client_dump_snapshot,
353 _waylend_tbm_monitor_client_dump_queue,
357 _waylend_tbm_monitor_client_trace,
362 handle_tbm_monitor_client_done(void *data, struct wl_tbm_monitor *wl_tbm_monitor, const char *message)
367 handle_tbm_monitor_client_request_to_client(void *data, struct wl_tbm_monitor *wl_tbm_monitor,
368 const char * options, const char * request_id)
370 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
372 char *argv[WL_TBM_MONITOR_ARGS_MAX] = {0};
375 char message[WL_TBM_MONITOR_REPLY_MSG_LEN] = {0,};
376 int len = sizeof(message);
377 char *reply = message;
382 snprintf(temp, sizeof(temp), "%s", options);
384 argv[argc] = strtok_r(temp, " ", &end);
387 if (argc == WL_TBM_MONITOR_ARGS_MAX)
389 argv[argc] = strtok_r(NULL, " ", &end);
393 WL_TBM_TRACE("receive request_id:%s argc:%d [%s %s] options:'%s'", request_id, argc, argv[0], argv[1], temp);
397 for (i = 0; i < sizeof(option_proc) / sizeof(option_proc[0]); i++) {
398 if (argv[0][0] == '-' && !strncmp(argv[0] + 1, option_proc[i].opt, 32)) {
399 if (option_proc[i].func) {
400 option_proc[i].func(argc, argv, reply, &len, tbm_client);
407 wl_tbm_monitor_responce_to_server(tbm_monitor, message, request_id);
410 static const struct wl_tbm_monitor_listener wl_tbm_monitor_listener = {
411 handle_tbm_monitor_client_done,
412 handle_tbm_monitor_client_request_to_client,
416 _wayland_tbm_client_registry_handle_global(void *data,
417 struct wl_registry *registry, uint32_t name,
418 const char *interface, uint32_t version)
420 struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
422 if (!strcmp(interface, "wl_tbm")) {
423 tbm_client->wl_tbm = wl_registry_bind(registry, name, &wl_tbm_interface,
425 WL_TBM_RETURN_IF_FAIL(tbm_client->wl_tbm != NULL);
427 wl_tbm_add_listener(tbm_client->wl_tbm, &wl_tbm_client_listener, tbm_client);
429 if (!tbm_client->bufmgr) {
430 tbm_client->bufmgr = tbm_bufmgr_init(-1);
431 if (!tbm_client->bufmgr) {
432 WL_TBM_LOG("failed to get auth_info");
433 wl_tbm_destroy(tbm_client->wl_tbm);
434 tbm_client->wl_tbm = NULL;
438 } else if (!strcmp(interface, "wl_tbm_monitor")) {
439 /*Create wl_monotor proxy by sington*/
443 tbm_monitor = wl_registry_bind(registry, name, &wl_tbm_monitor_interface, version);
444 WL_TBM_RETURN_IF_FAIL(tbm_monitor != NULL);
446 wl_proxy_set_queue((struct wl_proxy *)tbm_monitor, NULL);
448 wl_tbm_monitor_add_listener(tbm_monitor, &wl_tbm_monitor_listener, tbm_client);
452 static const struct wl_registry_listener registry_listener = {
453 _wayland_tbm_client_registry_handle_global,
458 wayland_tbm_client_set_event_queue(struct wayland_tbm_client *tbm_client, struct wl_event_queue *queue)
460 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
462 wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, queue);
463 tbm_client->event_queue = queue;
468 struct wayland_tbm_client *
469 wayland_tbm_client_init(struct wl_display *display)
471 WL_TBM_RETURN_VAL_IF_FAIL(display != NULL, NULL);
473 struct wl_display *display_wrapper;
474 struct wayland_tbm_client *tbm_client;
475 struct wl_event_queue *wl_queue;
476 struct wl_registry *wl_registry;
478 _wayland_tbm_check_dlog_enable();
482 tbm_client = calloc(1, sizeof(struct wayland_tbm_client));
483 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
485 tbm_client->dpy = display;
487 display_wrapper = wl_proxy_create_wrapper(display);
488 if (!display_wrapper) {
489 WL_TBM_LOG("Failed to create display_wrapper.");
494 wl_queue = wl_display_create_queue(display);
496 WL_TBM_LOG("Failed to create queue.");
497 wl_proxy_wrapper_destroy(display_wrapper);
502 wl_proxy_set_queue((struct wl_proxy *)display_wrapper, wl_queue);
504 wl_registry = wl_display_get_registry(display_wrapper);
505 wl_proxy_wrapper_destroy(display_wrapper);
507 WL_TBM_LOG("Failed to get registry");
509 wl_event_queue_destroy(wl_queue);
514 wl_registry_add_listener(wl_registry, ®istry_listener, tbm_client);
515 if (wl_display_roundtrip_queue(display, wl_queue) < 0) {
516 WL_TBM_LOG("Failed to wl_display_roundtrip_queue");
518 wl_registry_destroy(wl_registry);
519 wl_event_queue_destroy(wl_queue);
524 wl_event_queue_destroy(wl_queue);
525 wl_registry_destroy(wl_registry);
528 if (!tbm_client->wl_tbm) {
529 WL_TBM_LOG("failed to create wl_tbm");
530 wayland_tbm_client_deinit(tbm_client);
535 * wl_tbm's queue is destroyed above. We should make wl_tbm's queue to
536 * use display's default_queue.
538 wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, NULL);
540 /* queue_info list */
541 wl_list_init(&tbm_client->queue_info_list);
547 wayland_tbm_client_deinit(struct wayland_tbm_client *tbm_client)
552 if (tbm_client->bufmgr)
553 tbm_bufmgr_deinit(tbm_client->bufmgr);
555 if (tbm_client->wl_tbm) {
556 wl_tbm_set_user_data(tbm_client->wl_tbm, NULL);
557 wl_tbm_destroy(tbm_client->wl_tbm);
561 && (tbm_client == wl_tbm_monitor_get_user_data(tbm_monitor))) {
562 wl_tbm_monitor_destroy(tbm_monitor);
569 struct wayland_tbm_buffer *
570 _wayland_tbm_client_find_tbm_buffer_wl_buffer(struct wayland_tbm_client *tbm_client,
571 struct wl_buffer *wl_buffer)
573 struct wayland_tbm_surface_queue *queue_info = NULL;
575 if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
577 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
578 struct wayland_tbm_buffer *buffer = NULL;
580 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
581 if (buffer->wl_buffer == wl_buffer)
589 struct wayland_tbm_buffer *
590 _wayland_tbm_client_find_tbm_buffer_surface(struct wayland_tbm_client *tbm_client,
591 tbm_surface_h surface)
593 struct wayland_tbm_surface_queue *queue_info = NULL;
595 if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
597 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
598 struct wayland_tbm_buffer *buffer = NULL;
600 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
601 if (buffer->tbm_surface == surface)
610 wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
611 tbm_surface_h surface)
613 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
614 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
616 int bufs[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
617 struct wl_buffer *wl_buffer = NULL;
618 struct wayland_tbm_buffer *buffer = NULL;
619 int num_buf, is_fd = -1, i;
620 char debug_id[64] = {0, };
621 tbm_surface_info_s info;
623 struct wl_array plane_buf_idx, plane_offset, plane_stride, plane_size;
627 * if the surface is the attached surface from display server,
628 * return the wl_buffer of the attached surface
631 buffer = _wayland_tbm_client_find_tbm_buffer_surface(tbm_client, surface);
633 return buffer->wl_buffer;
635 if (tbm_surface_get_info(surface, &info) != TBM_SURFACE_ERROR_NONE) {
636 WL_TBM_LOG("Failed to create buffer from surface");
640 if (info.num_planes > 3) {
641 WL_TBM_LOG("invalid num_planes(%d)", info.num_planes);
645 num_buf = tbm_surface_internal_get_num_bos(surface);
647 WL_TBM_LOG("surface doesn't have any bo.");
651 for (i = 0; i < num_buf; i++) {
652 tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
654 WL_TBM_LOG("Failed to get bo from surface");
658 /* try to get fd first */
659 if (is_fd == -1 || is_fd == 1) {
660 bufs[i] = tbm_bo_export_fd(bo);
661 if (is_fd == -1 && bufs[i] >= 0)
665 /* if fail to get fd, try to get name second */
666 if (is_fd == -1 || is_fd == 0) {
667 bufs[i] = tbm_bo_export(bo);
668 if (is_fd == -1 && bufs[i] > 0)
673 (is_fd == 1 && bufs[i] < 0) ||
674 (is_fd == 0 && bufs[i] <= 0)) {
675 WL_TBM_LOG("Failed to export(is_fd:%d, bufs:%d)", is_fd, bufs[i]);
680 wl_array_init(&plane_buf_idx);
681 wl_array_init(&plane_offset);
682 wl_array_init(&plane_stride);
683 wl_array_init(&plane_size);
685 for (i = 0; i < 3; i++) {
686 p = wl_array_add(&plane_buf_idx, sizeof(int));
687 *p = tbm_surface_internal_get_plane_bo_idx(surface, i);
688 p = wl_array_add(&plane_offset, sizeof(int));
689 *p = info.planes[i].offset;
690 p = wl_array_add(&plane_stride, sizeof(int));
691 *p = info.planes[i].stride;
692 p = wl_array_add(&plane_size, sizeof(int));
693 *p = info.planes[i].size;
697 wl_buffer = wl_tbm_create_buffer_with_fd(tbm_client->wl_tbm,
698 info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
699 &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
700 flags, num_buf, bufs[0],
701 (bufs[1] == -1) ? bufs[0] : bufs[1],
702 (bufs[2] == -1) ? bufs[0] : bufs[2]);
704 wl_buffer = wl_tbm_create_buffer(tbm_client->wl_tbm,
705 info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
706 &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
708 num_buf, bufs[0], bufs[1], bufs[2]);
710 wl_array_release(&plane_buf_idx);
711 wl_array_release(&plane_offset);
712 wl_array_release(&plane_stride);
713 wl_array_release(&plane_size);
716 WL_TBM_LOG("Failed to create wl_buffer");
720 for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
721 if (is_fd == 1 && (bufs[i] >= 0))
725 wl_buffer_set_user_data(wl_buffer, surface);
727 snprintf(debug_id, sizeof(debug_id), "%u",
728 (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
729 tbm_surface_internal_set_debug_data(surface, "id", debug_id);
732 WL_TBM_TRACE(" pid:%d wl_buffer:%p tbm_surface:%p", getpid(),
739 for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
740 if (is_fd == 1 && (bufs[i] >= 0))
748 wayland_tbm_client_destroy_buffer(struct wayland_tbm_client *tbm_client,
749 struct wl_buffer *wl_buffer)
751 struct wayland_tbm_buffer *buffer = NULL;
753 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
754 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
756 // TODO: valid check if the buffer is from this tbm_client???
759 WL_TBM_TRACE(" pid:%d wl_buffer:%p", getpid(), wl_buffer);
762 buffer = _wayland_tbm_client_find_tbm_buffer_wl_buffer(tbm_client, wl_buffer);
764 buffer->wl_buffer = NULL;
766 wl_buffer_set_user_data(wl_buffer, NULL);
767 wl_buffer_destroy(wl_buffer);
771 wayland_tbm_client_set_sync_timeline(struct wayland_tbm_client *tbm_client,
772 struct wl_buffer *wl_buffer, tbm_fd timeline)
774 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
775 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
777 wl_tbm_set_sync_timeline(tbm_client->wl_tbm, wl_buffer, timeline);
781 wayland_tbm_client_set_buffer_transform(struct wayland_tbm_client *tbm_client,
782 struct wl_buffer *wl_buffer, int transform)
784 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
785 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
786 WL_TBM_RETURN_IF_FAIL(transform >= 0);
788 wl_tbm_set_buffer_transform(tbm_client->wl_tbm, wl_buffer, transform);
792 wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client)
794 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
796 return (void *)tbm_client->bufmgr;
800 _wayland_tbm_client_queue_destroy_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
802 struct wayland_tbm_buffer *buffer, *tmp;
804 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
806 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
808 if (buffer->wl_buffer) {
809 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
811 if (!buffer->reuse) {
813 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
815 wl_buffer_destroy(buffer->wl_buffer);
816 buffer->wl_buffer = NULL;
820 tbm_surface_internal_unref(buffer->tbm_surface);
821 wl_list_remove(&buffer->link);
827 _wayland_tbm_client_queue_destroy_unused_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
829 struct wayland_tbm_buffer *buffer, *tmp;
831 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
832 if (buffer->allocated) continue;
834 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
836 if (buffer->wl_buffer) {
837 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
839 if (!buffer->reuse) {
841 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
843 wl_buffer_destroy(buffer->wl_buffer);
844 buffer->wl_buffer = NULL;
848 tbm_surface_internal_unref(buffer->tbm_surface);
849 wl_list_remove(&buffer->link);
855 _wayland_tbm_client_surface_queue_flush(struct wayland_tbm_surface_queue *queue_info)
858 WL_TBM_TRACE("pid:%d", getpid());
861 _wayland_tbm_client_queue_destroy_unused_attach_bufs(queue_info);
862 tbm_surface_queue_set_size(queue_info->tbm_queue, queue_info->queue_size, 1);
866 _wayland_tbm_client_create_surface_from_param(tbm_bufmgr bufmgr,
874 struct wl_array *plane_buf_idx,
875 struct wl_array *plane_offset,
876 struct wl_array *plane_stride,
877 struct wl_array *plane_size,
884 int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
885 tbm_surface_info_s info = { 0, };
886 tbm_bo bos[TBM_SURF_PLANE_MAX];
887 int i, numPlane, numName;
888 tbm_surface_h tbm_surface;
890 numPlane = tbm_surface_internal_get_num_planes(format);
891 WL_TBM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
894 info.height = height;
895 info.format = format;
898 info.num_planes = numPlane;
901 for (i = 0; i < numPlane; i++) {
902 info.planes[i].offset = *WL_TBM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
903 info.planes[i].stride = *WL_TBM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
904 info.planes[i].size = *WL_TBM_ARRAY_NTH_DATA(plane_size, int32_t, i);
913 for (i = 0; i < numName; i++) {
915 bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
917 bos[i] = tbm_bo_import(bufmgr, names[i]);
920 tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
921 if (tbm_surface == NULL) {
936 for (i = 0; i < numName; i++)
937 tbm_bo_unref(bos[i]);
943 _wayland_tbm_client_is_valid_attach_bufs(struct wayland_tbm_surface_queue *queue_info,
944 struct wayland_tbm_buffer *buffer)
946 int width, height, format;
948 width = tbm_surface_get_width(buffer->tbm_surface);
949 height = tbm_surface_get_height(buffer->tbm_surface);
950 format = tbm_surface_get_format(buffer->tbm_surface);
952 if (queue_info->width != width ||
953 queue_info->height != height ||
954 queue_info->format != format)
961 __wayland_tbm_client_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *data)
963 struct wayland_tbm_surface_queue *queue_info =
964 (struct wayland_tbm_surface_queue *)data;
965 struct wayland_tbm_buffer *buffer;
966 tbm_surface_h surface = NULL;
968 if (queue_info->is_active && queue_info->active_flush) {
969 wl_list_for_each_reverse(buffer, &queue_info->attach_bufs, link) {
970 if (!buffer->allocated && buffer->usable) {
971 if (_wayland_tbm_client_is_valid_attach_bufs(queue_info, buffer)) {
972 surface = buffer->tbm_surface;
973 /* ref.. pair of __wayland_tbm_client_surface_free_cb */
974 tbm_surface_internal_ref(surface);
975 buffer->allocated = 1;
977 WL_TBM_TRACE(" pid:%d wl_buffer:%p tbm_surface:%p ACTIVE", getpid(), buffer->wl_buffer, buffer->tbm_surface);
980 surface = tbm_surface_internal_create_with_flags(queue_info->width,
985 WL_TBM_TRACE(" pid:%d tbm_surface:%p invalid attach_bufs fallback", getpid(), surface);
993 /* ref.. pair of __wayland_tbm_client_surface_free_cb */
994 surface = tbm_surface_internal_create_with_flags(queue_info->width,
1000 WL_TBM_TRACE(" pid:%d tbm_surface:%p DEACTIVE", getpid(), surface);
1008 __wayland_tbm_client_surface_free_cb(tbm_surface_queue_h surface_queue, void *data,
1009 tbm_surface_h surface)
1012 WL_TBM_TRACE(" pid:%d tbm_surface:%p", getpid(), surface);
1014 struct wayland_tbm_surface_queue *queue_info =
1015 (struct wayland_tbm_surface_queue *)data;
1016 struct wayland_tbm_buffer *buffer, *tmp;
1018 wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
1019 if (buffer->tbm_surface != surface) continue;
1020 if (!buffer->allocated) continue;
1022 buffer->allocated = 0;
1025 if (queue_info->is_active) continue;
1026 if (buffer->wl_buffer)
1027 wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
1029 tbm_surface_internal_unref(buffer->tbm_surface);
1030 wl_list_remove(&buffer->link);
1034 /* unref.. pair of __wayland_tbm_client_surface_alloc_cb */
1035 tbm_surface_internal_unref(surface);
1039 handle_tbm_queue_buffer_attached(void *data,
1040 struct wl_tbm_queue *wl_tbm_queue,
1041 struct wl_buffer *wl_buffer,
1044 struct wayland_tbm_surface_queue *queue_info =
1045 (struct wayland_tbm_surface_queue *)data;
1046 struct wayland_tbm_buffer *buffer;
1048 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1050 buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
1051 WL_TBM_GOTO_IF_FAIL(buffer != NULL, fail_alloc);
1053 wl_list_init(&buffer->link);
1055 buffer->wl_tbm_queue = wl_tbm_queue;
1056 buffer->wl_buffer = wl_buffer;
1057 buffer->allocated = 0;
1059 buffer->tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1060 WL_TBM_GOTO_IF_FAIL(buffer->tbm_surface != NULL, fail_get_data);
1061 buffer->flags = flags;
1063 wl_list_insert(&queue_info->attach_bufs, &buffer->link);
1066 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1067 getpid(), buffer->wl_buffer, buffer->tbm_surface);
1075 wl_buffer_destroy(wl_buffer);
1079 handle_tbm_queue_active(void *data,
1080 struct wl_tbm_queue *wl_tbm_queue,
1082 uint32_t queue_size,
1083 uint32_t need_flush)
1085 struct wayland_tbm_surface_queue *queue_info =
1086 (struct wayland_tbm_surface_queue *)data;
1088 WL_TBM_LOG("active queue");
1090 if (queue_info->is_active) {
1091 WL_TBM_C_LOG("warning: queue_info is already activated");
1095 WL_TBM_TRACE(" pid:%d", getpid());
1098 queue_info->is_active = 1;
1099 queue_info->usage = usage;
1102 /* flush the allocated surfaces at the client */
1103 queue_info->active_flush = need_flush;
1104 tbm_surface_queue_set_size(queue_info->tbm_queue, queue_size, 1);
1109 handle_tbm_queue_deactive(void *data,
1110 struct wl_tbm_queue *wl_tbm_queue)
1112 struct wayland_tbm_surface_queue *queue_info =
1113 (struct wayland_tbm_surface_queue *)data;
1116 WL_TBM_TRACE(" pid:%d", getpid());
1119 WL_TBM_LOG("deactive queue");
1121 if (!queue_info->is_active) {
1122 WL_TBM_C_LOG("warning: queue_info is already deactivated");
1126 queue_info->is_active = 0;
1128 if (queue_info->active_flush) {
1129 queue_info->active_flush = 0;
1130 /* flush the attached surfaces */
1131 _wayland_tbm_client_surface_queue_flush(queue_info);
1136 handle_tbm_queue_flush(void *data,
1137 struct wl_tbm_queue *wl_tbm_queue)
1139 struct wayland_tbm_surface_queue *queue_info =
1140 (struct wayland_tbm_surface_queue *)data;
1143 WL_TBM_TRACE("pid:%d", getpid());
1145 WL_TBM_LOG("flush queue");
1147 if (queue_info->is_active && queue_info->active_flush) {
1148 WL_TBM_C_LOG("warning: Cannot flush the tbm_surface_queueu. The queue is activate.");
1152 /* flush the allocated surfaces at the client */
1153 tbm_surface_queue_flush(queue_info->tbm_queue);
1157 handle_tbm_queue_buffer_usable(void *data,
1158 struct wl_tbm_queue *wl_tbm_queue,
1159 struct wl_buffer *wl_buffer)
1161 struct wayland_tbm_surface_queue *queue_info =
1162 (struct wayland_tbm_surface_queue *)data;
1163 struct wayland_tbm_buffer *buffer;
1165 WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1167 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1168 if (buffer->wl_buffer == wl_buffer)
1173 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1174 getpid(), buffer->wl_buffer, buffer->tbm_surface);
1177 tbm_surface_queue_notify_dequeuable(queue_info->tbm_queue);
1182 const struct wl_tbm_queue_listener wl_tbm_queue_listener = {
1183 handle_tbm_queue_buffer_attached,
1184 handle_tbm_queue_active,
1185 handle_tbm_queue_deactive,
1186 handle_tbm_queue_flush,
1187 handle_tbm_queue_buffer_usable,
1190 static struct wayland_tbm_surface_queue *
1191 _wayland_tbm_client_find_queue_info_wl_surface(struct wayland_tbm_client *tbm_client,
1192 struct wl_surface *surface)
1194 /* set the debug_pid to the surface for debugging */
1195 if (!wl_list_empty(&tbm_client->queue_info_list)) {
1196 struct wayland_tbm_surface_queue *queue_info = NULL;
1198 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1199 if (queue_info->wl_surface == surface)
1207 static struct wayland_tbm_surface_queue *
1208 _wayland_tbm_client_find_queue_info_queue(struct wayland_tbm_client *tbm_client,
1209 tbm_surface_queue_h queue)
1211 /* set the debug_pid to the surface for debugging */
1212 if (!wl_list_empty(&tbm_client->queue_info_list)) {
1213 struct wayland_tbm_surface_queue *queue_info = NULL;
1215 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1216 if (queue_info->tbm_queue == queue)
1226 _handle_tbm_surface_queue_destroy_notify(tbm_surface_queue_h surface_queue,
1229 struct wayland_tbm_surface_queue *queue_info =
1230 (struct wayland_tbm_surface_queue *)data;
1233 WL_TBM_TRACE(" pid:%d", getpid());
1236 /* remove the attach_bufs int the queue_info */
1237 _wayland_tbm_client_queue_destroy_attach_bufs(queue_info);
1239 if (queue_info->wl_tbm_queue)
1240 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1242 wl_list_remove(&queue_info->link);
1247 _handle_tbm_surface_queue_reset_notify(tbm_surface_queue_h surface_queue,
1250 struct wayland_tbm_surface_queue *queue_info = data;
1256 WL_TBM_TRACE(" pid:%d", getpid());
1259 width = tbm_surface_queue_get_width(surface_queue);
1260 height = tbm_surface_queue_get_height(surface_queue);
1261 format = tbm_surface_queue_get_format(surface_queue);
1263 queue_info->width = width;
1264 queue_info->height = height;
1265 queue_info->format = format;
1269 _handle_tbm_surface_queue_can_dequeue_notify(tbm_surface_queue_h surface_queue,
1272 struct wayland_tbm_surface_queue *queue_info = data;
1273 struct wayland_tbm_client *tbm_client = NULL;
1275 WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1277 if (!queue_info->is_active || !queue_info->active_flush) return;
1279 tbm_client = wl_tbm_get_user_data(queue_info->wl_tbm);
1280 WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
1282 if (!tbm_client->event_queue) return;
1284 if (wl_display_roundtrip_queue(tbm_client->dpy, tbm_client->event_queue) == -1) {
1287 WL_TBM_LOG_E("failed to wl_display_roundtrip_queue errno:%d", errno);
1289 dpy_err = wl_display_get_error(tbm_client->dpy);
1290 if (dpy_err == EPROTO) {
1291 const struct wl_interface *interface;
1292 uint32_t proxy_id, code;
1293 code = wl_display_get_protocol_error(tbm_client->dpy, &interface, &proxy_id);
1294 WL_TBM_LOG_E("protocol error interface:%s code:%d proxy_id:%d",
1295 interface->name, code, proxy_id);
1301 _handle_tbm_surface_queue_trace_notify(tbm_surface_queue_h surface_queue,
1302 tbm_surface_h tbm_surface, tbm_surface_queue_trace trace, void *data)
1304 struct wayland_tbm_surface_queue *queue_info = data;
1305 struct wl_buffer *wl_buffer = NULL;
1306 struct wayland_tbm_buffer *buffer = NULL;
1308 WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1310 if (trace != TBM_SURFACE_QUEUE_TRACE_DEQUEUE) return;
1311 if (!queue_info->is_active || !queue_info->active_flush) return;
1313 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1314 if (buffer->tbm_surface == tbm_surface)
1315 wl_buffer = buffer->wl_buffer;
1318 if (!wl_buffer) return;
1320 wl_tbm_queue_dequeue_buffer(queue_info->wl_tbm_queue, wl_buffer);
1324 wayland_tbm_client_create_surface_queue(struct wayland_tbm_client *tbm_client,
1325 struct wl_surface *surface,
1327 int width, int height, tbm_format format)
1329 struct wayland_tbm_surface_queue *queue_info;
1330 struct wl_tbm_queue *queue;
1333 WL_TBM_TRACE(" pid:%d", getpid());
1336 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1337 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1339 queue_info = calloc(1, sizeof(struct wayland_tbm_surface_queue));
1340 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1342 queue_info->wl_tbm = tbm_client->wl_tbm;
1343 queue_info->bufmgr = tbm_client->bufmgr;
1344 queue_info->wl_surface = surface;
1345 wl_list_init(&queue_info->attach_bufs);
1347 queue = wl_tbm_create_surface_queue(tbm_client->wl_tbm, surface);
1348 WL_TBM_GOTO_IF_FAIL(queue != NULL, fail);
1350 queue_info->wl_tbm_queue = queue;
1352 wl_tbm_queue_add_listener(queue, &wl_tbm_queue_listener, queue_info);
1354 queue_info->width = width;
1355 queue_info->height = height;
1356 queue_info->format = format;
1357 queue_info->flag = 0;
1358 queue_info->queue_size = queue_size;
1360 queue_info->tbm_queue = tbm_surface_queue_sequence_create(queue_size,
1361 width, height, format, 0);
1362 WL_TBM_GOTO_IF_FAIL(queue_info->tbm_queue != NULL, fail);
1364 tbm_surface_queue_set_alloc_cb(queue_info->tbm_queue,
1365 __wayland_tbm_client_surface_alloc_cb,
1366 __wayland_tbm_client_surface_free_cb,
1369 tbm_surface_queue_add_destroy_cb(queue_info->tbm_queue,
1370 _handle_tbm_surface_queue_destroy_notify,
1373 tbm_surface_queue_add_reset_cb(queue_info->tbm_queue,
1374 _handle_tbm_surface_queue_reset_notify, queue_info);
1376 tbm_surface_queue_add_can_dequeue_cb(queue_info->tbm_queue,
1377 _handle_tbm_surface_queue_can_dequeue_notify, queue_info);
1379 tbm_surface_queue_add_trace_cb(queue_info->tbm_queue,
1380 _handle_tbm_surface_queue_trace_notify, queue_info);
1383 WL_TBM_C_LOG("INFO cur(%dx%d fmt:0x%x num:%d) new(%dx%d fmt:0x%x num:%d)",
1384 queue_info->width, queue_info->height,
1385 queue_info->format, queue_info->num_bufs,
1386 width, height, format, queue_size);
1389 /* add queue_info to the list */
1390 wl_list_insert(&tbm_client->queue_info_list, &queue_info->link);
1392 return queue_info->tbm_queue;
1395 if (queue_info->wl_tbm_queue)
1396 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1401 struct wl_tbm_queue *
1402 wayland_tbm_client_get_wl_tbm_queue(struct wayland_tbm_client *tbm_client, struct wl_surface *surface)
1404 struct wayland_tbm_surface_queue *queue_info = NULL;
1406 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1407 WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1409 queue_info = _wayland_tbm_client_find_queue_info_wl_surface(tbm_client, surface);
1410 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1411 WL_TBM_RETURN_VAL_IF_FAIL(queue_info->wl_tbm_queue != NULL, NULL);
1413 return queue_info->wl_tbm_queue;
1417 wayland_tbm_client_get_wl_tbm(struct wayland_tbm_client *tbm_client)
1419 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1421 return tbm_client->wl_tbm;
1425 wayland_tbm_client_queue_check_activate(struct wayland_tbm_client *tbm_client, tbm_surface_queue_h queue)
1427 struct wayland_tbm_surface_queue *queue_info = NULL;
1429 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1430 WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1432 queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1433 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);
1435 if (queue_info->is_active) return 1;
1441 wayland_tbm_client_queue_get_surfaces(struct wayland_tbm_client *tbm_client,
1442 tbm_surface_queue_h queue, tbm_surface_h *surfaces, int *num)
1444 struct wayland_tbm_surface_queue *queue_info = NULL;
1445 tbm_surface_h surface = NULL;
1446 struct wayland_tbm_buffer *buffer = NULL;
1447 tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
1448 tbm_surface_h *get_surfaces;
1449 int get_num = 0, dequeued_num = 0, index = 0;
1452 WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1453 WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1455 queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1456 WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);;
1458 if (!surfaces && !num) {
1459 WL_TBM_LOG_E("invalid parameter");
1464 if (queue_info->is_active && queue_info->active_flush)
1465 *num = wl_list_length(&queue_info->attach_bufs);
1467 *num = queue_info->queue_size;
1471 if (queue_info->is_active && queue_info->active_flush) {
1472 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1473 surfaces[index] = buffer->tbm_surface;
1477 get_surfaces = (tbm_surface_h *)calloc(queue_info->queue_size, sizeof(tbm_surface_h));
1478 if (!get_surfaces) {
1479 WL_TBM_LOG_E("failed to alloc get_surfaces");
1483 tsq_err = tbm_surface_queue_get_surfaces(queue, get_surfaces, &get_num);
1484 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1485 WL_TBM_LOG_E("failed to tbm_surface_queue_get_surfaces");
1489 for (i = 0; i < get_num; i++) {
1490 surfaces[index] = get_surfaces[i];
1494 if (get_num < queue_info->queue_size) {
1495 for (i = 0; i < queue_info->queue_size - get_num; i++) {
1496 tsq_err = tbm_surface_queue_dequeue(queue, &surface);
1497 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1498 WL_TBM_LOG_E("failed to tbm_surface_queue_dequeue");
1503 surfaces[index] = surface;
1508 for (i = 0; i < dequeued_num; i++) {
1509 tsq_err = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1510 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1511 WL_TBM_LOG_E("failed to tbm_surface_queue_release");
1525 for (i = 0; i < dequeued_num; i++) {
1526 tsq_err = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1527 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1528 WL_TBM_LOG_E("failed to tbm_surface_queue_release");