5 #include <tbm_bufmgr.h>
6 #include <tbm_surface.h>
9 #include "e_mod_main.h"
10 #include "eom-server-protocol.h"
11 #include "Ecore_Drm.h"
12 #include <wayland-tbm-server.h>
18 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "EOM Module" };
19 static E_EomPtr g_eom = NULL;
20 Eina_Bool eom_server_debug_on = EINA_FALSE;
22 static const struct wl_eom_interface _e_eom_wl_implementation =
24 _e_eom_cb_wl_request_set_attribute,
25 _e_eom_cb_wl_request_set_xdg_window,
26 _e_eom_cb_wl_request_set_shell_window,
27 _e_eom_cb_wl_request_get_output_info
30 /* EOM Output Attributes
32 +----------------+------------+----------------+-------------+
33 | | normal | exclusiv_share | exclusive |
34 +----------------+------------+----------------+-------------+
35 | normal | possible | possible | possible |
36 +----------------+------------+----------------+-------------+
37 | exclusiv_share | impossible | possible | possible |
38 +----------------+------------+----------------+-------------+
39 | exclusive | impossible | impossible | impossible |
40 +----------------+------------+----------------+-------------+
45 static int eom_output_attributes[NUM_ATTR][NUM_ATTR] =
52 static const char *eom_conn_types[] =
54 "None", "VGA", "DVI-I", "DVI-D", "DVI-A",
55 "Composite", "S-Video", "LVDS", "Component", "DIN",
56 "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual",
60 static inline eom_output_mode_e
61 _e_eom_output_state_get_mode(E_EomOutputPtr output)
64 return EOM_OUTPUT_MODE_NONE;
69 _e_eom_output_state_set_mode(E_EomOutputPtr output, eom_output_mode_e mode)
76 static inline eom_output_attribute_e
77 _e_eom_output_state_get_attribute_state(E_EomOutputPtr output)
80 return EOM_OUTPUT_ATTRIBUTE_STATE_NONE;
81 return output->attribute_state;
85 _e_eom_output_attribute_state_set(E_EomOutputPtr output, eom_output_attribute_e attribute_state)
89 output->attribute_state = attribute_state;
92 static inline eom_output_attribute_e
93 _e_eom_output_state_get_attribute(E_EomOutputPtr output)
96 return EOM_OUTPUT_ATTRIBUTE_NONE;
97 return output->attribute;
101 _e_eom_output_state_set_force_attribute(E_EomOutputPtr output, eom_output_attribute_e attribute)
105 output->attribute = attribute;
108 static inline Eina_Bool
109 _e_eom_output_state_set_attribute(E_EomOutputPtr output, eom_output_attribute_e attribute)
114 if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE || output->attribute == EOM_OUTPUT_ATTRIBUTE_NONE)
116 output->attribute = attribute;
120 if (eom_output_attributes[output->attribute - 1][attribute - 1] == 1)
122 output->attribute = attribute;
129 static inline tdm_output_conn_status
130 _e_eom_output_state_get_status(E_EomOutputPtr output)
133 return TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
134 return output->status;
138 _e_eom_output_state_set_status(E_EomOutputPtr output, tdm_output_conn_status status)
142 output->status = status;
146 _e_eom_cb_wl_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
148 struct wl_resource *resource = NULL;
149 E_EomClientPtr new_client = NULL;
151 RETURNIFTRUE(data == NULL, "data is NULL");
155 resource = wl_resource_create(client,
159 if (resource == NULL)
161 EOM_ERR("resource is null. (version :%d, id:%d)", version, id);
162 wl_client_post_no_memory(client);
166 wl_resource_set_implementation(resource,
167 &_e_eom_wl_implementation,
169 _e_eom_cb_wl_resource_destory);
171 EOM_DBG("send - output count : %d", g_eom->output_count);
173 wl_eom_send_output_count(resource, g_eom->output_count);
178 E_EomOutputPtr output = NULL;
180 EINA_LIST_FOREACH(g_eom->outputs, l, output)
182 EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
183 output->id, output->type, output->mode, output->width, output->height,
184 output->phys_width, output->phys_height, output->status);
185 wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
186 output->phys_width, output->phys_height, output->status,
191 new_client = E_NEW(E_EomClient, 1);
192 RETURNIFTRUE(new_client == NULL, "Allocate new client")
194 new_client->resource = resource;
195 new_client->current = EINA_FALSE;
196 new_client->output_id = -1;
197 new_client->ec = NULL;
198 new_client->buffers_show = NULL;
199 new_client->buffers_del = NULL;
200 new_client->first_buffer = EINA_TRUE;
202 g_eom->clients = eina_list_append(g_eom->clients, new_client);
206 _e_eom_cb_wl_resource_destory(struct wl_resource *resource)
208 E_EomClientPtr client = NULL, iterator = NULL;
209 E_EomOutputPtr output = NULL;
213 EOM_DBG("client unbind");
215 client = _e_eom_client_get_by_resource(resource);
216 RETURNIFTRUE(client == NULL, "eom client is NULL");
218 g_eom->clients = eina_list_remove(g_eom->clients, client);
220 /* If it is not current client do nothing */
221 if (client->current == EINA_FALSE)
224 output = _e_eom_output_get_by_id(client->output_id);
225 GOTOIFTRUE(output == NULL, end2, "output is NULL");
227 _e_eom_output_state_set_mode(output, EOM_OUTPUT_MODE_MIRROR);
228 ret = _e_eom_output_state_set_attribute(output, EOM_OUTPUT_ATTRIBUTE_NONE);
231 _e_eom_client_free_buffers(client);
233 /* TODO: process case when output is not connected */
234 if (output->state == NONE)
237 /* If a client has been disconnected and mirror mode has not
238 * been restored, start mirror mode
240 if (output->state != MIRROR)
242 output->state = MIRROR;
244 ret = _e_eom_output_start_pp(output);
245 GOTOIFTRUE(ret == EINA_FALSE, end,
246 "Restore mirror mode after a client disconnection");
250 /* Notify eom clients which are binded to a concrete output that the
251 * state and mode of the output has been changed */
252 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
254 if (iterator && iterator->output_id == output->id)
256 wl_eom_send_output_attribute(iterator->resource,
258 _e_eom_output_state_get_attribute(output),
259 _e_eom_output_state_get_attribute_state(output),
260 EOM_OUTPUT_MODE_NONE);
262 wl_eom_send_output_mode(iterator->resource,
264 _e_eom_output_state_get_mode(output));
273 _e_eom_check_boot_connection(void *data)
275 if (g_eom->check_first_boot != 0)
278 return ECORE_CALLBACK_CANCEL;
281 g_eom->check_first_boot = 1;
286 E_EomOutputPtr eom_output;
288 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output)
291 const char *tmp_name;
292 char new_name[DRM_CONNECTOR_NAME_LEN];
293 tdm_output_type tdm_type;
294 tdm_error ret = TDM_ERROR_NONE;
295 tdm_output_conn_status status;
297 if (eom_output->id == 0)
300 output = eom_output->output;
303 EOM_ERR("output is null fail");
307 ret = tdm_output_get_conn_status(output, &status);
308 if (ret != TDM_ERROR_NONE)
310 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
314 if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
317 ret = tdm_output_get_output_type(output, &tdm_type);
318 if (ret != TDM_ERROR_NONE)
320 EOM_ERR("tdm_output_get_output_type fail(%d)", ret);
324 if (tdm_type < ALEN(eom_conn_types))
325 tmp_name = eom_conn_types[tdm_type];
327 tmp_name = "unknown";
328 /*TODO: What if there will more then one output of same type.
329 *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
330 snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
332 eom_output->type = (eom_output_type_e)tdm_type;
333 eom_output->name = eina_stringshare_add(new_name);
334 eom_output->status = status;
336 _e_eom_output_connected(eom_output);
340 return ECORE_CALLBACK_CANCEL;
344 _e_eom_cb_ecore_drm_output(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
346 Ecore_Drm_Event_Output *e = NULL;
349 if (!(e = event)) return ECORE_CALLBACK_PASS_ON;
351 EOM_DBG("id:%d (x,y,w,h):(%d,%d,%d,%d) (w_mm,h_mm):(%d,%d) refresh:%d subpixel_order:%d transform:%d make:%s model:%s name:%s plug:%d",
352 e->id, e->x, e->y, e->w, e->h, e->phys_width, e->phys_height, e->refresh, e->subpixel_order, e->transform, e->make, e->model, e->name, e->plug);
354 snprintf(buff, sizeof(buff), "%s", e->name);
362 g_eom->height = e->h;
363 if (g_eom->main_output_name == NULL)
364 g_eom->main_output_name = strdup(buff);
366 g_eom->main_output_state = UP;
368 if (g_eom->check_first_boot == 0)
371 ecore_timer_del(g_eom->timer);
372 g_eom->timer = ecore_timer_add(EOM_CONNECT_CHECK_TIMEOUT, _e_eom_check_boot_connection, NULL);
379 if (g_eom->main_output_name)
380 free(g_eom->main_output_name);
382 g_eom->main_output_state = DOWN;
386 return ECORE_CALLBACK_PASS_ON;
390 _e_eom_cb_ecore_drm_activate(void *data, int type EINA_UNUSED, void *event)
393 Ecore_Drm_Event_Activate *e = NULL;
396 EOM_DBG("_e_eom_cb_ecore_drm_activate called");
398 if ((!event) || (!data)) goto end;
402 EOM_DBG("e->active:%d", e->active);
416 return ECORE_CALLBACK_PASS_ON;
420 _e_eom_cb_client_buffer_change(void *data, int type, void *event)
422 E_Comp_Wl_Buffer *external_wl_buffer = NULL;
423 E_EomClientBufferPtr client_buffer = NULL;
424 E_EomClientPtr eom_client = NULL;
425 E_EomOutputPtr eom_output = NULL;
426 E_Event_Client *ev = event;
428 tbm_surface_h external_tbm_buffer = NULL;
430 tbm_surface_info_s surface_info;
434 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
435 EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
438 RETURNVALIFTRUE(e_object_is_del(E_OBJECT(ec)),
439 ECORE_CALLBACK_PASS_ON,
440 "ec objects is del");
442 eom_client = _e_eom_client_get_current_by_ec(ec);
443 if (eom_client== NULL)
444 return ECORE_CALLBACK_PASS_ON;
446 RETURNVALIFTRUE(eom_client == NULL,
447 ECORE_CALLBACK_PASS_ON,
448 "Current client is NULL");
451 eom_output = _e_eom_output_get_by_id(eom_client->output_id);
452 RETURNVALIFTRUE(eom_output == NULL,
453 ECORE_CALLBACK_PASS_ON,
454 "eom_output is NULL");
456 if (ec->pixmap == NULL)
457 return ECORE_CALLBACK_PASS_ON;
459 external_wl_buffer = e_pixmap_resource_get(ec->pixmap);
460 RETURNVALIFTRUE(external_wl_buffer == NULL,
461 ECORE_CALLBACK_PASS_ON,
462 "wl buffer is NULL");
463 RETURNVALIFTRUE(external_wl_buffer->resource == NULL,
464 ECORE_CALLBACK_PASS_ON,
468 EOM_DBG("wl_buff:%p type:%d %dx%d ",
470 external_wl_buffer->type,
471 external_wl_buffer->w,
472 external_wl_buffer->h,
476 /* Since Enlightenment client has reconfigured its window to fit
477 * external output resolution and Enlightenment no nothing about
478 * external outputs Enlightenment sees that client's resolution
479 * differs form main screen resolution. Therefore, Enlightenment
480 * is trying to resize it back to main screen resolution. It uses
481 * timer for that purpose. To forbid it just delte the timer */
483 /* TODO: it works but maybe there is better solution exists ?
484 * Also I do not know how it affects on performance */
487 EOM_DBG("delete map_timer");
488 E_FREE_FUNC(ec->map_timer, ecore_timer_del);
491 /* TODO: support buffers smaller then output resolution */
492 if (external_wl_buffer->w != eom_output->width ||
493 external_wl_buffer->h != eom_output->height )
495 EOM_ERR("tbm_buffer does not fit output's resolution");
496 return ECORE_CALLBACK_PASS_ON;
499 /* TODO: support different external_wl_buffer->type */
501 external_tbm_buffer = wayland_tbm_server_get_surface(
502 e_comp->wl_comp_data->tbm.server,
503 external_wl_buffer->resource);
504 RETURNVALIFTRUE(external_tbm_buffer == NULL,
505 ECORE_CALLBACK_PASS_ON,
506 "Client tbm buffer is NULL");
508 /* EOM_DBG("tbm_buffer %p", external_tbm_buffer); */
511 _e_eom_util_draw(external_tbm_buffer);
514 EOM_DBG("BUFF_CHANGE >>>>>>>>>>");
515 client_buffer = _e_eom_util_create_client_buffer(eom_client, external_wl_buffer, external_tbm_buffer);
516 RETURNVALIFTRUE(client_buffer == NULL,
517 ECORE_CALLBACK_PASS_ON,
518 "Alloc client buffer");
520 _e_eom_client_add_buffer(eom_client, client_buffer);
521 EOM_DBG("BUFF_CHANGE <<<<<<<<<<");
523 eom_output->state = PRESENTATION;
525 return ECORE_CALLBACK_PASS_ON;
529 _e_eom_cb_pp(tbm_surface_h surface, void *user_data)
531 tdm_error tdm_err = TDM_ERROR_NONE;
532 E_EomOutputPtr eom_output = NULL;
534 eom_output = (E_EomOutputPtr)user_data;
535 RETURNIFTRUE(user_data == NULL, "pp event: user data is NULL");
537 tdm_buffer_remove_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
538 _e_eom_cb_pp, eom_output);
540 /* TODO: lock these flags??? */
541 if (g_eom->main_output_state == DOWN)
544 /* If a client has committed its buffer stop mirror mode */
545 if (eom_output->state != MIRROR)
548 tbm_surface_h src_buffer;
549 src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
550 RETURNIFTRUE(src_buffer == NULL, "pp event: get root tdm surface");
552 /*TODO: rewrite the mirror mode buffer's switching */
553 eom_output->pp_buffer ^= 1;
555 tdm_err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
556 _e_eom_cb_pp, eom_output);
557 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: set pp hadler:%d", tdm_err );
559 tdm_err = tdm_pp_attach(eom_output->pp, src_buffer, eom_output->dst_buffers[eom_output->pp_buffer]);
560 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp attach:%d", tdm_err);
562 tdm_err = tdm_pp_commit(eom_output->pp);
563 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: commit:%d", tdm_err );
567 _e_eom_cb_commit(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
568 unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
571 E_EomClientBufferPtr client_buffer = NULL;
572 E_EomOutputPtr eom_output = NULL;
573 E_EomClientPtr eom_client = NULL;
574 tdm_error err = TDM_ERROR_NONE;
575 tbm_surface_h external_buffer = NULL;
577 eom_output = (E_EomOutputPtr)user_data;
578 RETURNIFTRUE(user_data == NULL, "commit event: user data is NULL");
580 if (g_eom->main_output_state == DOWN)
583 /* TODO: Maybe better to separating that callback on to mirror and extended callbacks */
584 if (eom_output->state == MIRROR)
586 /*TODO: rewrite the mirror mode buffer's switching */
587 eom_output->current_buffer ^= 1;
588 err = tdm_layer_set_buffer(eom_output->layer,
589 eom_output->dst_buffers[eom_output->current_buffer]);
591 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: set buffer 0 err:%d", err);
593 err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
594 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: commit err:%d", err);
596 else if (eom_output->state == PRESENTATION)
598 eom_client = _e_eom_client_get_current_by_id(eom_output->id);
599 RETURNIFTRUE(eom_client == NULL, "commit event: eom_client is NULL");
601 EOM_DBG("COMMIT +++++++++++++++>");
603 client_buffer = _e_eom_client_get_buffer(eom_client);
604 if (client_buffer == NULL)
606 external_buffer = eom_output->dummy_buffer;
607 EOM_DBG("substitute dummy buffer");
610 external_buffer = client_buffer->tbm_buffer;
613 EOM_DBG("COMMIT draw and set dummy");
615 _e_eom_util_draw(eom_output->dummy_buffer);
616 external_buffer = eom_output->dummy_buffer;
619 #ifdef DUMP_PRESENTATION
620 if (eom_output->dump_do)
622 tbm_surface_internal_dump_buffer(external_buffer, "eom_buffer");
623 eom_output->dump_count++;
625 if (eom_output->dump_count > DUMP_NUM)
627 tbm_surface_internal_dump_end();
628 eom_output->dump_do = EINA_FALSE;
633 err = tdm_layer_set_buffer(eom_output->layer, external_buffer);
634 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: set buffer");
636 err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
637 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: commit err:%d", err);
639 EOM_DBG("COMMIT <+++++++++++++++");
643 _e_eom_util_check_frames(eom_output);
648 _e_eom_output_connected(E_EomOutputPtr eom_output)
651 tdm_error ret = TDM_ERROR_NONE;
652 const char *maker = NULL, *model = NULL, *name = NULL;
653 unsigned int mmWidth, mmHeight, subpixel;
654 const tdm_output_mode *mode;
656 E_EomClientPtr iterator = NULL;
659 output = eom_output->output;
661 ret = tdm_output_get_model_info(output, &maker, &model, &name);
662 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_model_info fail(%d)", ret);
664 ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
665 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_physical_size fail(%d)", ret);
667 ret = tdm_output_get_subpixel(output, &subpixel);
668 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_subpixel fail(%d)", ret);
670 mode = _e_eom_output_get_best_mode(output);
671 RETURNVALIFTRUE(mode == NULL, -1, "_e_eom_get_best_resolution fail");
673 ret = tdm_output_set_mode(output, mode);
674 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_set_mode fail(%d)", ret);
676 x = _e_eom_output_get_position();
677 EOM_DBG("mode: %dx%d, phy(%dx%d), pos(%d,0), refresh:%d, subpixel:%d",
678 mode->hdisplay, mode->vdisplay, mmWidth, mmHeight, x, mode->vrefresh, subpixel);
680 if (!e_comp_wl_output_init(eom_output->name, maker, eom_output->name, x, 0,
681 mode->hdisplay, mode->vdisplay,
682 mmWidth, mmHeight, mode->vrefresh, subpixel, 0))
684 EOM_ERR("Could not setup new output: %s", eom_output->name);
687 EOM_DBG("Setup new output: %s", eom_output->name);
689 /* update eom_output connect */
690 eom_output->width = mode->hdisplay;
691 eom_output->height = mode->vdisplay;
692 eom_output->phys_width = mmWidth;
693 eom_output->phys_height = mmHeight;
694 #ifdef DUMP_PRESENTATION
695 eom_output->dump_do = EINA_TRUE;
696 eom_output->dump_count = 1;
698 EOM_DBG("dump init");
699 tbm_surface_internal_dump_start("/eom_buffers", eom_output->width, eom_output->height, DUMP_NUM);
701 /* TODO: check output mode(presentation set) and HDMI type */
702 _e_eom_output_start_mirror(eom_output);
704 /* If there were previously connected clients to the output - notify them */
705 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
709 EOM_DBG("Send MIRROR ON notification to clients");
711 if (iterator->current)
712 wl_eom_send_output_info(iterator->resource, eom_output->id,
713 eom_output->type, eom_output->mode,
714 eom_output->width, eom_output->height,
715 eom_output->phys_width, eom_output->phys_height,
716 WL_EOM_STATUS_CONNECTION,
718 _e_eom_output_state_get_attribute(eom_output),
719 EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE,
722 wl_eom_send_output_info(iterator->resource, eom_output->id,
723 eom_output->type, eom_output->mode,
724 eom_output->width, eom_output->height,
725 eom_output->phys_width, eom_output->phys_height,
726 WL_EOM_STATUS_CONNECTION,
735 _e_eom_cb_tdm_output_status_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
737 tdm_output_type tdm_type;
738 tdm_error ret = TDM_ERROR_NONE;
739 tdm_output_conn_status status;
740 const char *tmp_name;
741 char new_name[DRM_CONNECTOR_NAME_LEN];
742 E_EomOutputPtr eom_output = NULL;
743 tdm_output_conn_status plug;
745 g_eom->check_first_boot = 1;
747 if (type == TDM_OUTPUT_CHANGE_DPMS || g_eom->main_output_state == DOWN)
753 E_EomOutputPtr eom_output_tmp;
755 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
757 if (eom_output_tmp->output == output)
758 eom_output = eom_output_tmp;
761 RETURNIFTRUE(eom_output == NULL, "eom_output get fail");
763 ret = tdm_output_get_output_type(output, &tdm_type);
764 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_output_type fail(%d)", ret);
766 ret = tdm_output_get_conn_status(output, &status);
767 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_conn_status fail(%d)", ret);
771 EOM_DBG("id (%d), type(%d, %d), status(%d, %d)", eom_output->id, type, tdm_type, status, plug);
773 if (tdm_type < ALEN(eom_conn_types))
774 tmp_name = eom_conn_types[tdm_type];
776 tmp_name = "unknown";
777 /*TODO: What if there will more then one output of same type.
778 *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
779 snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
781 eom_output->type = (eom_output_type_e)tdm_type;
782 eom_output->name = eina_stringshare_add(new_name);
783 eom_output->status = plug;
785 if (plug == TDM_OUTPUT_CONN_STATUS_CONNECTED)
787 _e_eom_output_connected(eom_output);
789 else if (plug == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
791 E_EomClientPtr iterator = NULL;
794 if (eom_output->state == MIRROR)
795 _e_eom_output_stop_mirror(eom_output);
796 else if (eom_output->state == PRESENTATION)
797 _e_eom_output_stop_presentation(eom_output);
799 /* update eom_output disconnect */
800 eom_output->width = 0;
801 eom_output->height = 0;
802 eom_output->phys_width = 0;
803 eom_output->phys_height = 0;
805 /* If there were previously connected clients to the output - notify them */
806 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
810 EOM_DBG("Send MIRROR OFF notification to clients");
811 if (iterator->current)
812 wl_eom_send_output_info(iterator->resource, eom_output->id,
813 eom_output->type, eom_output->mode,
814 eom_output->width, eom_output->height,
815 eom_output->phys_width, eom_output->phys_height,
816 WL_EOM_STATUS_DISCONNECTION,
818 _e_eom_output_state_get_attribute(eom_output),
819 EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE,
822 wl_eom_send_output_info(iterator->resource, eom_output->id,
823 eom_output->type, eom_output->mode,
824 eom_output->width, eom_output->height,
825 eom_output->phys_width, eom_output->phys_height,
826 WL_EOM_STATUS_DISCONNECTION,
831 e_comp_wl_output_remove(new_name);
832 EOM_DBG("Destory output: %s", new_name);
833 eina_stringshare_del(eom_output->name);
838 _e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
840 eom_error_e eom_error = EOM_ERROR_NONE;
841 E_EomClientPtr eom_client = NULL, current_eom_client = NULL, iterator = NULL;
842 E_EomOutputPtr eom_output = NULL;
843 Eina_Bool ret = EINA_FALSE;
846 eom_client = _e_eom_client_get_by_resource(resource);
847 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
849 /* Bind the client with a concrete output */
850 eom_client->output_id = output_id;
852 eom_output = _e_eom_output_get_by_id(output_id);
853 GOTOIFTRUE(eom_output == NULL, no_output, "eom_output is NULL");
855 EOM_DBG("Set attribute:%d", attribute);
857 if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id)
859 /* Current client can set any flag it wants */
860 _e_eom_output_state_set_force_attribute(eom_output, attribute);
864 /* A client is trying to set new attribute */
865 ret = _e_eom_output_state_set_attribute(eom_output, attribute);
866 if (ret == EINA_FALSE)
868 EOM_DBG("set attribute FAILED");
870 eom_error = EOM_ERROR_INVALID_PARAMETER;
875 EOM_DBG("set attribute OK");
877 /* If client has set EOM_OUTPUT_ATTRIBUTE_NONE switching to mirror mode */
878 if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR)
880 eom_output->state = MIRROR;
881 eom_client->current = EINA_FALSE;
883 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
884 ret = _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
887 _e_eom_client_free_buffers(eom_client);
889 if (eom_output->status == 0)
891 EOM_DBG("output:%d is disconnected", output_id);
895 ret = _e_eom_output_start_pp(eom_output);
896 GOTOIFTRUE(ret == EINA_FALSE, end,
897 "Restore mirror mode after disconnection of the client");
899 /* If mirror mode has been ran notify all clients about that */
900 EOM_DBG("client set NONE attribute send new info to previous current client");
901 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
903 if (iterator->output_id == output_id)
905 wl_eom_send_output_attribute(iterator->resource,
907 _e_eom_output_state_get_attribute(eom_output),
908 _e_eom_output_state_get_attribute_state(eom_output),
911 wl_eom_send_output_mode(iterator->resource,
913 _e_eom_output_state_get_mode(eom_output));
921 /* If client was not able to set attribute then send LOST event
922 * to it and return */
923 /* TODO: I think it is bad to send LOST event in that case
924 * Client must process eom_errors */
925 if (eom_error == EOM_ERROR_INVALID_PARAMETER)
927 EOM_DBG("client failed to set attribute");
929 wl_eom_send_output_attribute(eom_client->resource,
931 _e_eom_output_state_get_attribute(eom_output),
932 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
937 /* Send changes to the caller-client */
938 wl_eom_send_output_attribute(eom_client->resource,
940 _e_eom_output_state_get_attribute(eom_output),
941 _e_eom_output_state_get_attribute_state(eom_output),
944 /* Send changes to previous current client */
945 if (eom_client->current == EINA_FALSE &&
946 (current_eom_client = _e_eom_client_get_current_by_id(eom_output->id)))
948 current_eom_client->current = EINA_FALSE;
950 EOM_DBG("client failed to set attribute");
952 wl_eom_send_output_attribute(current_eom_client->resource,
954 _e_eom_output_state_get_attribute(eom_output),
955 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
959 /* Set the client as current client of the eom_output */
960 eom_client->current= EINA_TRUE;
964 /* Get here if EOM does not have output referred by output_id */
966 wl_eom_send_output_attribute(eom_client->resource,
968 EOM_OUTPUT_ATTRIBUTE_NONE,
969 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
970 EOM_ERROR_NO_SUCH_DEVICE);
972 wl_eom_send_output_mode(eom_client->resource,
974 EOM_OUTPUT_MODE_NONE);
976 wl_eom_send_output_type(eom_client->resource,
978 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
979 TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
983 /* TODO: It uses xdg_surface. Add support of shell_surface */
984 /* TODO: I think there must be implemented an event for client which signals if set window was successful */
986 _e_eom_cb_wl_request_set_xdg_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
990 if (resource == NULL || output_id <= 0 || surface == NULL)
993 EOM_DBG("set xdg output id:%d resource:%p surface:%p",
994 output_id, resource, surface);
996 if (!(ec = wl_resource_get_user_data(surface)))
998 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
999 "No Client For Shell Surface");
1003 _e_eom_window_set_internal(resource, output_id, ec);
1007 _e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
1009 E_Client *ec = NULL;
1011 if (resource == NULL || output_id <= 0 || surface == NULL)
1014 EOM_DBG("set shell output id:%d resource:%p surface:%p",
1015 output_id, resource, surface);
1017 if (!(ec = wl_resource_get_user_data(surface)))
1019 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
1020 "No Client For Shell Surface");
1024 _e_eom_window_set_internal(resource, output_id, ec);
1028 _e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
1030 EOM_DBG("output:%d", output_id);
1035 E_EomOutputPtr output = NULL;
1037 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1039 if (output->id == output_id)
1041 EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
1042 output->id, output->type, output->mode, output->width, output->height,
1043 output->phys_width, output->phys_height, output->status);
1045 wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
1046 output->phys_width, output->phys_height, output->status, 1, 0, 0, 0);
1053 _e_eom_cb_comp_object_redirected(void *data, E_Client *ec)
1055 E_EomCompObjectInterceptHookData *hook_data;
1057 EOM_DBG("_e_eom_cb_comp_object_redirected");
1058 RETURNVALIFTRUE(data == NULL, EINA_TRUE, "data is NULL");
1060 hook_data = (E_EomCompObjectInterceptHookData* )data;
1062 RETURNVALIFTRUE(hook_data->ec == NULL, EINA_TRUE, "hook_data->ec is NULL");
1063 RETURNVALIFTRUE(hook_data->hook == NULL, EINA_TRUE, "hook_data->hook is NULL");
1064 RETURNVALIFTRUE(hook_data->ec != ec, EINA_TRUE, "hook_data->ec != ec");
1066 /* Hide the window from Enlightenment main screen */
1067 e_comp_object_redirected_set(ec->frame, EINA_FALSE);
1069 e_comp_object_intercept_hook_del(hook_data->hook);
1071 g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks,
1080 _e_eom_output_init(tdm_display *dpy)
1082 tdm_error ret = TDM_ERROR_NONE;
1085 ret = tdm_display_get_output_count(dpy, &count);
1086 RETURNVALIFTRUE(ret != TDM_ERROR_NONE,
1088 "tdm_display_get_output_count fail");
1089 RETURNVALIFTRUE(count <= 1,
1091 "output count is 1. device doesn't support external outputs.");
1093 g_eom->output_count = count - 1;
1094 EOM_DBG("external output count : %d", g_eom->output_count);
1096 /* skip main output id:0 */
1098 for (i = 1; i < count; i++)
1100 const tdm_output_mode *mode = NULL;
1101 E_EomOutputPtr new_output = NULL;
1102 unsigned int mmWidth, mmHeight;
1103 tdm_output_conn_status status;
1104 tdm_output *output = NULL;
1105 tdm_output_type type;
1107 output = tdm_display_get_output(dpy, i, &ret);
1108 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1110 "tdm_display_get_output fail(ret:%d)", ret);
1112 GOTOIFTRUE(output == NULL,
1114 "tdm_display_get_output fail(no output:%d)", ret);
1116 ret = tdm_output_get_output_type(output, &type);
1117 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1119 "tdm_output_get_output_type fail(%d)", ret);
1121 new_output = E_NEW(E_EomOutput, 1);
1122 GOTOIFTRUE(new_output == NULL,
1126 ret = tdm_output_get_conn_status(output, &status);
1127 if (ret != TDM_ERROR_NONE)
1129 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1134 new_output->type = type;
1135 new_output->status = status;
1136 new_output->mode = EOM_OUTPUT_MODE_NONE;
1137 new_output->output = output;
1139 ret = tdm_output_add_change_handler(output, _e_eom_cb_tdm_output_status_change, NULL);
1140 if (ret != TDM_ERROR_NONE)
1142 EOM_ERR("tdm_output_add_change_handler fail(%d)", ret);
1147 if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1149 EOM_DBG("create(%d)output, type:%d, status:%d",
1150 new_output->id, new_output->type, new_output->status);
1151 g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1154 new_output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1156 ret = tdm_output_get_mode(output, &mode);
1157 if (ret != TDM_ERROR_NONE)
1159 EOM_ERR("tdm_output_get_mode fail(%d)", ret);
1166 new_output->width = 0;
1167 new_output->height = 0;
1171 new_output->width = mode->hdisplay;
1172 new_output->height = mode->vdisplay;
1175 ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
1176 if (ret != TDM_ERROR_NONE)
1178 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1182 new_output->phys_width = mmWidth;
1183 new_output->phys_height = mmHeight;
1185 EOM_DBG("create(%d)output, type:%d, status:%d, w:%d, h:%d, mm_w:%d, mm_h:%d",
1186 new_output->id, new_output->type, new_output->status,
1187 new_output->width, new_output->height, new_output->phys_width, new_output->phys_height);
1189 g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1198 E_EomOutputPtr output;
1200 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1204 eina_list_free(g_eom->outputs);
1210 static const tdm_output_mode *
1211 _e_eom_output_get_best_mode(tdm_output *output)
1213 tdm_error ret = TDM_ERROR_NONE;
1214 const tdm_output_mode *modes;
1215 const tdm_output_mode *mode = NULL;
1216 /* unsigned int vrefresh = 0; */
1217 unsigned int best_value = 0;
1221 ret = tdm_output_get_available_modes(output, &modes, &count);
1222 if (ret != TDM_ERROR_NONE)
1224 EOM_ERR("tdm_output_get_available_modes fail(%d)", ret);
1228 for (i = 0; i < count; i++)
1230 value = modes[i].vdisplay + modes[i].hdisplay;
1231 if (value >= best_value)
1238 EOM_DBG("bestmode : %s, (%dx%d) r(%d), f(%d), t(%d)",
1239 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1245 _e_eom_output_get_position(void)
1247 tdm_output *output_main = NULL;
1248 const tdm_output_mode *mode;
1249 tdm_error ret = TDM_ERROR_NONE;
1252 output_main = tdm_display_get_output(g_eom->dpy, 0, &ret);
1253 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_display_get_output main fail(ret:%d)", ret);
1254 RETURNVALIFTRUE(output_main == NULL, 0, "tdm_display_get_output main fail(no output:%d)", ret);
1256 ret = tdm_output_get_mode(output_main, &mode);
1257 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_output_get_mode main fail(ret:%d)", ret);
1267 E_EomOutputPtr eom_output_tmp;
1269 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
1271 if (eom_output_tmp->status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1272 x += eom_output_tmp->width;
1280 _e_eom_output_start_mirror(E_EomOutputPtr eom_output)
1282 tdm_layer *hal_layer;
1283 tdm_info_layer layer_info;
1284 tdm_error tdm_err = TDM_ERROR_NONE;
1287 if (eom_output->state == MIRROR)
1290 hal_layer = _e_eom_output_get_layer(eom_output);
1291 GOTOIFTRUE(hal_layer == NULL, err, "Get hal layer");
1293 ret = _e_eom_output_create_buffers(eom_output, eom_output->width, eom_output->height);
1294 GOTOIFTRUE(ret == EINA_FALSE, err, "Create buffers ");
1296 tdm_err = tdm_layer_get_info(hal_layer, &layer_info);
1297 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Get layer info: %d", tdm_err);
1299 EOM_DBG("layer info: %dx%d, pos (x:%d, y:%d, w:%d, h:%d, dpos (x:%d, y:%d, w:%d, h:%d))",
1300 layer_info.src_config.size.h, layer_info.src_config.size.v,
1301 layer_info.src_config.pos.x, layer_info.src_config.pos.y,
1302 layer_info.src_config.pos.w, layer_info.src_config.pos.h,
1303 layer_info.dst_pos.x, layer_info.dst_pos.y,
1304 layer_info.dst_pos.w, layer_info.dst_pos.h);
1306 eom_output->layer = hal_layer;
1307 eom_output->current_buffer = 0;
1309 tdm_err = tdm_layer_set_buffer(hal_layer, eom_output->dst_buffers[eom_output->current_buffer]);
1310 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Set buffer on layer:%d", tdm_err);
1312 tdm_err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_ON);
1313 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "tdm_output_set_dpms on");
1315 /* get main surface */
1316 ret = _e_eom_output_start_pp(eom_output);
1317 GOTOIFTRUE(ret == EINA_FALSE, err, "Get root surfcae");
1319 tdm_err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
1320 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Commit crtc:%d", tdm_err);
1322 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_MIRROR);
1323 /* _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE); */
1324 eom_output->state = MIRROR;
1330 * TODO: add deinitialization
1336 _e_eom_output_stop_mirror(E_EomOutputPtr eom_output)
1338 if (eom_output->state == NONE)
1341 _e_eom_output_state_set_status(eom_output, TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
1342 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE);
1343 _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
1345 _e_eom_output_deinit(eom_output, 1);
1347 eom_output->state = NONE;
1351 _e_eom_output_stop_presentation(E_EomOutputPtr eom_output)
1353 E_EomClientPtr iterator = NULL;
1356 if (eom_output->state == NONE)
1359 _e_eom_output_state_set_status(eom_output, TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
1360 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE);
1362 _e_eom_output_deinit(eom_output, 0);
1364 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1365 if (iterator && iterator->output_id == eom_output->id)
1366 _e_eom_client_free_buffers(iterator);
1368 eom_output->state = NONE;
1372 _e_eom_output_deinit(E_EomOutputPtr eom_output, int pp)
1374 tdm_error err = TDM_ERROR_NONE;
1375 E_EomClientPtr iterator = NULL;
1379 if (eom_output->layer)
1381 err = tdm_layer_unset_buffer(eom_output->layer);
1382 if (err != TDM_ERROR_NONE)
1383 EOM_DBG("fail unset buffer:%d", err);
1385 err = tdm_output_commit(eom_output->output, 0, NULL, eom_output);
1386 if (err != TDM_ERROR_NONE)
1387 EOM_DBG ("fail commit:%d", err);
1390 /* TODO: do I need to do DPMS off? */
1392 err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_OFF);
1393 if (err != TDM_ERROR_NONE)
1394 EOM_ERR("set DPMS off:%d", err);
1398 for (i = 0; i < NUM_MAIN_BUF; i++)
1400 tdm_buffer_remove_release_handler(eom_output->dst_buffers[i],
1401 _e_eom_cb_pp, eom_output);
1403 if (eom_output->dst_buffers[i])
1404 tbm_surface_destroy(eom_output->dst_buffers[i]);
1408 if (g_eom->main_output_state == DOWN)
1409 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1411 if (iterator && iterator->output_id == eom_output->id)
1412 _e_eom_client_free_buffers(iterator);
1417 _e_eom_output_get_layer(E_EomOutputPtr eom_output)
1421 tdm_layer *layer = NULL;
1422 tdm_error err = TDM_ERROR_NONE;
1423 tdm_layer_capability capa;
1424 tdm_info_layer layer_info;
1426 RETURNVALIFTRUE(eom_output == NULL, NULL, "eom_output is NULL");
1427 RETURNVALIFTRUE(eom_output->output == NULL, NULL, "eom_output->output is NULL");
1429 err = tdm_output_get_layer_count(eom_output->output, &count);
1430 if (err != TDM_ERROR_NONE)
1432 EOM_DBG ("tdm_output_get_layer_count fail(%d)", err);
1436 for (i = 0; i < count; i++)
1438 layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err);
1439 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_output_get_layer fail(%d)", err);
1441 err = tdm_layer_get_capabilities(layer, &capa);
1442 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_get_capabilities fail(%d)", err);
1444 if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
1446 EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d", i);
1451 memset(&layer_info, 0x0, sizeof(tdm_info_layer));
1452 layer_info.src_config.size.h = eom_output->width;
1453 layer_info.src_config.size.v = eom_output->height;
1454 layer_info.src_config.pos.x = 0;
1455 layer_info.src_config.pos.y = 0;
1456 layer_info.src_config.pos.w = eom_output->width;
1457 layer_info.src_config.pos.h = eom_output->height;
1458 layer_info.src_config.format = TBM_FORMAT_ARGB8888;
1459 layer_info.dst_pos.x = 0;
1460 layer_info.dst_pos.y = 0;
1461 layer_info.dst_pos.w = eom_output->width;
1462 layer_info.dst_pos.h = eom_output->height;
1463 layer_info.transform = TDM_TRANSFORM_NORMAL;
1465 err = tdm_layer_set_info(layer, &layer_info);
1466 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_set_info fail(%d)", err);
1471 static E_EomOutputPtr
1472 _e_eom_output_get_by_id(int id)
1475 E_EomOutputPtr output;
1477 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1479 if (output && output->id == id)
1487 _e_eom_output_start_pp(E_EomOutputPtr eom_output)
1489 /* should be changed in HWC enable environment */
1490 tbm_surface_info_s src_buffer_info;
1491 tbm_surface_h src_buffer = NULL;
1492 Eina_Bool ret = EINA_FALSE;
1494 src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
1495 RETURNVALIFTRUE(src_buffer == NULL, EINA_FALSE, "Get root tdm surfcae");
1497 tbm_surface_get_info(src_buffer, &src_buffer_info);
1499 EOM_DBG("main output info: %dx%d bpp:%d size:%d",
1500 src_buffer_info.width, src_buffer_info.height,
1501 src_buffer_info.bpp, src_buffer_info.size);
1503 /* TODO: if internal and external outputs are equal */
1504 ret = _e_eom_pp_is_needed(g_eom->width, g_eom->height,
1505 eom_output->width, eom_output->height);
1506 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_TRUE, "pp is not required");
1508 ret = _e_eom_pp_init(eom_output, src_buffer);
1509 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_FALSE, "Init pp");
1515 _e_eom_output_create_buffers(E_EomOutputPtr eom_output, int width, int height)
1519 /* TODO: Add support for other formats */
1520 for (i = 0; i < NUM_MAIN_BUF; i++)
1522 eom_output->dst_buffers[i] = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1523 GOTOIFTRUE(eom_output->dst_buffers[i] == NULL, err, "Create dst buffer");
1526 eom_output->dummy_buffer = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1527 GOTOIFTRUE(eom_output->dummy_buffer == NULL, err, "Create dummy buffer");
1532 for (i = 0; i < NUM_MAIN_BUF; i++)
1533 if (eom_output->dst_buffers[i])
1534 tbm_surface_destroy(eom_output->dst_buffers[i]);
1540 _e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec)
1542 E_EomOutputPtr eom_output = NULL;
1543 E_EomClientPtr eom_client = NULL;
1544 E_Comp_Client_Data *cdata = NULL;
1545 Eina_Bool ret = EINA_FALSE;
1547 if (resource == NULL || output_id <= 0 || ec == NULL)
1550 cdata = ec->comp_data;
1551 RETURNIFTRUE(cdata == NULL, "cdata is NULL");
1552 RETURNIFTRUE(cdata->shell.configure_send == NULL, "cdata->shell.configure_send is NULL");
1554 eom_client = _e_eom_client_get_by_resource(resource);
1555 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
1557 eom_output = _e_eom_output_get_by_id(output_id);
1558 RETURNIFTRUE(eom_output == NULL, "eom_output is NULL");
1560 ret = _e_eom_util_add_comp_object_redirected_hook(ec);
1561 RETURNIFTRUE(ret != EINA_TRUE, "Set redirect comp hook failed");
1563 EOM_DBG("e_comp_object_redirected_set (ec->frame:%p)\n", ec->frame);
1565 /* Send reconfigure event to a client which will resize its window to
1566 * external output resolution in respond */
1567 cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height);
1569 /* ec is used in buffer_change callback for distinguishing external ec and its buffers */
1570 eom_client->ec = ec;
1572 if (eom_client->current == EINA_TRUE)
1573 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_NONE);
1575 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_OUTPUT_OCCUPIED);
1579 _e_eom_pp_init(E_EomOutputPtr eom_output, tbm_surface_h src_buffer)
1581 tdm_error err = TDM_ERROR_NONE;
1582 tdm_info_pp pp_info;
1586 pp = tdm_display_create_pp(g_eom->dpy, &err);
1587 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Create pp:%d", err);
1589 eom_output->pp = pp;
1591 /* TODO : consider rotation */
1592 _e_eom_util_calculate_fullsize(g_eom->width, g_eom->height,
1593 eom_output->width, eom_output->height,
1596 EOM_DBG("PP calculation: x:%d, y:%d, w:%d, h:%d", x, y, w, h);
1598 pp_info.src_config.size.h = g_eom->width;
1599 pp_info.src_config.size.v = g_eom->height;
1600 pp_info.src_config.pos.x = 0;
1601 pp_info.src_config.pos.y = 0;
1602 pp_info.src_config.pos.w = g_eom->width;
1603 pp_info.src_config.pos.h = g_eom->height;
1604 pp_info.src_config.format = TBM_FORMAT_ARGB8888;
1606 pp_info.dst_config.size.h = eom_output->width;
1607 pp_info.dst_config.size.v = eom_output->height;
1608 pp_info.dst_config.pos.x = x;
1609 pp_info.dst_config.pos.y = y;
1610 pp_info.dst_config.pos.w = w;
1611 pp_info.dst_config.pos.h = h;
1612 pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
1614 /* TO DO : get rotation */
1615 pp_info.transform = TDM_TRANSFORM_NORMAL;
1619 err = tdm_pp_set_info(pp, &pp_info);
1620 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp info:%d", err);
1622 eom_output->pp_buffer = !eom_output->current_buffer;
1623 err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
1624 _e_eom_cb_pp, eom_output);
1625 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp handler:%d", err);
1627 err = tdm_pp_attach(pp, src_buffer,
1628 eom_output->dst_buffers[eom_output->pp_buffer]);
1629 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp attach:%d", err);
1631 err = tdm_pp_commit(eom_output->pp);
1632 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp commit:%d", err);
1638 _e_eom_pp_is_needed(int src_w, int src_h, int dst_w, int dst_h)
1650 _e_eom_util_get_debug_env()
1652 char *env = getenv("EOM_SERVER_DEBUG");
1656 eom_server_debug_on =(atoi(env)) > 0 ? EINA_TRUE : EINA_FALSE;
1658 eom_server_debug_on = EINA_FALSE;
1660 EOM_INF("EOM_SERVER_DEBUG = %s", eom_server_debug_on > 0 ? "ON" : "OFF");
1663 static tbm_surface_h
1664 _e_eom_util_create_buffer(int width, int height, int format, int flags)
1666 tbm_surface_info_s buffer_info;
1667 tbm_surface_h buffer = NULL;
1669 buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
1670 RETURNVALIFTRUE(buffer == NULL, NULL, "Create buffer");
1672 memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
1673 if (tbm_surface_map(buffer,
1674 TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
1675 &buffer_info) != TBM_SURFACE_ERROR_NONE)
1677 EOM_ERR("map buffer");
1678 tbm_surface_destroy(buffer);
1682 memset(buffer_info.planes[0].ptr, 0x0, buffer_info.planes[0].size);
1683 tbm_surface_unmap(buffer);
1688 static E_EomClientBufferPtr
1689 _e_eom_util_create_client_buffer(E_EomClientPtr client, E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1691 E_EomClientBufferPtr buffer = NULL;
1693 buffer = E_NEW(E_EomClientBuffer, 1);
1694 RETURNVALIFTRUE(buffer == NULL, NULL, "Allocate new client buffer")
1696 /* TODO: Internal and External frame rate are same */
1698 /* Forbid E sending 'wl_buffer_send_release' event to external clients */
1701 buffer->wl_buffer = wl_buffer;
1702 buffer->tbm_buffer = tbm_buffer;
1704 EOM_DBG("new client buffer wl:%p tbm:%p",
1705 buffer->wl_buffer, buffer->tbm_buffer);
1708 buffer->stamp = _e_eom_util_get_stamp();
1714 static tbm_surface_h
1715 _e_eom_util_get_output_surface(const char *name)
1717 Ecore_Drm_Output *primary_output = NULL;
1718 Ecore_Drm_Device *dev;
1720 tdm_output *tdm_output_obj = NULL;
1721 tbm_surface_h tbm = NULL;
1722 tdm_error err = TDM_ERROR_NONE;
1723 int count = 0, i = 0;
1725 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1727 primary_output = ecore_drm_device_output_name_find(dev, name);
1728 if (primary_output != NULL)
1732 if (primary_output == NULL)
1734 EOM_ERR("Get primary output.(%s)", name);
1735 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1737 primary_output = ecore_drm_output_primary_get(dev);
1738 if (primary_output != NULL)
1742 if (primary_output == NULL)
1744 EOM_ERR("Get primary output.(%s)", name);
1749 tdm_output_obj = tdm_display_get_output(g_eom->dpy, 0, &err);
1750 if (tdm_output_obj == NULL || err != TDM_ERROR_NONE)
1752 EOM_ERR("tdm_display_get_output 0 fail");
1755 err = tdm_output_get_layer_count(tdm_output_obj, &count);
1756 if (err != TDM_ERROR_NONE)
1758 EOM_ERR("tdm_output_get_layer_count fail");
1762 for (i = 0; i < count; i++)
1764 tdm_layer *layer = tdm_output_get_layer(tdm_output_obj, i, NULL);
1765 tdm_layer_capability capabilities = 0;
1766 tdm_layer_get_capabilities(layer, &capabilities);
1767 if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1769 tbm = tdm_layer_get_displaying_buffer(layer, &err);
1770 if (err != TDM_ERROR_NONE)
1772 EOM_ERR("tdm_layer_get_displaying_buffer fail");
1783 _e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v,
1784 int *dst_x, int *dst_y, int *dst_w, int *dst_h)
1786 double h_ratio, v_ratio;
1788 h_ratio = src_h / dst_size_h;
1789 v_ratio = src_v / dst_size_v;
1791 if (h_ratio == v_ratio)
1795 *dst_w = dst_size_h;
1796 *dst_h = dst_size_v;
1798 else if (h_ratio < v_ratio)
1801 *dst_h = dst_size_v;
1802 *dst_w = dst_size_v * src_h / src_v;
1803 *dst_x = (dst_size_h - *dst_w) / 2;
1805 else /* (h_ratio > v_ratio) */
1808 *dst_w = dst_size_h;
1809 *dst_h = dst_size_h * src_h / src_v;
1810 *dst_y = (dst_size_v - *dst_h) / 2;
1815 _e_eom_util_add_comp_object_redirected_hook(E_Client *ec)
1817 E_EomCompObjectInterceptHookData *hook_data = NULL;
1818 E_Comp_Object_Intercept_Hook *hook = NULL;
1820 hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1);
1821 GOTOIFTRUE(hook_data == NULL, err, "hook_data = NULL");
1825 hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,
1826 _e_eom_cb_comp_object_redirected,
1828 GOTOIFTRUE(hook == NULL, err, "hook = NULL");
1830 hook_data->hook = hook;
1832 g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks,
1835 EOM_DBG("_e_eom_redirected_hook have been added");
1846 _e_eom_util_get_stamp()
1850 clock_gettime(CLOCK_MONOTONIC, &tp);
1852 return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1862 _e_eom_util_draw(tbm_surface_h surface)
1864 unsigned char rw = 0, gw = 0, bw = 0, aw = 0;
1865 unsigned char r = 255, g = 255, b = 255, a = 0;
1867 unsigned int *mm = NULL;
1870 int w = (int)tbm_surface_get_width(surface);
1871 int h = (int)tbm_surface_get_height(surface);
1873 tbm_bo bo = tbm_surface_internal_get_bo(surface, 0);
1874 RETURNIFTRUE(bo == NULL, "bo is NULL");
1876 mm = (unsigned int *)tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE).ptr;
1877 RETURNIFTRUE(mm == NULL, "mm is NULL");
1879 for (i = 0; i < h; i++)
1880 for (j = 0; j < w; j++)
1882 if (j > square_x && j < square_x + square_w)
1883 mm[i*w + j] = r << 24 | g << 16 | b << 8 | a;
1885 mm[i*w + j] = rw << 24 | gw << 16 | bw << 8 | aw;
1889 if (square_x + square_w> w)
1896 static void _e_eom_util_check_frames(E_EomOutputPtr eom_output)
1899 static int first = 1;
1901 eom_output->num_frames += 1;
1902 res = gettimeofday(&eom_output->curr, NULL);
1905 EOM_ERR("gettimeofday");
1909 if (eom_output->curr.tv_sec > eom_output->prev.tv_sec && !first)
1911 EOM_DBG("FPS:%d", eom_output->num_frames);
1913 eom_output->num_frames = 0;
1914 eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1915 eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1919 eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1920 eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1927 _e_eom_client_add_buffer(E_EomClientPtr client, E_EomClientBufferPtr buffer)
1929 client->buffers_show = eina_list_append(client->buffers_show, buffer);
1933 _e_eom_client_free_buffers(E_EomClientPtr client)
1935 E_EomClientBufferPtr buffer = NULL;
1938 EINA_LIST_FOREACH(client->buffers_show, l, buffer)
1942 client->buffers_show = eina_list_remove(client->buffers_show, buffer);
1944 /* TODO: not sure if it is necessary */
1945 if (buffer->tbm_buffer && client->first_buffer == EINA_FALSE)
1946 tbm_surface_internal_unref(buffer->tbm_buffer);
1948 /* TODO: not sure if it is necessary */
1949 if (buffer->wl_buffer)
1950 buffer->wl_buffer->busy--;
1956 EINA_LIST_FOREACH(client->buffers_del, l, buffer)
1960 client->buffers_del= eina_list_remove(client->buffers_del, buffer);
1962 /* TODO: not sure if it is necessary */
1963 if (buffer->tbm_buffer)
1964 tbm_surface_internal_unref(buffer->tbm_buffer);
1966 /* TODO: not sure if it is necessary */
1967 if (buffer->wl_buffer)
1968 buffer->wl_buffer->busy--;
1975 static E_EomClientBufferPtr
1976 _e_eom_client_get_buffer(E_EomClientPtr client)
1978 E_EomClientBufferPtr show_buffer = NULL;
1979 E_EomClientBufferPtr prev_buffer = NULL;
1980 E_EomClientBufferPtr del_buffer = NULL;
1983 /* TODO: is it possible that a client has only one buffet to draw too? */
1984 RETURNVALIFTRUE(eina_list_count(client->buffers_show) == 0, NULL,
1985 "eom client (%p) do not have buffers to be shown", client);
1987 /* If there is only one buffer we have slow client, just return the buffer */
1988 if (eina_list_count(client->buffers_show) == 1)
1990 show_buffer = eina_list_nth(client->buffers_show, 0);
1991 RETURNVALIFTRUE(show_buffer == NULL, NULL,
1992 "eom client (%p) buffer is NULL", client);
1994 EOM_DBG("one wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1999 if (client->first_buffer == EINA_TRUE)
2001 show_buffer= eina_list_nth(client->buffers_show, 0);
2002 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) first buffer is NULL", client);
2004 EOM_DBG("first wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2006 /* I am not sure if it is necessary */
2007 EOM_DBG("ref first");
2008 tbm_surface_internal_ref(show_buffer->tbm_buffer);
2010 client->first_buffer = EINA_FALSE;
2014 EINA_LIST_FOREACH(client->buffers_del, l, del_buffer)
2018 client->buffers_del = eina_list_remove(client->buffers_del, del_buffer);
2020 if (del_buffer->wl_buffer)
2022 del_buffer->wl_buffer->busy--;
2023 EOM_DBG("wl_buffer:%p busy:%d", del_buffer->wl_buffer, del_buffer->wl_buffer->busy);
2024 if (del_buffer->wl_buffer->busy == 0)
2026 if (del_buffer->wl_buffer->type != E_COMP_WL_BUFFER_TYPE_TBM)
2028 if (!wl_resource_get_client(del_buffer->wl_buffer->resource))
2030 EOM_DBG("wl_buffer->resource is NULL");
2034 wl_buffer_send_release(del_buffer->wl_buffer->resource);
2039 EOM_DBG("del wl:%p tbm:%p", del_buffer->wl_buffer, del_buffer->tbm_buffer);
2041 if (del_buffer->tbm_buffer)
2043 EOM_DBG("del unref");
2044 tbm_surface_internal_unref(del_buffer->tbm_buffer);
2047 /* TODO: should wl_buffer and tbm_surface be deleted here? */
2052 /* TODO: case of 2 or n buffers */
2053 prev_buffer = eina_list_nth(client->buffers_show, 0);
2054 RETURNVALIFTRUE(prev_buffer == NULL, NULL, "eom client (%p) old_buffer is NULL", client);
2056 EOM_DBG("old wl:%p tbm:%p", prev_buffer->wl_buffer, prev_buffer->tbm_buffer);
2058 client->buffers_show = eina_list_remove(client->buffers_show, prev_buffer);
2059 client->buffers_del = eina_list_append(client->buffers_del, prev_buffer);
2061 /* Take next buffer to be shown on external output */
2062 show_buffer = eina_list_nth(client->buffers_show, 0);
2063 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) next buffer is NULL", client);
2065 EOM_DBG("show wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2067 if (show_buffer->tbm_buffer)
2069 EOM_DBG("show ref");
2070 tbm_surface_internal_ref(show_buffer->tbm_buffer);
2076 static E_EomClientPtr
2077 _e_eom_client_get_by_resource(struct wl_resource *resource)
2080 E_EomClientPtr client;
2082 EINA_LIST_FOREACH(g_eom->clients, l, client)
2084 if (client && client->resource == resource)
2091 static E_EomClientPtr
2092 _e_eom_client_get_current_by_id(int id)
2095 E_EomClientPtr client;
2097 EINA_LIST_FOREACH(g_eom->clients, l, client)
2100 client->current == EINA_TRUE &&
2101 client->output_id == id)
2108 static E_EomClientPtr
2109 _e_eom_client_get_current_by_ec(E_Client *ec)
2112 E_EomClientPtr client;
2114 EINA_LIST_FOREACH(g_eom->clients, l, client)
2117 client->current == EINA_TRUE &&
2128 Eina_Bool ret = EINA_FALSE;
2130 _e_eom_util_get_debug_env();
2132 EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
2134 g_eom = E_NEW(E_Eom, 1);
2135 EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
2137 g_eom->global = wl_global_create(e_comp_wl->wl.disp,
2143 uint32_t id = wl_display_get_serial(e_comp_wl->wl.disp);
2144 EOM_DBG("eom name: %d", id);
2146 EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
2148 ret = _e_eom_init_internal();
2149 GOTOIFTRUE(ret == EINA_FALSE, err, "init_internal() failed");
2151 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_cb_ecore_drm_activate, g_eom);
2152 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT, _e_eom_cb_ecore_drm_output, g_eom);
2153 E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL);
2155 g_eom->main_output_name = NULL;
2165 _e_eom_init_internal()
2167 tdm_error ret = TDM_ERROR_NONE;
2169 g_eom->dpy = tdm_display_init(&ret);
2170 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_init fail");
2172 ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
2173 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_get_fd fail");
2175 g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
2176 GOTOIFTRUE(g_eom->bufmgr == NULL, err, "tbm_bufmgr_init fail");
2178 if (_e_eom_output_init(g_eom->dpy) != EINA_TRUE)
2180 EOM_ERR("_e_eom_output_init fail");
2188 tbm_bufmgr_deinit(g_eom->bufmgr);
2191 tdm_display_deinit(g_eom->dpy);
2199 Ecore_Event_Handler *h = NULL;
2201 if (g_eom == NULL) return;
2203 if (g_eom->handlers)
2205 EINA_LIST_FREE(g_eom->handlers, h)
2206 ecore_event_handler_del(h);
2209 if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
2210 if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
2212 if (g_eom->global) wl_global_destroy(g_eom->global);
2218 e_modapi_init(E_Module *m)
2220 return (_e_eom_init() ? m : NULL);
2224 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2231 e_modapi_save(E_Module *m EINA_UNUSED)
2233 /* Save something to be kept */