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);
600 EOM_DBG("COMMIT +++++++++++++++>");
602 client_buffer = _e_eom_client_get_buffer(eom_client);
603 if (client_buffer == NULL)
605 external_buffer = eom_output->dummy_buffer;
606 EOM_DBG("substitute dummy buffer");
609 external_buffer = client_buffer->tbm_buffer;
612 EOM_DBG("COMMIT draw and set dummy");
614 _e_eom_util_draw(eom_output->dummy_buffer);
615 external_buffer = eom_output->dummy_buffer;
618 #ifdef DUMP_PRESENTATION
619 if (eom_output->dump_do)
621 tbm_surface_internal_dump_buffer(external_buffer, "eom_buffer");
622 eom_output->dump_count++;
624 if (eom_output->dump_count > DUMP_NUM)
626 tbm_surface_internal_dump_end();
627 eom_output->dump_do = EINA_FALSE;
632 err = tdm_layer_set_buffer(eom_output->layer, external_buffer);
633 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: set buffer");
635 err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
636 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: commit err:%d", err);
638 EOM_DBG("COMMIT <+++++++++++++++");
642 _e_eom_util_check_frames(eom_output);
647 _e_eom_output_connected(E_EomOutputPtr eom_output)
650 tdm_error ret = TDM_ERROR_NONE;
651 const char *maker = NULL, *model = NULL, *name = NULL;
652 unsigned int mmWidth, mmHeight, subpixel;
653 const tdm_output_mode *mode;
655 E_EomClientPtr iterator = NULL;
658 output = eom_output->output;
660 ret = tdm_output_get_model_info(output, &maker, &model, &name);
661 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_model_info fail(%d)", ret);
663 ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
664 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_physical_size fail(%d)", ret);
666 ret = tdm_output_get_subpixel(output, &subpixel);
667 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_get_subpixel fail(%d)", ret);
669 mode = _e_eom_output_get_best_mode(output);
670 RETURNVALIFTRUE(mode == NULL, -1, "_e_eom_get_best_resolution fail");
672 ret = tdm_output_set_mode(output, mode);
673 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, -1, "tdm_output_set_mode fail(%d)", ret);
675 x = _e_eom_output_get_position();
676 EOM_DBG("mode: %dx%d, phy(%dx%d), pos(%d,0), refresh:%d, subpixel:%d",
677 mode->hdisplay, mode->vdisplay, mmWidth, mmHeight, x, mode->vrefresh, subpixel);
679 if (!e_comp_wl_output_init(eom_output->name, maker, eom_output->name, x, 0,
680 mode->hdisplay, mode->vdisplay,
681 mmWidth, mmHeight, mode->vrefresh, subpixel, 0))
683 EOM_ERR("Could not setup new output: %s", eom_output->name);
686 EOM_DBG("Setup new output: %s", eom_output->name);
688 /* update eom_output connect */
689 eom_output->width = mode->hdisplay;
690 eom_output->height = mode->vdisplay;
691 eom_output->phys_width = mmWidth;
692 eom_output->phys_height = mmHeight;
693 #ifdef DUMP_PRESENTATION
694 eom_output->dump_do = EINA_TRUE;
695 eom_output->dump_count = 1;
697 EOM_DBG("dump init");
698 tbm_surface_internal_dump_start("/eom_buffers", eom_output->width, eom_output->height, DUMP_NUM);
700 /* TODO: check output mode(presentation set) and HDMI type */
701 _e_eom_output_start_mirror(eom_output);
703 /* If there were previously connected clients to the output - notify them */
704 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
708 EOM_DBG("Send MIRROR ON notification to clients");
710 if (iterator->current)
711 wl_eom_send_output_info(iterator->resource, eom_output->id,
712 eom_output->type, eom_output->mode,
713 eom_output->width, eom_output->height,
714 eom_output->phys_width, eom_output->phys_height,
717 _e_eom_output_state_get_attribute(eom_output),
718 EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE,
721 wl_eom_send_output_info(iterator->resource, eom_output->id,
722 eom_output->type, eom_output->mode,
723 eom_output->width, eom_output->height,
724 eom_output->phys_width, eom_output->phys_height,
734 _e_eom_cb_tdm_output_status_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
736 tdm_output_type tdm_type;
737 tdm_error ret = TDM_ERROR_NONE;
738 tdm_output_conn_status status;
739 const char *tmp_name;
740 char new_name[DRM_CONNECTOR_NAME_LEN];
741 E_EomOutputPtr eom_output = NULL;
742 tdm_output_conn_status plug;
744 g_eom->check_first_boot = 1;
746 if (type == TDM_OUTPUT_CHANGE_DPMS || g_eom->main_output_state == DOWN)
752 E_EomOutputPtr eom_output_tmp;
754 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
756 if (eom_output_tmp->output == output)
757 eom_output = eom_output_tmp;
761 ret = tdm_output_get_output_type(output, &tdm_type);
762 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_output_type fail(%d)", ret);
764 ret = tdm_output_get_conn_status(output, &status);
765 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_conn_status fail(%d)", ret);
769 EOM_DBG("id (%d), type(%d, %d), status(%d, %d)", eom_output->id, type, tdm_type, status, plug);
771 if (tdm_type < ALEN(eom_conn_types))
772 tmp_name = eom_conn_types[tdm_type];
774 tmp_name = "unknown";
775 /*TODO: What if there will more then one output of same type.
776 *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
777 snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
779 eom_output->type = (eom_output_type_e)tdm_type;
780 eom_output->name = eina_stringshare_add(new_name);
781 eom_output->status = plug;
783 if (plug == TDM_OUTPUT_CONN_STATUS_CONNECTED)
785 _e_eom_output_connected(eom_output);
787 else if (plug == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
789 E_EomClientPtr iterator = NULL;
792 if (eom_output->state == MIRROR)
793 _e_eom_output_stop_mirror(eom_output);
795 /* update eom_output disconnect */
796 eom_output->width = 0;
797 eom_output->height = 0;
798 eom_output->phys_width = 0;
799 eom_output->phys_height = 0;
801 /* If there were previously connected clients to the output - notify them */
802 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
806 EOM_DBG("Send MIRROR OFF notification to clients");
807 if (iterator->current)
808 wl_eom_send_output_info(iterator->resource, eom_output->id,
809 eom_output->type, eom_output->mode,
810 eom_output->width, eom_output->height,
811 eom_output->phys_width, eom_output->phys_height,
814 _e_eom_output_state_get_attribute(eom_output),
815 EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE,
818 wl_eom_send_output_info(iterator->resource, eom_output->id,
819 eom_output->type, eom_output->mode,
820 eom_output->width, eom_output->height,
821 eom_output->phys_width, eom_output->phys_height,
827 e_comp_wl_output_remove(new_name);
828 EOM_DBG("Destory output: %s", new_name);
829 eina_stringshare_del(eom_output->name);
834 _e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
836 eom_error_e eom_error = EOM_ERROR_NONE;
837 E_EomClientPtr eom_client = NULL, current_eom_client = NULL, iterator = NULL;
838 E_EomOutputPtr eom_output = NULL;
839 Eina_Bool ret = EINA_FALSE;
842 eom_client = _e_eom_client_get_by_resource(resource);
843 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
845 /* Bind the client with a concrete output */
846 eom_client->output_id = output_id;
848 eom_output = _e_eom_output_get_by_id(output_id);
849 GOTOIFTRUE(eom_output == NULL, no_output, "eom_output is NULL");
851 EOM_DBG("Set attribute:%d", attribute);
853 if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id)
855 /* Current client can set any flag it wants */
856 _e_eom_output_state_set_force_attribute(eom_output, attribute);
860 /* A client is trying to set new attribute */
861 ret = _e_eom_output_state_set_attribute(eom_output, attribute);
862 if (ret == EINA_FALSE)
864 EOM_DBG("set attribute FAILED");
866 eom_error = EOM_ERROR_INVALID_PARAMETER;
871 EOM_DBG("set attribute OK");
873 /* If client has set EOM_OUTPUT_ATTRIBUTE_NONE switching to mirror mode */
874 if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR)
876 eom_output->state = MIRROR;
877 eom_client->current = EINA_FALSE;
879 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
880 ret = _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
883 _e_eom_client_free_buffers(eom_client);
885 if (eom_output->status == 0)
887 EOM_DBG("output:%d is disconnected", output_id);
891 ret = _e_eom_output_start_pp(eom_output);
892 GOTOIFTRUE(ret == EINA_FALSE, end,
893 "Restore mirror mode after disconnection of the client");
895 /* If mirror mode has been ran notify all clients about that */
896 EOM_DBG("client set NONE attribute send new info to previous current client");
897 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
899 if (iterator->output_id == output_id)
901 wl_eom_send_output_attribute(iterator->resource,
903 _e_eom_output_state_get_attribute(eom_output),
904 _e_eom_output_state_get_attribute_state(eom_output),
907 wl_eom_send_output_mode(iterator->resource,
909 _e_eom_output_state_get_mode(eom_output));
917 /* If client was not able to set attribute then send LOST event
918 * to it and return */
919 /* TODO: I think it is bad to send LOST event in that case
920 * Client must process eom_errors */
921 if (eom_error == EOM_ERROR_INVALID_PARAMETER)
923 EOM_DBG("client failed to set attribute");
925 wl_eom_send_output_attribute(eom_client->resource,
927 _e_eom_output_state_get_attribute(eom_output),
928 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
933 /* Send changes to the caller-client */
934 wl_eom_send_output_attribute(eom_client->resource,
936 _e_eom_output_state_get_attribute(eom_output),
937 _e_eom_output_state_get_attribute_state(eom_output),
940 /* Send changes to previous current client */
941 if (eom_client->current == EINA_FALSE &&
942 (current_eom_client = _e_eom_client_get_current_by_id(eom_output->id)))
944 current_eom_client->current = EINA_FALSE;
946 EOM_DBG("client failed to set attribute");
948 wl_eom_send_output_attribute(current_eom_client->resource,
950 _e_eom_output_state_get_attribute(eom_output),
951 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
955 /* Set the client as current client of the eom_output */
956 eom_client->current= EINA_TRUE;
960 /* Get here if EOM does not have output referred by output_id */
962 wl_eom_send_output_attribute(eom_client->resource,
964 EOM_OUTPUT_ATTRIBUTE_NONE,
965 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
966 EOM_ERROR_NO_SUCH_DEVICE);
968 wl_eom_send_output_mode(eom_client->resource,
970 EOM_OUTPUT_MODE_NONE);
972 wl_eom_send_output_type(eom_client->resource,
974 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
975 TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
979 /* TODO: It uses xdg_surface. Add support of shell_surface */
980 /* TODO: I think there must be implemented an event for client which signals if set window was successful */
982 _e_eom_cb_wl_request_set_xdg_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
986 if (resource == NULL || output_id <= 0 || surface == NULL)
989 EOM_DBG("set xdg output id:%d resource:%p surface:%p",
990 output_id, resource, surface);
992 if (!(ec = wl_resource_get_user_data(surface)))
994 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
995 "No Client For Shell Surface");
999 _e_eom_window_set_internal(resource, output_id, ec);
1003 _e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
1005 E_Client *ec = NULL;
1007 if (resource == NULL || output_id <= 0 || surface == NULL)
1010 EOM_DBG("set shell output id:%d resource:%p surface:%p",
1011 output_id, resource, surface);
1013 if (!(ec = wl_resource_get_user_data(surface)))
1015 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
1016 "No Client For Shell Surface");
1020 _e_eom_window_set_internal(resource, output_id, ec);
1024 _e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
1026 EOM_DBG("output:%d", output_id);
1031 E_EomOutputPtr output = NULL;
1033 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1035 if (output->id == output_id)
1037 EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
1038 output->id, output->type, output->mode, output->width, output->height,
1039 output->phys_width, output->phys_height, output->status);
1041 wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
1042 output->phys_width, output->phys_height, output->status, 1, 0, 0, 0);
1049 _e_eom_cb_comp_object_redirected(void *data, E_Client *ec)
1051 E_EomCompObjectInterceptHookData *hook_data;
1053 EOM_DBG("_e_eom_cb_comp_object_redirected");
1054 RETURNVALIFTRUE(data == NULL, EINA_TRUE, "data is NULL");
1056 hook_data = (E_EomCompObjectInterceptHookData* )data;
1058 RETURNVALIFTRUE(hook_data->ec == NULL, EINA_TRUE, "hook_data->ec is NULL");
1059 RETURNVALIFTRUE(hook_data->hook == NULL, EINA_TRUE, "hook_data->hook is NULL");
1060 RETURNVALIFTRUE(hook_data->ec != ec, EINA_TRUE, "hook_data->ec != ec");
1062 /* Hide the window from Enlightenment main screen */
1063 e_comp_object_redirected_set(ec->frame, EINA_FALSE);
1065 e_comp_object_intercept_hook_del(hook_data->hook);
1067 g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks,
1076 _e_eom_output_init(tdm_display *dpy)
1078 tdm_error ret = TDM_ERROR_NONE;
1081 ret = tdm_display_get_output_count(dpy, &count);
1082 RETURNVALIFTRUE(ret != TDM_ERROR_NONE,
1084 "tdm_display_get_output_count fail");
1085 RETURNVALIFTRUE(count <= 1,
1087 "output count is 1. device doesn't support external outputs.");
1089 g_eom->output_count = count - 1;
1090 EOM_DBG("external output count : %d", g_eom->output_count);
1092 /* skip main output id:0 */
1094 for (i = 1; i < count; i++)
1096 const tdm_output_mode *mode = NULL;
1097 E_EomOutputPtr new_output = NULL;
1098 unsigned int mmWidth, mmHeight;
1099 tdm_output_conn_status status;
1100 tdm_output *output = NULL;
1101 tdm_output_type type;
1103 output = tdm_display_get_output(dpy, i, &ret);
1104 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1106 "tdm_display_get_output fail(ret:%d)", ret);
1108 GOTOIFTRUE(output == NULL,
1110 "tdm_display_get_output fail(no output:%d)", ret);
1112 ret = tdm_output_get_output_type(output, &type);
1113 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1115 "tdm_output_get_output_type fail(%d)", ret);
1117 new_output = E_NEW(E_EomOutput, 1);
1118 GOTOIFTRUE(new_output == NULL,
1122 ret = tdm_output_get_conn_status(output, &status);
1123 if (ret != TDM_ERROR_NONE)
1125 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1130 new_output->type = type;
1131 new_output->status = status;
1132 new_output->mode = EOM_OUTPUT_MODE_NONE;
1133 new_output->output = output;
1135 ret = tdm_output_add_change_handler(output, _e_eom_cb_tdm_output_status_change, NULL);
1136 if (ret != TDM_ERROR_NONE)
1138 EOM_ERR("tdm_output_add_change_handler fail(%d)", ret);
1144 e_comp_hwc_disable_output_hwc_rendering(i, 0);
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);
1347 eom_output->state = NONE;
1351 _e_eom_output_deinit(E_EomOutputPtr eom_output)
1353 tdm_error err = TDM_ERROR_NONE;
1354 E_EomClientPtr iterator = NULL;
1358 if (eom_output->layer)
1360 err = tdm_layer_unset_buffer(eom_output->layer);
1361 if (err != TDM_ERROR_NONE)
1362 EOM_DBG("fail unset buffer:%d", err);
1364 err = tdm_output_commit(eom_output->output, 0, NULL, eom_output);
1365 if (err != TDM_ERROR_NONE)
1366 EOM_DBG ("fail commit:%d", err);
1369 /* TODO: do I need to do DPMS off? */
1371 err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_OFF);
1372 if (err != TDM_ERROR_NONE)
1373 EOM_ERR("set DPMS off:%d", err);
1375 for (i = 0; i < NUM_MAIN_BUF; i++)
1377 tdm_buffer_remove_release_handler(eom_output->dst_buffers[i],
1378 _e_eom_cb_pp, eom_output);
1380 if (eom_output->dst_buffers[i])
1381 tbm_surface_destroy(eom_output->dst_buffers[i]);
1384 if (g_eom->main_output_state == DOWN)
1385 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1387 if (iterator && iterator->output_id == eom_output->id)
1388 _e_eom_client_free_buffers(iterator);
1393 _e_eom_output_get_layer(E_EomOutputPtr eom_output)
1397 tdm_layer *layer = NULL;
1398 tdm_error err = TDM_ERROR_NONE;
1399 tdm_layer_capability capa;
1400 tdm_info_layer layer_info;
1402 RETURNVALIFTRUE(eom_output == NULL, NULL, "eom_output is NULL");
1403 RETURNVALIFTRUE(eom_output->output == NULL, NULL, "eom_output->output is NULL");
1405 err = tdm_output_get_layer_count(eom_output->output, &count);
1406 if (err != TDM_ERROR_NONE)
1408 EOM_DBG ("tdm_output_get_layer_count fail(%d)", err);
1412 for (i = 0; i < count; i++)
1414 layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err);
1415 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_output_get_layer fail(%d)", err);
1417 err = tdm_layer_get_capabilities(layer, &capa);
1418 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_get_capabilities fail(%d)", err);
1420 if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
1422 EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d", i);
1427 memset(&layer_info, 0x0, sizeof(tdm_info_layer));
1428 layer_info.src_config.size.h = eom_output->width;
1429 layer_info.src_config.size.v = eom_output->height;
1430 layer_info.src_config.pos.x = 0;
1431 layer_info.src_config.pos.y = 0;
1432 layer_info.src_config.pos.w = eom_output->width;
1433 layer_info.src_config.pos.h = eom_output->height;
1434 layer_info.src_config.format = TBM_FORMAT_ARGB8888;
1435 layer_info.dst_pos.x = 0;
1436 layer_info.dst_pos.y = 0;
1437 layer_info.dst_pos.w = eom_output->width;
1438 layer_info.dst_pos.h = eom_output->height;
1439 layer_info.transform = TDM_TRANSFORM_NORMAL;
1441 err = tdm_layer_set_info(layer, &layer_info);
1442 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_set_info fail(%d)", err);
1447 static E_EomOutputPtr
1448 _e_eom_output_get_by_id(int id)
1451 E_EomOutputPtr output;
1453 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1455 if (output && output->id == id)
1463 _e_eom_output_start_pp(E_EomOutputPtr eom_output)
1465 /* should be changed in HWC enable environment */
1466 tbm_surface_info_s src_buffer_info;
1467 tbm_surface_h src_buffer = NULL;
1468 Eina_Bool ret = EINA_FALSE;
1470 src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
1471 RETURNVALIFTRUE(src_buffer == NULL, EINA_FALSE, "Get root tdm surfcae");
1473 tbm_surface_get_info(src_buffer, &src_buffer_info);
1475 EOM_DBG("main output info: %dx%d bpp:%d size:%d",
1476 src_buffer_info.width, src_buffer_info.height,
1477 src_buffer_info.bpp, src_buffer_info.size);
1479 /* TODO: if internal and external outputs are equal */
1480 ret = _e_eom_pp_is_needed(g_eom->width, g_eom->height,
1481 eom_output->width, eom_output->height);
1482 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_TRUE, "pp is not required");
1484 ret = _e_eom_pp_init(eom_output, src_buffer);
1485 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_FALSE, "Init pp");
1491 _e_eom_output_create_buffers(E_EomOutputPtr eom_output, int width, int height)
1495 /* TODO: Add support for other formats */
1496 for (i = 0; i < NUM_MAIN_BUF; i++)
1498 eom_output->dst_buffers[i] = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1499 GOTOIFTRUE(eom_output->dst_buffers[i] == NULL, err, "Create dst buffer");
1502 eom_output->dummy_buffer = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1503 GOTOIFTRUE(eom_output->dummy_buffer == NULL, err, "Create dummy buffer");
1508 for (i = 0; i < NUM_MAIN_BUF; i++)
1509 if (eom_output->dst_buffers[i])
1510 tbm_surface_destroy(eom_output->dst_buffers[i]);
1516 _e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec)
1518 E_EomOutputPtr eom_output = NULL;
1519 E_EomClientPtr eom_client = NULL;
1520 E_Comp_Client_Data *cdata = NULL;
1521 Eina_Bool ret = EINA_FALSE;
1523 if (resource == NULL || output_id <= 0 || ec == NULL)
1526 cdata = ec->comp_data;
1527 RETURNIFTRUE(cdata == NULL, "cdata is NULL");
1528 RETURNIFTRUE(cdata->shell.configure_send == NULL, "cdata->shell.configure_send is NULL");
1530 eom_client = _e_eom_client_get_by_resource(resource);
1531 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
1533 eom_output = _e_eom_output_get_by_id(output_id);
1534 RETURNIFTRUE(eom_output == NULL, "eom_output is NULL");
1536 ret = _e_eom_util_add_comp_object_redirected_hook(ec);
1537 RETURNIFTRUE(ret != EINA_TRUE, "Set redirect comp hook failed");
1539 EOM_DBG("e_comp_object_redirected_set (ec->frame:%p)\n", ec->frame);
1541 /* Send reconfigure event to a client which will resize its window to
1542 * external output resolution in respond */
1543 cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height);
1545 /* ec is used in buffer_change callback for distinguishing external ec and its buffers */
1546 eom_client->ec = ec;
1548 if (eom_client->current == EINA_TRUE)
1549 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_NONE);
1551 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_OUTPUT_OCCUPIED);
1555 _e_eom_pp_init(E_EomOutputPtr eom_output, tbm_surface_h src_buffer)
1557 tdm_error err = TDM_ERROR_NONE;
1558 tdm_info_pp pp_info;
1562 pp = tdm_display_create_pp(g_eom->dpy, &err);
1563 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Create pp:%d", err);
1565 eom_output->pp = pp;
1567 /* TODO : consider rotation */
1568 _e_eom_util_calculate_fullsize(g_eom->width, g_eom->height,
1569 eom_output->width, eom_output->height,
1572 EOM_DBG("PP calculation: x:%d, y:%d, w:%d, h:%d", x, y, w, h);
1574 pp_info.src_config.size.h = g_eom->width;
1575 pp_info.src_config.size.v = g_eom->height;
1576 pp_info.src_config.pos.x = 0;
1577 pp_info.src_config.pos.y = 0;
1578 pp_info.src_config.pos.w = g_eom->width;
1579 pp_info.src_config.pos.h = g_eom->height;
1580 pp_info.src_config.format = TBM_FORMAT_ARGB8888;
1582 pp_info.dst_config.size.h = eom_output->width;
1583 pp_info.dst_config.size.v = eom_output->height;
1584 pp_info.dst_config.pos.x = x;
1585 pp_info.dst_config.pos.y = y;
1586 pp_info.dst_config.pos.w = w;
1587 pp_info.dst_config.pos.h = h;
1588 pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
1590 /* TO DO : get rotation */
1591 pp_info.transform = TDM_TRANSFORM_NORMAL;
1595 err = tdm_pp_set_info(pp, &pp_info);
1596 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp info:%d", err);
1598 eom_output->pp_buffer = !eom_output->current_buffer;
1599 err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
1600 _e_eom_cb_pp, eom_output);
1601 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp handler:%d", err);
1603 err = tdm_pp_attach(pp, src_buffer,
1604 eom_output->dst_buffers[eom_output->pp_buffer]);
1605 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp attach:%d", err);
1607 err = tdm_pp_commit(eom_output->pp);
1608 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp commit:%d", err);
1614 _e_eom_pp_is_needed(int src_w, int src_h, int dst_w, int dst_h)
1626 _e_eom_util_get_debug_env()
1628 char *env = getenv("EOM_SERVER_DEBUG");
1632 eom_server_debug_on =(atoi(env)) > 0 ? EINA_TRUE : EINA_FALSE;
1634 eom_server_debug_on = EINA_FALSE;
1636 EOM_INF("EOM_SERVER_DEBUG = %s", eom_server_debug_on > 0 ? "ON" : "OFF");
1639 static tbm_surface_h
1640 _e_eom_util_create_buffer(int width, int height, int format, int flags)
1642 tbm_surface_info_s buffer_info;
1643 tbm_surface_h buffer = NULL;
1645 buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
1646 RETURNVALIFTRUE(buffer == NULL, NULL, "Create buffer");
1648 memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
1649 if (tbm_surface_map(buffer,
1650 TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
1651 &buffer_info) != TBM_SURFACE_ERROR_NONE)
1653 EOM_ERR("map buffer");
1654 tbm_surface_destroy(buffer);
1658 memset(buffer_info.planes[0].ptr, 0x0, buffer_info.planes[0].size);
1659 tbm_surface_unmap(buffer);
1664 static E_EomClientBufferPtr
1665 _e_eom_util_create_client_buffer(E_EomClientPtr client, E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1667 E_EomClientBufferPtr buffer = NULL;
1669 buffer = E_NEW(E_EomClientBuffer, 1);
1670 RETURNVALIFTRUE(buffer == NULL, NULL, "Allocate new client buffer")
1672 /* TODO: Internal and External frame rate are same */
1674 /* Forbid E sending 'wl_buffer_send_release' event to external clients */
1677 buffer->wl_buffer = wl_buffer;
1678 buffer->tbm_buffer = tbm_buffer;
1680 EOM_DBG("new client buffer wl:%p tbm:%p",
1681 buffer->wl_buffer, buffer->tbm_buffer);
1684 buffer->stamp = _e_eom_util_get_stamp();
1690 static tbm_surface_h
1691 _e_eom_util_get_output_surface(const char *name)
1693 Ecore_Drm_Output *primary_output = NULL;
1694 Ecore_Drm_Device *dev;
1696 tdm_output *tdm_output_obj = NULL;
1697 tbm_surface_h tbm = NULL;
1698 tdm_error err = TDM_ERROR_NONE;
1699 int count = 0, i = 0;
1701 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1703 primary_output = ecore_drm_device_output_name_find(dev, name);
1704 if (primary_output != NULL)
1708 if (primary_output == NULL)
1710 EOM_ERR("Get primary output.(%s)", name);
1711 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1713 primary_output = ecore_drm_output_primary_get(dev);
1714 if (primary_output != NULL)
1718 if (primary_output == NULL)
1720 EOM_ERR("Get primary output.(%s)", name);
1725 tdm_output_obj = tdm_display_get_output(g_eom->dpy, 0, &err);
1726 if (tdm_output_obj == NULL || err != TDM_ERROR_NONE)
1728 EOM_ERR("tdm_display_get_output 0 fail");
1731 err = tdm_output_get_layer_count(tdm_output_obj, &count);
1732 if (err != TDM_ERROR_NONE)
1734 EOM_ERR("tdm_output_get_layer_count fail");
1738 for (i = 0; i < count; i++)
1740 tdm_layer *layer = tdm_output_get_layer(tdm_output_obj, i, NULL);
1741 tdm_layer_capability capabilities = 0;
1742 tdm_layer_get_capabilities(layer, &capabilities);
1743 if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1745 tbm = tdm_layer_get_displaying_buffer(layer, &err);
1746 if (err != TDM_ERROR_NONE)
1748 EOM_ERR("tdm_layer_get_displaying_buffer fail");
1759 _e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v,
1760 int *dst_x, int *dst_y, int *dst_w, int *dst_h)
1762 double h_ratio, v_ratio;
1764 h_ratio = src_h / dst_size_h;
1765 v_ratio = src_v / dst_size_v;
1767 if (h_ratio == v_ratio)
1771 *dst_w = dst_size_h;
1772 *dst_h = dst_size_v;
1774 else if (h_ratio < v_ratio)
1777 *dst_h = dst_size_v;
1778 *dst_w = dst_size_v * src_h / src_v;
1779 *dst_x = (dst_size_h - *dst_w) / 2;
1781 else /* (h_ratio > v_ratio) */
1784 *dst_w = dst_size_h;
1785 *dst_h = dst_size_h * src_h / src_v;
1786 *dst_y = (dst_size_v - *dst_h) / 2;
1791 _e_eom_util_add_comp_object_redirected_hook(E_Client *ec)
1793 E_EomCompObjectInterceptHookData *hook_data = NULL;
1794 E_Comp_Object_Intercept_Hook *hook = NULL;
1796 hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1);
1797 GOTOIFTRUE(hook_data == NULL, err, "hook_data = NULL");
1801 hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,
1802 _e_eom_cb_comp_object_redirected,
1804 GOTOIFTRUE(hook == NULL, err, "hook = NULL");
1806 hook_data->hook = hook;
1808 g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks,
1811 EOM_DBG("_e_eom_redirected_hook have been added");
1822 _e_eom_util_get_stamp()
1826 clock_gettime(CLOCK_MONOTONIC, &tp);
1828 return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1838 _e_eom_util_draw(tbm_surface_h surface)
1840 unsigned char rw = 0, gw = 0, bw = 0, aw = 0;
1841 unsigned char r = 255, g = 255, b = 255, a = 0;
1843 unsigned int *mm = NULL;
1846 int w = (int)tbm_surface_get_width(surface);
1847 int h = (int)tbm_surface_get_height(surface);
1849 tbm_bo bo = tbm_surface_internal_get_bo(surface, 0);
1850 RETURNIFTRUE(bo == NULL, "bo is NULL");
1852 mm = (unsigned int *)tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE).ptr;
1853 RETURNIFTRUE(mm == NULL, "mm is NULL");
1855 for (i = 0; i < h; i++)
1856 for (j = 0; j < w; j++)
1858 if (j > square_x && j < square_x + square_w)
1859 mm[i*w + j] = r << 24 | g << 16 | b << 8 | a;
1861 mm[i*w + j] = rw << 24 | gw << 16 | bw << 8 | aw;
1865 if (square_x + square_w> w)
1872 static void _e_eom_util_check_frames(E_EomOutputPtr eom_output)
1875 static int first = 1;
1877 eom_output->num_frames += 1;
1878 res = gettimeofday(&eom_output->curr, NULL);
1881 EOM_ERR("gettimeofday");
1885 if (eom_output->curr.tv_sec > eom_output->prev.tv_sec && !first)
1887 EOM_DBG("FPS:%d", eom_output->num_frames);
1889 eom_output->num_frames = 0;
1890 eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1891 eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1895 eom_output->prev.tv_sec = eom_output->curr.tv_sec;
1896 eom_output->prev.tv_usec = eom_output->curr.tv_usec;
1903 _e_eom_client_add_buffer(E_EomClientPtr client, E_EomClientBufferPtr buffer)
1905 client->buffers_show = eina_list_append(client->buffers_show, buffer);
1909 _e_eom_client_free_buffers(E_EomClientPtr client)
1911 E_EomClientBufferPtr buffer = NULL;
1914 EINA_LIST_FOREACH(client->buffers_show, l, buffer)
1918 client->buffers_show = eina_list_remove(client->buffers_show, buffer);
1920 /* TODO: not sure if it is necessary */
1921 if (buffer->tbm_buffer && client->first_buffer == EINA_FALSE)
1922 tbm_surface_internal_unref(buffer->tbm_buffer);
1924 /* TODO: not sure if it is necessary */
1925 if (buffer->wl_buffer)
1926 buffer->wl_buffer->busy--;
1932 EINA_LIST_FOREACH(client->buffers_del, l, buffer)
1936 client->buffers_del= eina_list_remove(client->buffers_del, buffer);
1938 /* TODO: not sure if it is necessary */
1939 if (buffer->tbm_buffer)
1940 tbm_surface_internal_unref(buffer->tbm_buffer);
1942 /* TODO: not sure if it is necessary */
1943 if (buffer->wl_buffer)
1944 buffer->wl_buffer->busy--;
1951 static E_EomClientBufferPtr
1952 _e_eom_client_get_buffer(E_EomClientPtr client)
1954 E_EomClientBufferPtr show_buffer = NULL;
1955 E_EomClientBufferPtr prev_buffer = NULL;
1956 E_EomClientBufferPtr del_buffer = NULL;
1959 /* TODO: is it possible that a client has only one buffet to draw too? */
1960 RETURNVALIFTRUE(eina_list_count(client->buffers_show) == 0, NULL,
1961 "eom client (%p) do not have buffers to be shown", client);
1963 /* If there is only one buffer we have slow client, just return the buffer */
1964 if (eina_list_count(client->buffers_show) == 1)
1966 show_buffer = eina_list_nth(client->buffers_show, 0);
1967 RETURNVALIFTRUE(show_buffer == NULL, NULL,
1968 "eom client (%p) buffer is NULL", client);
1970 EOM_DBG("one wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1975 if (client->first_buffer == EINA_TRUE)
1977 show_buffer= eina_list_nth(client->buffers_show, 0);
1978 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) first buffer is NULL", client);
1980 EOM_DBG("first wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1982 /* I am not sure if it is necessary */
1983 EOM_DBG("ref first");
1984 tbm_surface_internal_ref(show_buffer->tbm_buffer);
1986 client->first_buffer = EINA_FALSE;
1990 EINA_LIST_FOREACH(client->buffers_del, l, del_buffer)
1994 client->buffers_del = eina_list_remove(client->buffers_del, del_buffer);
1996 if (del_buffer->wl_buffer)
1998 del_buffer->wl_buffer->busy--;
1999 EOM_DBG("wl_buffer:%p busy:%d", del_buffer->wl_buffer, del_buffer->wl_buffer->busy);
2000 if (del_buffer->wl_buffer->busy == 0)
2002 if (del_buffer->wl_buffer->type != E_COMP_WL_BUFFER_TYPE_TBM)
2004 if (!wl_resource_get_client(del_buffer->wl_buffer->resource))
2006 EOM_DBG("wl_buffer->resource is NULL");
2010 wl_buffer_send_release(del_buffer->wl_buffer->resource);
2015 EOM_DBG("del wl:%p tbm:%p", del_buffer->wl_buffer, del_buffer->tbm_buffer);
2017 if (del_buffer->tbm_buffer)
2019 EOM_DBG("del unref");
2020 tbm_surface_internal_unref(del_buffer->tbm_buffer);
2023 /* TODO: should wl_buffer and tbm_surface be deleted here? */
2028 /* TODO: case of 2 or n buffers */
2029 prev_buffer = eina_list_nth(client->buffers_show, 0);
2030 RETURNVALIFTRUE(prev_buffer == NULL, NULL, "eom client (%p) old_buffer is NULL", client);
2032 EOM_DBG("old wl:%p tbm:%p", prev_buffer->wl_buffer, prev_buffer->tbm_buffer);
2034 client->buffers_show = eina_list_remove(client->buffers_show, prev_buffer);
2035 client->buffers_del = eina_list_append(client->buffers_del, prev_buffer);
2037 /* Take next buffer to be shown on external output */
2038 show_buffer = eina_list_nth(client->buffers_show, 0);
2039 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) next buffer is NULL", client);
2041 EOM_DBG("show wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
2043 if (show_buffer->tbm_buffer)
2045 EOM_DBG("show ref");
2046 tbm_surface_internal_ref(show_buffer->tbm_buffer);
2052 static E_EomClientPtr
2053 _e_eom_client_get_by_resource(struct wl_resource *resource)
2056 E_EomClientPtr client;
2058 EINA_LIST_FOREACH(g_eom->clients, l, client)
2060 if (client && client->resource == resource)
2067 static E_EomClientPtr
2068 _e_eom_client_get_current_by_id(int id)
2071 E_EomClientPtr client;
2073 EINA_LIST_FOREACH(g_eom->clients, l, client)
2076 client->current == EINA_TRUE &&
2077 client->output_id == id)
2084 static E_EomClientPtr
2085 _e_eom_client_get_current_by_ec(E_Client *ec)
2088 E_EomClientPtr client;
2090 EINA_LIST_FOREACH(g_eom->clients, l, client)
2093 client->current == EINA_TRUE &&
2104 Eina_Bool ret = EINA_FALSE;
2106 _e_eom_util_get_debug_env();
2108 EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
2110 g_eom = E_NEW(E_Eom, 1);
2111 EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
2113 g_eom->global = wl_global_create(e_comp_wl->wl.disp,
2119 uint32_t id = wl_display_get_serial(e_comp_wl->wl.disp);
2120 EOM_DBG("eom name: %d", id);
2122 EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
2124 ret = _e_eom_init_internal();
2125 GOTOIFTRUE(ret == EINA_FALSE, err, "init_internal() failed");
2127 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_cb_ecore_drm_activate, g_eom);
2128 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT, _e_eom_cb_ecore_drm_output, g_eom);
2129 E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL);
2131 g_eom->main_output_name = NULL;
2141 _e_eom_init_internal()
2143 tdm_error ret = TDM_ERROR_NONE;
2145 g_eom->dpy = tdm_display_init(&ret);
2146 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_init fail");
2148 ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
2149 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_get_fd fail");
2151 g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
2152 GOTOIFTRUE(g_eom->bufmgr == NULL, err, "tbm_bufmgr_init fail");
2154 if (_e_eom_output_init(g_eom->dpy) != EINA_TRUE)
2156 EOM_ERR("_e_eom_output_init fail");
2164 tbm_bufmgr_deinit(g_eom->bufmgr);
2167 tdm_display_deinit(g_eom->dpy);
2175 Ecore_Event_Handler *h = NULL;
2177 if (g_eom == NULL) return;
2179 if (g_eom->handlers)
2181 EINA_LIST_FREE(g_eom->handlers, h)
2182 ecore_event_handler_del(h);
2185 if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
2186 if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
2188 if (g_eom->global) wl_global_destroy(g_eom->global);
2194 e_modapi_init(E_Module *m)
2196 return (_e_eom_init() ? m : NULL);
2200 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2207 e_modapi_save(E_Module *m EINA_UNUSED)
2209 /* Save something to be kept */