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>
14 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "EOM Module" };
15 static E_EomPtr g_eom = NULL;
16 Eina_Bool eom_server_debug_on = EINA_FALSE;
18 #ifdef DUMP_PRESENTATION
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);
188 wl_eom_send_output_attribute(resource,
190 _e_eom_output_state_get_attribute(output),
191 _e_eom_output_state_get_attribute_state(output),
196 new_client = E_NEW(E_EomClient, 1);
197 RETURNIFTRUE(new_client == NULL, "Allocate new client")
199 new_client->resource = resource;
200 new_client->current = EINA_FALSE;
201 new_client->output_id = -1;
202 new_client->ec = NULL;
203 new_client->buffers_show = NULL;
204 new_client->buffers_del = NULL;
205 new_client->first_buffer = EINA_TRUE;
207 g_eom->clients = eina_list_append(g_eom->clients, new_client);
211 _e_eom_cb_wl_resource_destory(struct wl_resource *resource)
213 E_EomClientPtr client = NULL, iterator = NULL;
214 E_EomOutputPtr output = NULL;
218 EOM_DBG("client unbind");
220 client = _e_eom_client_get_by_resource(resource);
221 RETURNIFTRUE(client == NULL, "eom client is NULL");
223 g_eom->clients = eina_list_remove(g_eom->clients, client);
225 /* If it is not current client do nothing */
226 if (client->current == EINA_FALSE)
229 output = _e_eom_output_get_by_id(client->output_id);
230 GOTOIFTRUE(output == NULL, end2, "output is NULL");
232 _e_eom_output_state_set_mode(output, EOM_OUTPUT_MODE_MIRROR);
233 ret = _e_eom_output_state_set_attribute(output, EOM_OUTPUT_ATTRIBUTE_NONE);
236 _e_eom_client_free_buffers(client);
238 /* TODO: process case when output is not connected */
239 if (output->state == NONE)
242 /* If a client has been disconnected and mirror mode has not
243 * been restored, start mirror mode
245 if (output->state != MIRROR)
247 output->state = MIRROR;
249 ret = _e_eom_output_start_pp(output);
250 GOTOIFTRUE(ret == EINA_FALSE, end,
251 "Restore mirror mode after a client disconnection");
255 /* Notify eom clients which are binded to a concrete output that the
256 * state and mode of the output has been changed */
257 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
259 if (iterator && iterator->output_id == output->id)
261 wl_eom_send_output_attribute(iterator->resource,
263 _e_eom_output_state_get_attribute(output),
264 _e_eom_output_state_get_attribute_state(output),
265 EOM_OUTPUT_MODE_NONE);
267 wl_eom_send_output_mode(iterator->resource,
269 _e_eom_output_state_get_mode(output));
278 _e_eom_cb_ecore_drm_output(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
280 Ecore_Drm_Event_Output *e = NULL;
283 if (!(e = event)) return ECORE_CALLBACK_PASS_ON;
285 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",
286 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);
288 snprintf(buff, sizeof(buff), "%s", e->name);
296 g_eom->height = e->h;
297 if (g_eom->main_output_name == NULL)
298 g_eom->main_output_name = strdup(buff);
300 g_eom->main_output_state = UP;
306 if (g_eom->main_output_name)
307 free(g_eom->main_output_name);
309 g_eom->main_output_state = DOWN;
313 return ECORE_CALLBACK_PASS_ON;
317 _e_eom_cb_ecore_drm_activate(void *data, int type EINA_UNUSED, void *event)
320 Ecore_Drm_Event_Activate *e = NULL;
323 EOM_DBG("_e_eom_cb_ecore_drm_activate called");
325 if ((!event) || (!data)) goto end;
329 EOM_DBG("e->active:%d", e->active);
343 return ECORE_CALLBACK_PASS_ON;
347 _e_eom_cb_client_buffer_change(void *data, int type, void *event)
349 E_Comp_Wl_Buffer *external_wl_buffer = NULL;
350 E_EomClientBufferPtr client_buffer = NULL;
351 E_EomClientPtr eom_client = NULL;
352 E_EomOutputPtr eom_output = NULL;
353 E_Event_Client *ev = event;
355 tbm_surface_h external_tbm_buffer = NULL;
357 tbm_surface_info_s surface_info;
361 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
362 EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
365 RETURNVALIFTRUE(e_object_is_del(E_OBJECT(ec)),
366 ECORE_CALLBACK_PASS_ON,
367 "ec objects is del");
369 eom_client = _e_eom_client_get_current_by_ec(ec);
370 if (eom_client== NULL)
371 return ECORE_CALLBACK_PASS_ON;
373 RETURNVALIFTRUE(eom_client == NULL,
374 ECORE_CALLBACK_PASS_ON,
375 "Current client is NULL");
378 eom_output = _e_eom_output_get_by_id(eom_client->output_id);
379 RETURNVALIFTRUE(eom_output == NULL,
380 ECORE_CALLBACK_PASS_ON,
381 "eom_output is NULL");
383 if (ec->pixmap == NULL)
384 return ECORE_CALLBACK_PASS_ON;
386 external_wl_buffer = e_pixmap_resource_get(ec->pixmap);
387 RETURNVALIFTRUE(external_wl_buffer == NULL,
388 ECORE_CALLBACK_PASS_ON,
389 "wl buffer is NULL");
390 RETURNVALIFTRUE(external_wl_buffer->resource == NULL,
391 ECORE_CALLBACK_PASS_ON,
395 EOM_DBG("wl_buff:%p type:%d %dx%d ",
397 external_wl_buffer->type,
398 external_wl_buffer->w,
399 external_wl_buffer->h,
403 /* Since Enlightenment client has reconfigured its window to fit
404 * external output resolution and Enlightenment no nothing about
405 * external outputs Enlightenment sees that client's resolution
406 * differs form main screen resolution. Therefore, Enlightenment
407 * is trying to resize it back to main screen resolution. It uses
408 * timer for that purpose. To forbid it just delte the timer */
410 /* TODO: it works but maybe there is better solution exists ?
411 * Also I do not know how it affects on performance */
414 EOM_DBG("delete map_timer");
415 E_FREE_FUNC(ec->map_timer, ecore_timer_del);
418 /* TODO: support buffers smaller then output resolution */
419 if (external_wl_buffer->w != eom_output->width ||
420 external_wl_buffer->h != eom_output->height )
422 EOM_ERR("tbm_buffer does not fit output's resolution");
423 return ECORE_CALLBACK_PASS_ON;
426 /* TODO: support different external_wl_buffer->type */
428 external_tbm_buffer = wayland_tbm_server_get_surface(
429 e_comp->wl_comp_data->tbm.server,
430 external_wl_buffer->resource);
431 RETURNVALIFTRUE(external_tbm_buffer == NULL,
432 ECORE_CALLBACK_PASS_ON,
433 "Client tbm buffer is NULL");
435 /* EOM_DBG("tbm_buffer %p", external_tbm_buffer); */
438 _e_eom_util_draw(external_tbm_buffer);
441 EOM_DBG("BUFF_CHANGE >>>>>>>>>>");
442 client_buffer = _e_eom_util_create_client_buffer(eom_client, external_wl_buffer, external_tbm_buffer);
443 RETURNVALIFTRUE(client_buffer == NULL,
444 ECORE_CALLBACK_PASS_ON,
445 "Alloc client buffer");
447 _e_eom_client_add_buffer(eom_client, client_buffer);
448 EOM_DBG("BUFF_CHANGE <<<<<<<<<<");
450 eom_output->state = PRESENTATION;
452 return ECORE_CALLBACK_PASS_ON;
456 _e_eom_cb_pp(tbm_surface_h surface, void *user_data)
458 tdm_error tdm_err = TDM_ERROR_NONE;
459 E_EomOutputPtr eom_output = NULL;
461 eom_output = (E_EomOutputPtr)user_data;
462 RETURNIFTRUE(user_data == NULL, "pp event: user data is NULL");
464 tdm_buffer_remove_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
465 _e_eom_cb_pp, eom_output);
467 /* TODO: lock these flags??? */
468 if (g_eom->main_output_state == DOWN)
471 /* If a client has committed its buffer stop mirror mode */
472 if (eom_output->state != MIRROR)
475 tbm_surface_h src_buffer;
476 src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
477 RETURNIFTRUE(src_buffer == NULL, "pp event: get root tdm surface");
479 /*TODO: rewrite the mirror mode buffer's switching */
480 eom_output->pp_buffer ^= 1;
482 tdm_err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
483 _e_eom_cb_pp, eom_output);
484 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: set pp hadler:%d", tdm_err );
486 tdm_err = tdm_pp_attach(eom_output->pp, src_buffer, eom_output->dst_buffers[eom_output->pp_buffer]);
487 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp attach:%d", tdm_err);
489 tdm_err = tdm_pp_commit(eom_output->pp);
490 RETURNIFTRUE(tdm_err != TDM_ERROR_NONE, "pp event: commit:%d", tdm_err );
494 _e_eom_cb_commit(tdm_output *output EINA_UNUSED, unsigned int sequence EINA_UNUSED,
495 unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED,
498 E_EomClientBufferPtr client_buffer = NULL;
499 E_EomOutputPtr eom_output = NULL;
500 E_EomClientPtr eom_client = NULL;
501 tdm_error err = TDM_ERROR_NONE;
502 tbm_surface_h external_buffer = NULL;
504 eom_output = (E_EomOutputPtr)user_data;
505 RETURNIFTRUE(user_data == NULL, "commit event: user data is NULL");
507 if (g_eom->main_output_state == DOWN)
510 /* TODO: Maybe better to separating that callback on to mirror and extended callbacks */
511 if (eom_output->state == MIRROR)
513 /*TODO: rewrite the mirror mode buffer's switching */
514 eom_output->current_buffer ^= 1;
515 err = tdm_layer_set_buffer(eom_output->layer,
516 eom_output->dst_buffers[eom_output->current_buffer]);
518 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: set buffer 0 err:%d", err);
520 err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
521 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: mirror: commit err:%d", err);
523 else if (eom_output->state == PRESENTATION)
525 eom_client = _e_eom_client_get_current_by_id(eom_output->id);
527 EOM_DBG("COMMIT +++++++++++++++>");
529 client_buffer = _e_eom_client_get_buffer(eom_client);
530 if (client_buffer == NULL)
532 external_buffer = eom_output->dummy_buffer;
533 EOM_DBG("substitute dummy buffer");
536 external_buffer = client_buffer->tbm_buffer;
539 EOM_DBG("COMMIT draw and set dummy");
541 _e_eom_util_draw(eom_output->dummy_buffer);
542 external_buffer = eom_output->dummy_buffer;
545 #ifdef DUMP_PRESENTATION
548 tbm_surface_internal_dump_buffer(external_buffer, "kyky");
553 tbm_surface_internal_dump_end();
558 err = tdm_layer_set_buffer(eom_output->layer, external_buffer);
559 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: set buffer");
561 err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
562 RETURNIFTRUE(err != TDM_ERROR_NONE, "commit event: presentation: commit err:%d", err);
564 EOM_DBG("COMMIT <+++++++++++++++");
569 _e_eom_cb_tdm_output_status_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
571 tdm_output_type tdm_type;
572 tdm_error ret = TDM_ERROR_NONE;
573 tdm_output_conn_status status;
574 tdm_output_conn_status status2;
575 const char *maker = NULL, *model = NULL, *name = NULL;
576 const char *tmp_name;
577 char new_name[DRM_CONNECTOR_NAME_LEN];
578 E_EomOutputPtr eom_output = NULL;
579 tdm_output_conn_status plug;
580 E_EomClientPtr iterator = NULL;
583 if (type == TDM_OUTPUT_CHANGE_DPMS || g_eom->main_output_state == DOWN)
589 E_EomOutputPtr eom_output_tmp;
591 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
593 if (eom_output_tmp->output == output)
594 eom_output = eom_output_tmp;
598 ret = tdm_output_get_output_type(output, &tdm_type);
599 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_output_type fail(%d)", ret);
601 ret = tdm_output_get_model_info(output, &maker, &model, &name);
602 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_model_info fail(%d)", ret);
604 ret = tdm_output_get_conn_status(output, &status);
605 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_conn_status fail(%d)", ret);
609 EOM_DBG("id (%d), type(%d, %d), status(%d, %d) (%s,%s,%s)", eom_output->id, type, tdm_type, status, status2, maker, model, name);
611 if (tdm_type < ALEN(eom_conn_types))
612 tmp_name = eom_conn_types[tdm_type];
614 tmp_name = "unknown";
615 /*TODO: What if there will more then one output of same type.
616 *e.g. "HDMI and HDMI" "LVDS and LVDS"*/
617 snprintf(new_name, sizeof(new_name), "%s-%d", tmp_name, 0);
621 if (plug == TDM_OUTPUT_CONN_STATUS_CONNECTED)
623 unsigned int mmWidth, mmHeight, subpixel;
624 const tdm_output_mode *mode;
627 ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
628 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_physical_size fail(%d)", ret);
630 ret = tdm_output_get_subpixel(output, &subpixel);
631 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_get_subpixel fail(%d)", ret);
633 mode = _e_eom_output_get_best_mode(output);
634 RETURNIFTRUE(mode == NULL, "_e_eom_get_best_resolution fail");
636 ret = tdm_output_set_mode(output, mode);
637 RETURNIFTRUE(ret != TDM_ERROR_NONE, "tdm_output_set_mode fail(%d)", ret);
639 x = _e_eom_output_get_position();
640 EOM_DBG("mode: %dx%d, phy(%dx%d), pos(%d,0), refresh:%d, subpixel:%d",
641 mode->hdisplay, mode->vdisplay, mmWidth, mmHeight, x, mode->vrefresh, subpixel);
643 /* model is substituted with new_name.
644 * It used to bind wl_output with eom_output in libeom. */
645 if (!e_comp_wl_output_init(new_name, maker, new_name, x, 0,
646 mode->hdisplay, mode->vdisplay,
647 mmWidth, mmHeight, mode->vrefresh, subpixel, 0))
649 EOM_ERR("Could not setup new output: %s", new_name);
652 EOM_DBG("Setup new output: %s", new_name);
654 /* update eom_output connect */
655 eom_output->width = mode->hdisplay;
656 eom_output->height = mode->vdisplay;
657 eom_output->phys_width = mmWidth;
658 eom_output->phys_height = mmHeight;
659 eom_output->status = plug;
660 eom_output->name = eina_stringshare_add(new_name);
661 eom_output->type = (eom_output_type_e)tdm_type;
663 /* TODO: check output mode(presentation set) and HDMI type */
664 _e_eom_output_start_mirror(eom_output);
666 /* If there were previously connected clients to the output - notify them */
667 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
671 EOM_DBG("Send MIRROR ON notification to clients");
673 wl_eom_send_output_info(iterator->resource, eom_output->id,
674 eom_output->type, eom_output->mode,
675 eom_output->width, eom_output->height,
676 eom_output->phys_width, eom_output->phys_height,
679 wl_eom_send_output_attribute(iterator->resource,
681 _e_eom_output_state_get_attribute(eom_output),
682 _e_eom_output_state_get_attribute_state(eom_output),
687 else if (plug == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
689 if (eom_output->state == MIRROR)
690 _e_eom_output_stop_mirror(eom_output);
692 /* update eom_output disconnect */
693 eom_output->width = 0;
694 eom_output->height = 0;
695 eom_output->phys_width = 0;
696 eom_output->phys_height = 0;
697 eom_output->status = plug;
699 /* If there were previously connected clients to the output - notify them */
700 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
704 EOM_DBG("Send MIRROR OFF notification to clients");
706 wl_eom_send_output_info(iterator->resource, eom_output->id,
707 eom_output->type, eom_output->mode,
708 eom_output->width, eom_output->height,
709 eom_output->phys_width, eom_output->phys_height,
712 wl_eom_send_output_attribute(iterator->resource,
714 _e_eom_output_state_get_attribute(eom_output),
715 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
720 e_comp_wl_output_remove(new_name);
721 EOM_DBG("Destory output: %s", new_name);
722 eina_stringshare_del(eom_output->name);
727 _e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute)
729 eom_error_e eom_error = EOM_ERROR_NONE;
730 E_EomClientPtr eom_client = NULL, current_eom_client = NULL, iterator = NULL;
731 E_EomOutputPtr eom_output = NULL;
732 Eina_Bool changes = EINA_FALSE;
733 Eina_Bool ret = EINA_FALSE;
736 eom_client = _e_eom_client_get_by_resource(resource);
737 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
739 /* Bind the client with a concrete output */
740 eom_client->output_id = output_id;
742 eom_output = _e_eom_output_get_by_id(output_id);
743 GOTOIFTRUE(eom_output == NULL, no_output, "eom_output is NULL");
745 EOM_DBG("Set attribute:%d", attribute);
747 if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id)
749 /* Current client can set any flag it wants */
750 _e_eom_output_state_set_force_attribute(eom_output, attribute);
755 /* A client is trying to set new attribute */
756 ret = _e_eom_output_state_set_attribute(eom_output, attribute);
757 if (ret == EINA_FALSE)
759 EOM_DBG("set attribute FAILED");
761 eom_error = EOM_ERROR_INVALID_PARAMETER;
768 /* If there was no new changes applied do nothing */
769 if (changes == EINA_FALSE)
771 EOM_DBG("no new changes");
775 EOM_DBG("set attribute OK");
777 /* If client has set EOM_OUTPUT_ATTRIBUTE_NONE switching to mirror mode */
778 if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR)
780 eom_output->state = MIRROR;
781 eom_client->current = EINA_FALSE;
783 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
784 ret = _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
787 _e_eom_client_free_buffers(eom_client);
789 if (eom_output->status == 0)
791 EOM_DBG("output:%d is disconnected", output_id);
795 ret = _e_eom_output_start_pp(eom_output);
796 GOTOIFTRUE(ret == EINA_FALSE, end,
797 "Restore mirror mode after disconnection of the client");
799 /* If mirror mode has been ran notify all clients about that */
800 EOM_DBG("client set NONE attribute send new info to previous current client");
801 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
803 if (iterator->output_id == output_id)
805 wl_eom_send_output_attribute(iterator->resource,
807 _e_eom_output_state_get_attribute(eom_output),
808 _e_eom_output_state_get_attribute_state(eom_output),
811 wl_eom_send_output_mode(iterator->resource,
813 _e_eom_output_state_get_mode(eom_output));
821 /* If client was not able to set attribute then send LOST event
822 * to it and return */
823 /* TODO: I think it is bad to send LOST event in that case
824 * Client must process eom_errors */
825 if (eom_error == EOM_ERROR_INVALID_PARAMETER)
827 EOM_DBG("client failed to set attribute");
829 wl_eom_send_output_attribute(eom_client->resource,
831 _e_eom_output_state_get_attribute(eom_output),
832 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
837 /* Send changes to the caller-client */
838 wl_eom_send_output_attribute(eom_client->resource,
840 _e_eom_output_state_get_attribute(eom_output),
841 _e_eom_output_state_get_attribute_state(eom_output),
844 /* Send changes to previous current client */
845 if (eom_client->current == EINA_FALSE &&
846 (current_eom_client = _e_eom_client_get_current_by_id(eom_output->id)))
848 current_eom_client->current = EINA_FALSE;
850 EOM_DBG("client failed to set attribute");
852 wl_eom_send_output_attribute(current_eom_client->resource,
854 _e_eom_output_state_get_attribute(eom_output),
855 EOM_OUTPUT_ATTRIBUTE_STATE_LOST,
859 /* Set the client as current client of the eom_output */
860 eom_client->current= EINA_TRUE;
864 /* Get here if EOM does not have output referred by output_id */
866 wl_eom_send_output_attribute(eom_client->resource,
868 EOM_OUTPUT_ATTRIBUTE_NONE,
869 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
870 EOM_ERROR_NO_SUCH_DEVICE);
872 wl_eom_send_output_mode(eom_client->resource,
874 EOM_OUTPUT_MODE_NONE);
876 wl_eom_send_output_type(eom_client->resource,
878 EOM_OUTPUT_ATTRIBUTE_STATE_NONE,
879 TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
883 /* TODO: It uses xdg_surface. Add support of shell_surface */
884 /* TODO: I think there must be implemented an event for client which signals if set window was successful */
886 _e_eom_cb_wl_request_set_xdg_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
890 if (resource == NULL || output_id <= 0 || surface == NULL)
893 EOM_DBG("set xdg output id:%d resource:%p surface:%p",
894 output_id, resource, surface);
896 if (!(ec = wl_resource_get_user_data(surface)))
898 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
899 "No Client For Shell Surface");
903 _e_eom_window_set_internal(resource, output_id, ec);
907 _e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface)
911 if (resource == NULL || output_id <= 0 || surface == NULL)
914 EOM_DBG("set shell output id:%d resource:%p surface:%p",
915 output_id, resource, surface);
917 if (!(ec = wl_resource_get_user_data(surface)))
919 wl_resource_post_error(surface,WL_DISPLAY_ERROR_INVALID_OBJECT,
920 "No Client For Shell Surface");
924 _e_eom_window_set_internal(resource, output_id, ec);
928 _e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id)
930 EOM_DBG("output:%d", output_id);
935 E_EomOutputPtr output = NULL;
937 EINA_LIST_FOREACH(g_eom->outputs, l, output)
939 if (output->id == output_id)
941 EOM_DBG("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d",
942 output->id, output->type, output->mode, output->width, output->height,
943 output->phys_width, output->phys_height, output->status);
945 wl_eom_send_output_info(resource, output->id, output->type, output->mode, output->width, output->height,
946 output->phys_width, output->phys_height, output->status);
953 _e_eom_cb_comp_object_redirected(void *data, E_Client *ec)
955 E_EomCompObjectInterceptHookData *hook_data;
957 EOM_DBG("_e_eom_cb_comp_object_redirected");
958 RETURNVALIFTRUE(data == NULL, EINA_TRUE, "data is NULL");
960 hook_data = (E_EomCompObjectInterceptHookData* )data;
962 RETURNVALIFTRUE(hook_data->ec == NULL, EINA_TRUE, "hook_data->ec is NULL");
963 RETURNVALIFTRUE(hook_data->hook == NULL, EINA_TRUE, "hook_data->hook is NULL");
964 RETURNVALIFTRUE(hook_data->ec != ec, EINA_TRUE, "hook_data->ec != ec");
966 /* Hide the window from Enlightenment main screen */
967 e_comp_object_redirected_set(ec->frame, EINA_FALSE);
969 e_comp_object_intercept_hook_del(hook_data->hook);
971 g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks,
980 _e_eom_output_init(tdm_display *dpy)
982 tdm_error ret = TDM_ERROR_NONE;
985 ret = tdm_display_get_output_count(dpy, &count);
986 RETURNVALIFTRUE(ret != TDM_ERROR_NONE,
988 "tdm_display_get_output_count fail");
989 RETURNVALIFTRUE(count <= 1,
991 "output count is 1. device doesn't support external outputs.");
993 g_eom->output_count = count - 1;
994 EOM_DBG("external output count : %d", g_eom->output_count);
996 /* skip main output id:0 */
998 for (i = 1; i < count; i++)
1000 const tdm_output_mode *mode = NULL;
1001 E_EomOutputPtr new_output = NULL;
1002 unsigned int mmWidth, mmHeight;
1003 tdm_output_conn_status status;
1004 tdm_output *output = NULL;
1005 tdm_output_type type;
1007 output = tdm_display_get_output(dpy, i, &ret);
1008 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1010 "tdm_display_get_output fail(ret:%d)", ret);
1012 GOTOIFTRUE(output == NULL,
1014 "tdm_display_get_output fail(no output:%d)", ret);
1016 ret = tdm_output_get_output_type(output, &type);
1017 GOTOIFTRUE(ret != TDM_ERROR_NONE,
1019 "tdm_output_get_output_type fail(%d)", ret);
1021 new_output = E_NEW(E_EomOutput, 1);
1022 GOTOIFTRUE(new_output == NULL,
1026 ret = tdm_output_get_conn_status(output, &status);
1027 if (ret != TDM_ERROR_NONE)
1029 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1034 new_output->type = type;
1035 new_output->status = status;
1036 new_output->mode = EOM_OUTPUT_MODE_NONE;
1037 new_output->output = output;
1039 ret = tdm_output_add_change_handler(output, _e_eom_cb_tdm_output_status_change, NULL);
1040 if (ret != TDM_ERROR_NONE)
1042 EOM_ERR("tdm_output_add_change_handler fail(%d)", ret);
1048 e_comp_hwc_disable_output_hwc_rendering(i, 0);
1051 if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1053 EOM_DBG("create(%d)output, type:%d, status:%d",
1054 new_output->id, new_output->type, new_output->status);
1055 g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1058 new_output->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1060 ret = tdm_output_get_mode(output, &mode);
1061 if (ret != TDM_ERROR_NONE)
1063 EOM_ERR("tdm_output_get_mode fail(%d)", ret);
1070 new_output->width = 0;
1071 new_output->height = 0;
1075 new_output->width = mode->hdisplay;
1076 new_output->height = mode->vdisplay;
1079 ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
1080 if (ret != TDM_ERROR_NONE)
1082 EOM_ERR("tdm_output_get_conn_status fail(%d)", ret);
1086 new_output->phys_width = mmWidth;
1087 new_output->phys_height = mmHeight;
1089 EOM_DBG("create(%d)output, type:%d, status:%d, w:%d, h:%d, mm_w:%d, mm_h:%d",
1090 new_output->id, new_output->type, new_output->status,
1091 new_output->width, new_output->height, new_output->phys_width, new_output->phys_height);
1093 g_eom->outputs = eina_list_append(g_eom->outputs, new_output);
1102 E_EomOutputPtr output;
1104 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1108 eina_list_free(g_eom->outputs);
1114 static const tdm_output_mode *
1115 _e_eom_output_get_best_mode(tdm_output *output)
1117 tdm_error ret = TDM_ERROR_NONE;
1118 const tdm_output_mode *modes;
1119 const tdm_output_mode *mode = NULL;
1120 /* unsigned int vrefresh = 0; */
1121 unsigned int best_value = 0;
1125 ret = tdm_output_get_available_modes(output, &modes, &count);
1126 if (ret != TDM_ERROR_NONE)
1128 EOM_ERR("tdm_output_get_available_modes fail(%d)", ret);
1132 for (i = 0; i < count; i++)
1134 value = modes[i].vdisplay + modes[i].hdisplay;
1135 if (value >= best_value)
1142 EOM_DBG("bestmode : %s, (%dx%d) r(%d), f(%d), t(%d)",
1143 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1149 _e_eom_output_get_position(void)
1151 tdm_output *output_main = NULL;
1152 const tdm_output_mode *mode;
1153 tdm_error ret = TDM_ERROR_NONE;
1156 output_main = tdm_display_get_output(g_eom->dpy, 0, &ret);
1157 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_display_get_output main fail(ret:%d)", ret);
1158 RETURNVALIFTRUE(output_main == NULL, 0, "tdm_display_get_output main fail(no output:%d)", ret);
1160 ret = tdm_output_get_mode(output_main, &mode);
1161 RETURNVALIFTRUE(ret != TDM_ERROR_NONE, 0, "tdm_output_get_mode main fail(ret:%d)", ret);
1171 E_EomOutputPtr eom_output_tmp;
1173 EINA_LIST_FOREACH(g_eom->outputs, l, eom_output_tmp)
1175 if (eom_output_tmp->status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
1176 x += eom_output_tmp->width;
1184 _e_eom_output_start_mirror(E_EomOutputPtr eom_output)
1186 tdm_layer *hal_layer;
1187 tdm_info_layer layer_info;
1188 tdm_error tdm_err = TDM_ERROR_NONE;
1191 if (eom_output->state == MIRROR)
1194 hal_layer = _e_eom_output_get_layer(eom_output);
1195 GOTOIFTRUE(hal_layer == NULL, err, "Get hal layer");
1197 ret = _e_eom_output_create_buffers(eom_output, eom_output->width, eom_output->height);
1198 GOTOIFTRUE(ret == EINA_FALSE, err, "Create buffers ");
1200 tdm_err = tdm_layer_get_info(hal_layer, &layer_info);
1201 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Get layer info: %d", tdm_err);
1203 EOM_DBG("layer info: %dx%d, pos (x:%d, y:%d, w:%d, h:%d, dpos (x:%d, y:%d, w:%d, h:%d))",
1204 layer_info.src_config.size.h, layer_info.src_config.size.v,
1205 layer_info.src_config.pos.x, layer_info.src_config.pos.y,
1206 layer_info.src_config.pos.w, layer_info.src_config.pos.h,
1207 layer_info.dst_pos.x, layer_info.dst_pos.y,
1208 layer_info.dst_pos.w, layer_info.dst_pos.h);
1210 eom_output->layer = hal_layer;
1211 eom_output->current_buffer = 0;
1213 tdm_err = tdm_layer_set_buffer(hal_layer, eom_output->dst_buffers[eom_output->current_buffer]);
1214 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Set buffer on layer:%d", tdm_err);
1216 tdm_err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_ON);
1217 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "tdm_output_set_dpms on");
1219 /* get main surface */
1220 ret = _e_eom_output_start_pp(eom_output);
1221 GOTOIFTRUE(ret == EINA_FALSE, err, "Get root surfcae");
1223 tdm_err = tdm_output_commit(eom_output->output, 0, _e_eom_cb_commit, eom_output);
1224 GOTOIFTRUE(tdm_err != TDM_ERROR_NONE, err, "Commit crtc:%d", tdm_err);
1226 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_MIRROR);
1227 _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
1228 eom_output->state = MIRROR;
1234 * TODO: add deinitialization
1240 _e_eom_output_stop_mirror(E_EomOutputPtr eom_output)
1242 if (eom_output->state == NONE)
1245 _e_eom_output_state_set_status(eom_output, TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
1246 _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE);
1247 _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE);
1249 _e_eom_output_deinit(eom_output);
1251 eom_output->state = NONE;
1255 _e_eom_output_deinit(E_EomOutputPtr eom_output)
1257 tdm_error err = TDM_ERROR_NONE;
1258 E_EomClientPtr iterator = NULL;
1262 if (eom_output->layer)
1264 err = tdm_layer_unset_buffer(eom_output->layer);
1265 if (err != TDM_ERROR_NONE)
1266 EOM_DBG("fail unset buffer:%d", err);
1268 err = tdm_output_commit(eom_output->output, 0, NULL, eom_output);
1269 if (err != TDM_ERROR_NONE)
1270 EOM_DBG ("fail commit:%d", err);
1273 /* TODO: do I need to do DPMS off? */
1275 err = tdm_output_set_dpms(eom_output->output, TDM_OUTPUT_DPMS_OFF);
1276 if (err != TDM_ERROR_NONE)
1277 EOM_ERR("set DPMS off:%d", err);
1279 for (i = 0; i < NUM_MAIN_BUF; i++)
1281 tdm_buffer_remove_release_handler(eom_output->dst_buffers[i],
1282 _e_eom_cb_pp, eom_output);
1284 if (eom_output->dst_buffers[i])
1285 tbm_surface_destroy(eom_output->dst_buffers[i]);
1288 if (g_eom->main_output_state == DOWN)
1289 EINA_LIST_FOREACH(g_eom->clients, l, iterator)
1291 if (iterator && iterator->output_id == eom_output->id)
1292 _e_eom_client_free_buffers(iterator);
1297 _e_eom_output_get_layer(E_EomOutputPtr eom_output)
1301 tdm_layer *layer = NULL;
1302 tdm_error err = TDM_ERROR_NONE;
1303 tdm_layer_capability capa;
1304 tdm_info_layer layer_info;
1306 RETURNVALIFTRUE(eom_output == NULL, NULL, "eom_output is NULL");
1307 RETURNVALIFTRUE(eom_output->output == NULL, NULL, "eom_output->output is NULL");
1309 err = tdm_output_get_layer_count(eom_output->output, &count);
1310 if (err != TDM_ERROR_NONE)
1312 EOM_DBG ("tdm_output_get_layer_count fail(%d)", err);
1316 for (i = 0; i < count; i++)
1318 layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err);
1319 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_output_get_layer fail(%d)", err);
1321 err = tdm_layer_get_capabilities(layer, &capa);
1322 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_get_capabilities fail(%d)", err);
1324 if (capa & TDM_LAYER_CAPABILITY_PRIMARY)
1326 EOM_DBG("TDM_LAYER_CAPABILITY_PRIMARY layer found : %d", i);
1331 memset(&layer_info, 0x0, sizeof(tdm_info_layer));
1332 layer_info.src_config.size.h = eom_output->width;
1333 layer_info.src_config.size.v = eom_output->height;
1334 layer_info.src_config.pos.x = 0;
1335 layer_info.src_config.pos.y = 0;
1336 layer_info.src_config.pos.w = eom_output->width;
1337 layer_info.src_config.pos.h = eom_output->height;
1338 layer_info.src_config.format = TBM_FORMAT_ARGB8888;
1339 layer_info.dst_pos.x = 0;
1340 layer_info.dst_pos.y = 0;
1341 layer_info.dst_pos.w = eom_output->width;
1342 layer_info.dst_pos.h = eom_output->height;
1343 layer_info.transform = TDM_TRANSFORM_NORMAL;
1345 err = tdm_layer_set_info(layer, &layer_info);
1346 RETURNVALIFTRUE(err != TDM_ERROR_NONE, NULL, "tdm_layer_set_info fail(%d)", err);
1351 static E_EomOutputPtr
1352 _e_eom_output_get_by_id(int id)
1355 E_EomOutputPtr output;
1357 EINA_LIST_FOREACH(g_eom->outputs, l, output)
1359 if (output && output->id == id)
1367 _e_eom_output_start_pp(E_EomOutputPtr eom_output)
1369 /* should be changed in HWC enable environment */
1370 tbm_surface_info_s src_buffer_info;
1371 tbm_surface_h src_buffer = NULL;
1372 Eina_Bool ret = EINA_FALSE;
1374 src_buffer = _e_eom_util_get_output_surface(g_eom->main_output_name);
1375 RETURNVALIFTRUE(src_buffer == NULL, EINA_FALSE, "Get root tdm surfcae");
1377 tbm_surface_get_info(src_buffer, &src_buffer_info);
1379 EOM_DBG("main output info: %dx%d bpp:%d size:%d",
1380 src_buffer_info.width, src_buffer_info.height,
1381 src_buffer_info.bpp, src_buffer_info.size);
1383 /* TODO: if internal and external outputs are equal */
1384 ret = _e_eom_pp_is_needed(g_eom->width, g_eom->height,
1385 eom_output->width, eom_output->height);
1386 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_TRUE, "pp is not required");
1388 ret = _e_eom_pp_init(eom_output, src_buffer);
1389 RETURNVALIFTRUE(ret == EINA_FALSE, EINA_FALSE, "Init pp");
1395 _e_eom_output_create_buffers(E_EomOutputPtr eom_output, int width, int height)
1399 /* TODO: Add support for other formats */
1400 for (i = 0; i < NUM_MAIN_BUF; i++)
1402 eom_output->dst_buffers[i] = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1403 GOTOIFTRUE(eom_output->dst_buffers[i] == NULL, err, "Create dst buffer");
1406 eom_output->dummy_buffer = _e_eom_util_create_buffer(width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
1407 GOTOIFTRUE(eom_output->dummy_buffer == NULL, err, "Create dummy buffer");
1412 for (i = 0; i < NUM_MAIN_BUF; i++)
1413 if (eom_output->dst_buffers[i])
1414 tbm_surface_destroy(eom_output->dst_buffers[i]);
1420 _e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec)
1422 E_EomOutputPtr eom_output = NULL;
1423 E_EomClientPtr eom_client = NULL;
1424 E_Comp_Client_Data *cdata = NULL;
1425 Eina_Bool ret = EINA_FALSE;
1427 if (resource == NULL || output_id <= 0 || ec == NULL)
1430 cdata = ec->comp_data;
1431 RETURNIFTRUE(cdata == NULL, "cdata is NULL");
1432 RETURNIFTRUE(cdata->shell.configure_send == NULL, "cdata->shell.configure_send is NULL");
1434 eom_client = _e_eom_client_get_by_resource(resource);
1435 RETURNIFTRUE(eom_client == NULL, "eom_client is NULL");
1437 eom_output = _e_eom_output_get_by_id(output_id);
1438 RETURNIFTRUE(eom_output == NULL, "eom_output is NULL");
1440 ret = _e_eom_util_add_comp_object_redirected_hook(ec);
1441 RETURNIFTRUE(ret != EINA_TRUE, "Set redirect comp hook failed");
1443 EOM_DBG("e_comp_object_redirected_set (ec->frame:%p)\n", ec->frame);
1445 /* Send reconfigure event to a client which will resize its window to
1446 * external output resolution in respond */
1447 cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height);
1449 /* ec is used in buffer_change callback for distinguishing external ec and its buffers */
1450 eom_client->ec = ec;
1452 if (eom_client->current == EINA_TRUE)
1453 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_NONE);
1455 wl_eom_send_output_set_window(resource, eom_output->id, WL_EOM_ERROR_OUTPUT_OCCUPIED);
1459 _e_eom_pp_init(E_EomOutputPtr eom_output, tbm_surface_h src_buffer)
1461 tdm_error err = TDM_ERROR_NONE;
1462 tdm_info_pp pp_info;
1466 pp = tdm_display_create_pp(g_eom->dpy, &err);
1467 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Create pp:%d", err);
1469 eom_output->pp = pp;
1471 /* TODO : consider rotation */
1472 _e_eom_util_calculate_fullsize(g_eom->width, g_eom->height,
1473 eom_output->width, eom_output->height,
1476 EOM_DBG("PP calculation: x:%d, y:%d, w:%d, h:%d", x, y, w, h);
1478 pp_info.src_config.size.h = g_eom->width;
1479 pp_info.src_config.size.v = g_eom->height;
1480 pp_info.src_config.pos.x = 0;
1481 pp_info.src_config.pos.y = 0;
1482 pp_info.src_config.pos.w = g_eom->width;
1483 pp_info.src_config.pos.h = g_eom->height;
1484 pp_info.src_config.format = TBM_FORMAT_ARGB8888;
1486 pp_info.dst_config.size.h = eom_output->width;
1487 pp_info.dst_config.size.v = eom_output->height;
1488 pp_info.dst_config.pos.x = x;
1489 pp_info.dst_config.pos.y = y;
1490 pp_info.dst_config.pos.w = w;
1491 pp_info.dst_config.pos.h = h;
1492 pp_info.dst_config.format = TBM_FORMAT_ARGB8888;
1494 /* TO DO : get rotation */
1495 pp_info.transform = TDM_TRANSFORM_NORMAL;
1499 err = tdm_pp_set_info(pp, &pp_info);
1500 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp info:%d", err);
1502 eom_output->pp_buffer = !eom_output->current_buffer;
1503 err = tdm_buffer_add_release_handler(eom_output->dst_buffers[eom_output->pp_buffer],
1504 _e_eom_cb_pp, eom_output);
1505 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "Set pp handler:%d", err);
1507 err = tdm_pp_attach(pp, src_buffer,
1508 eom_output->dst_buffers[eom_output->pp_buffer]);
1509 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp attach:%d", err);
1511 err = tdm_pp_commit(eom_output->pp);
1512 RETURNVALIFTRUE(err != TDM_ERROR_NONE, EINA_FALSE, "pp commit:%d", err);
1518 _e_eom_pp_is_needed(int src_w, int src_h, int dst_w, int dst_h)
1530 _e_eom_util_get_debug_env()
1532 char *env = getenv("EOM_SERVER_DEBUG");
1536 eom_server_debug_on =(atoi(env)) > 0 ? EINA_TRUE : EINA_FALSE;
1538 eom_server_debug_on = EINA_FALSE;
1540 EOM_INF("EOM_SERVER_DEBUG = %s", eom_server_debug_on > 0 ? "ON" : "OFF");
1543 static tbm_surface_h
1544 _e_eom_util_create_buffer(int width, int height, int format, int flags)
1546 tbm_surface_info_s buffer_info;
1547 tbm_surface_h buffer = NULL;
1549 buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
1550 RETURNVALIFTRUE(buffer == NULL, NULL, "Create buffer");
1552 memset(&buffer_info, 0x0, sizeof(tbm_surface_info_s));
1553 if (tbm_surface_map(buffer,
1554 TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
1555 &buffer_info) != TBM_SURFACE_ERROR_NONE)
1557 EOM_ERR("map buffer");
1558 tbm_surface_destroy(buffer);
1562 memset(buffer_info.planes[0].ptr, 0x0, buffer_info.planes[0].size);
1563 tbm_surface_unmap(buffer);
1568 static E_EomClientBufferPtr
1569 _e_eom_util_create_client_buffer(E_EomClientPtr client, E_Comp_Wl_Buffer *wl_buffer, tbm_surface_h tbm_buffer)
1571 E_EomClientBufferPtr buffer = NULL;
1573 buffer = E_NEW(E_EomClientBuffer, 1);
1574 RETURNVALIFTRUE(buffer == NULL, NULL, "Allocate new client buffer")
1576 /* TODO: Internal and External frame rate are same */
1578 /* Forbid E sending 'wl_buffer_send_release' event to external clients */
1581 buffer->wl_buffer = wl_buffer;
1582 buffer->tbm_buffer = tbm_buffer;
1584 EOM_DBG("new client buffer wl:%p tbm:%p",
1585 buffer->wl_buffer, buffer->tbm_buffer);
1587 #ifdef DUMP_PRESENTATION
1590 EOM_DBG("dump start");
1591 tbm_surface_internal_dump_start("/A", wl_buffer->w, wl_buffer->h, 30);
1596 buffer->stamp = _e_eom_util_get_stamp();
1602 static tbm_surface_h
1603 _e_eom_util_get_output_surface(const char *name)
1605 Ecore_Drm_Output *primary_output = NULL;
1606 Ecore_Drm_Device *dev;
1608 tdm_output *tdm_output_obj = NULL;
1609 tbm_surface_h tbm = NULL;
1610 tdm_error err = TDM_ERROR_NONE;
1611 int count = 0, i = 0;
1613 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1615 primary_output = ecore_drm_device_output_name_find(dev, name);
1616 if (primary_output != NULL)
1620 if (primary_output == NULL)
1622 EOM_ERR("Get primary output.(%s)", name);
1623 EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
1625 primary_output = ecore_drm_output_primary_get(dev);
1626 if (primary_output != NULL)
1630 if (primary_output == NULL)
1632 EOM_ERR("Get primary output.(%s)", name);
1637 tdm_output_obj = tdm_display_get_output(g_eom->dpy, 0, &err);
1638 if (tdm_output_obj == NULL || err != TDM_ERROR_NONE)
1640 EOM_ERR("tdm_display_get_output 0 fail");
1643 err = tdm_output_get_layer_count(tdm_output_obj, &count);
1644 if (err != TDM_ERROR_NONE)
1646 EOM_ERR("tdm_output_get_layer_count fail");
1650 for (i = 0; i < count; i++)
1652 tdm_layer *layer = tdm_output_get_layer(tdm_output_obj, i, NULL);
1653 tdm_layer_capability capabilities = 0;
1654 tdm_layer_get_capabilities(layer, &capabilities);
1655 if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1657 tbm = tdm_layer_get_displaying_buffer(layer, &err);
1658 if (err != TDM_ERROR_NONE)
1660 EOM_ERR("tdm_layer_get_displaying_buffer fail");
1671 _e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v,
1672 int *dst_x, int *dst_y, int *dst_w, int *dst_h)
1674 double h_ratio, v_ratio;
1676 h_ratio = src_h / dst_size_h;
1677 v_ratio = src_v / dst_size_v;
1679 if (h_ratio == v_ratio)
1683 *dst_w = dst_size_h;
1684 *dst_h = dst_size_v;
1686 else if (h_ratio < v_ratio)
1689 *dst_h = dst_size_v;
1690 *dst_w = dst_size_v * src_h / src_v;
1691 *dst_x = (dst_size_h - *dst_w) / 2;
1693 else /* (h_ratio > v_ratio) */
1696 *dst_w = dst_size_h;
1697 *dst_h = dst_size_h * src_h / src_v;
1698 *dst_y = (dst_size_v - *dst_h) / 2;
1703 _e_eom_util_add_comp_object_redirected_hook(E_Client *ec)
1705 E_EomCompObjectInterceptHookData *hook_data = NULL;
1706 E_Comp_Object_Intercept_Hook *hook = NULL;
1708 hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1);
1709 GOTOIFTRUE(hook_data == NULL, err, "hook_data = NULL");
1713 hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER,
1714 _e_eom_cb_comp_object_redirected,
1716 GOTOIFTRUE(hook == NULL, err, "hook = NULL");
1718 hook_data->hook = hook;
1720 g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks,
1723 EOM_DBG("_e_eom_redirected_hook have been added");
1734 _e_eom_util_get_stamp()
1738 clock_gettime(CLOCK_MONOTONIC, &tp);
1740 return ((tp.tv_sec * 1000) + (tp.tv_nsec / 1000));
1750 _e_eom_util_draw(tbm_surface_h surface)
1752 unsigned char rw = 0, gw = 0, bw = 0, aw = 0;
1753 unsigned char r = 255, g = 255, b = 255, a = 0;
1755 unsigned int *mm = NULL;
1758 int w = (int)tbm_surface_get_width(surface);
1759 int h = (int)tbm_surface_get_height(surface);
1761 tbm_bo bo = tbm_surface_internal_get_bo(surface, 0);
1762 RETURNIFTRUE(bo == NULL, "bo is NULL");
1764 mm = (unsigned int *)tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE).ptr;
1765 RETURNIFTRUE(mm == NULL, "mm is NULL");
1767 for (i = 0; i < h; i++)
1768 for (j = 0; j < w; j++)
1770 if (j > square_x && j < square_x + square_w)
1771 mm[i*w + j] = r << 24 | g << 16 | b << 8 | a;
1773 mm[i*w + j] = rw << 24 | gw << 16 | bw << 8 | aw;
1777 if (square_x + square_w> w)
1785 _e_eom_client_add_buffer(E_EomClientPtr client, E_EomClientBufferPtr buffer)
1787 client->buffers_show = eina_list_append(client->buffers_show, buffer);
1791 _e_eom_client_free_buffers(E_EomClientPtr client)
1793 E_EomClientBufferPtr buffer = NULL;
1796 EINA_LIST_FOREACH(client->buffers_show, l, buffer)
1800 client->buffers_show = eina_list_remove(client->buffers_show, buffer);
1802 /* TODO: not sure if it is necessary */
1803 if (buffer->tbm_buffer && client->first_buffer == EINA_FALSE)
1804 tbm_surface_internal_unref(buffer->tbm_buffer);
1806 /* TODO: not sure if it is necessary */
1807 if (buffer->wl_buffer)
1808 buffer->wl_buffer->busy--;
1814 EINA_LIST_FOREACH(client->buffers_del, l, buffer)
1818 client->buffers_del= eina_list_remove(client->buffers_del, buffer);
1820 /* TODO: not sure if it is necessary */
1821 if (buffer->tbm_buffer)
1822 tbm_surface_internal_unref(buffer->tbm_buffer);
1824 /* TODO: not sure if it is necessary */
1825 if (buffer->wl_buffer)
1826 buffer->wl_buffer->busy--;
1833 static E_EomClientBufferPtr
1834 _e_eom_client_get_buffer(E_EomClientPtr client)
1836 E_EomClientBufferPtr show_buffer = NULL;
1837 E_EomClientBufferPtr prev_buffer = NULL;
1838 E_EomClientBufferPtr del_buffer = NULL;
1841 /* TODO: is it possible that a client has only one buffet to draw too? */
1842 RETURNVALIFTRUE(eina_list_count(client->buffers_show) == 0, NULL,
1843 "eom client (%p) do not have buffers to be shown", client);
1845 /* If there is only one buffer we have slow client, just return the buffer */
1846 if (eina_list_count(client->buffers_show) == 1)
1848 show_buffer = eina_list_nth(client->buffers_show, 0);
1849 RETURNVALIFTRUE(show_buffer == NULL, NULL,
1850 "eom client (%p) buffer is NULL", client);
1852 EOM_DBG("one wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1857 if (client->first_buffer == EINA_TRUE)
1859 show_buffer= eina_list_nth(client->buffers_show, 0);
1860 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) first buffer is NULL", client);
1862 EOM_DBG("first wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1864 /* I am not sure if it is necessary */
1865 EOM_DBG("ref first");
1866 tbm_surface_internal_ref(show_buffer->tbm_buffer);
1868 client->first_buffer = EINA_FALSE;
1872 EINA_LIST_FOREACH(client->buffers_del, l, del_buffer)
1876 client->buffers_del = eina_list_remove(client->buffers_del, del_buffer);
1878 if (del_buffer->wl_buffer)
1880 del_buffer->wl_buffer->busy--;
1881 EOM_DBG("wl_buffer:%p busy:%d", del_buffer->wl_buffer, del_buffer->wl_buffer->busy);
1882 if (del_buffer->wl_buffer->busy == 0)
1884 if (del_buffer->wl_buffer->type != E_COMP_WL_BUFFER_TYPE_TBM)
1886 if (!wl_resource_get_client(del_buffer->wl_buffer->resource))
1888 EOM_DBG("wl_buffer->resource is NULL");
1892 wl_buffer_send_release(del_buffer->wl_buffer->resource);
1897 EOM_DBG("del wl:%p tbm:%p", del_buffer->wl_buffer, del_buffer->tbm_buffer);
1899 if (del_buffer->tbm_buffer)
1901 EOM_DBG("del unref");
1902 tbm_surface_internal_unref(del_buffer->tbm_buffer);
1905 /* TODO: should wl_buffer and tbm_surface be deleted here? */
1910 /* TODO: case of 2 or n buffers */
1911 prev_buffer = eina_list_nth(client->buffers_show, 0);
1912 RETURNVALIFTRUE(prev_buffer == NULL, NULL, "eom client (%p) old_buffer is NULL", client);
1914 EOM_DBG("old wl:%p tbm:%p", prev_buffer->wl_buffer, prev_buffer->tbm_buffer);
1916 client->buffers_show = eina_list_remove(client->buffers_show, prev_buffer);
1917 client->buffers_del = eina_list_append(client->buffers_del, prev_buffer);
1919 /* Take next buffer to be shown on external output */
1920 show_buffer = eina_list_nth(client->buffers_show, 0);
1921 RETURNVALIFTRUE(show_buffer == NULL, NULL, "eom client (%p) next buffer is NULL", client);
1923 EOM_DBG("show wl:%p tbm:%p", show_buffer->wl_buffer, show_buffer->tbm_buffer);
1925 if (show_buffer->tbm_buffer)
1927 EOM_DBG("show ref");
1928 tbm_surface_internal_ref(show_buffer->tbm_buffer);
1934 static E_EomClientPtr
1935 _e_eom_client_get_by_resource(struct wl_resource *resource)
1938 E_EomClientPtr client;
1940 EINA_LIST_FOREACH(g_eom->clients, l, client)
1942 if (client && client->resource == resource)
1949 static E_EomClientPtr
1950 _e_eom_client_get_current_by_id(int id)
1953 E_EomClientPtr client;
1955 EINA_LIST_FOREACH(g_eom->clients, l, client)
1958 client->current == EINA_TRUE &&
1959 client->output_id == id)
1966 static E_EomClientPtr
1967 _e_eom_client_get_current_by_ec(E_Client *ec)
1970 E_EomClientPtr client;
1972 EINA_LIST_FOREACH(g_eom->clients, l, client)
1975 client->current == EINA_TRUE &&
1986 Eina_Bool ret = EINA_FALSE;
1988 _e_eom_util_get_debug_env();
1990 EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err);
1992 g_eom = E_NEW(E_Eom, 1);
1993 EINA_SAFETY_ON_NULL_RETURN_VAL(g_eom, EINA_FALSE);
1995 g_eom->global = wl_global_create(e_comp_wl->wl.disp,
2001 uint32_t id = wl_display_get_serial(e_comp_wl->wl.disp);
2002 EOM_DBG("eom name: %d", id);
2004 EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err);
2006 ret = _e_eom_init_internal();
2007 GOTOIFTRUE(ret == EINA_FALSE, err, "init_internal() failed");
2009 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_ACTIVATE, _e_eom_cb_ecore_drm_activate, g_eom);
2010 E_LIST_HANDLER_APPEND(g_eom->handlers, ECORE_DRM_EVENT_OUTPUT, _e_eom_cb_ecore_drm_output, g_eom);
2011 E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL);
2013 g_eom->main_output_name = NULL;
2023 _e_eom_init_internal()
2025 tdm_error ret = TDM_ERROR_NONE;
2027 g_eom->dpy = tdm_display_init(&ret);
2028 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_init fail");
2030 ret = tdm_display_get_fd(g_eom->dpy, &g_eom->fd);
2031 GOTOIFTRUE(ret != TDM_ERROR_NONE, err, "tdm_display_get_fd fail");
2033 g_eom->bufmgr = tbm_bufmgr_init(g_eom->fd);
2034 GOTOIFTRUE(g_eom->bufmgr == NULL, err, "tbm_bufmgr_init fail");
2036 if (_e_eom_output_init(g_eom->dpy) != EINA_TRUE)
2038 EOM_ERR("_e_eom_output_init fail");
2046 tbm_bufmgr_deinit(g_eom->bufmgr);
2049 tdm_display_deinit(g_eom->dpy);
2057 Ecore_Event_Handler *h = NULL;
2059 if (g_eom == NULL) return;
2061 if (g_eom->handlers)
2063 EINA_LIST_FREE(g_eom->handlers, h)
2064 ecore_event_handler_del(h);
2067 if (g_eom->dpy) tdm_display_deinit(g_eom->dpy);
2068 if (g_eom->bufmgr) tbm_bufmgr_deinit(g_eom->bufmgr);
2070 if (g_eom->global) wl_global_destroy(g_eom->global);
2076 e_modapi_init(E_Module *m)
2078 return (_e_eom_init() ? m : NULL);
2082 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2089 e_modapi_save(E_Module *m EINA_UNUSED)
2091 /* Save something to be kept */