# include <tdm_helper.h>
# include <wayland-tbm-server.h>
+//#define USE_DLOG_HWC
+#ifdef USE_DLOG_HWC
+#define LOG_TAG "HWC"
+#include <dlog.h>
+#define HWC_DLOG(fmt, args...) LOGE("[HWC]" fmt, ##args)
+#endif
+
# define HWC_DRM_MODE_DPMS_OFF 3
# ifndef CLEAR
# define CLEAR(x) memset(&(x), 0, sizeof (x))
typedef struct _E_Comp_Hwc_Layer E_Comp_Hwc_Layer;
typedef struct _E_Comp_Hwc_Renderer E_Comp_Hwc_Renderer;
typedef struct _E_Comp_Hwc_Commit_Data E_Comp_Hwc_Commit_Data;
+typedef struct _E_Comp_Hwc_Client E_Comp_Hwc_Client;
+
+struct _E_Comp_Hwc_Client
+{
+ E_Client *ec;
+
+ Eina_Bool activated;
+
+ E_Comp_Wl_Buffer *buffer;
+ E_Comp_Wl_Buffer *backup_buffer;
+
+ Eina_Bool wait_for_commit;
+};
struct _E_Comp_Hwc_Commit_Data {
E_Comp_Hwc_Layer *hwc_layer;
Eina_List *hwc_outputs;
Eina_Bool trace_debug;
+
+ Eina_List *hwc_clients;
};
// Global variable.
free(output);
}
+static tbm_surface_h
+_e_comp_hwc_create_copied_surface(E_Client *ec, Eina_Bool refresh)
+{
+ tbm_surface_h tsurface = NULL;
+ tbm_surface_h new_tsurface = NULL;
+ E_Pixmap *pixmap = NULL;
+ E_Comp_Wl_Buffer *buffer = NULL;
+ tbm_surface_info_s src_info, dst_info;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+
+ pixmap = ec->pixmap;
+
+ if (refresh)
+ e_pixmap_image_refresh(ec->pixmap);
+
+ buffer = e_pixmap_resource_get(pixmap);
+ if (!buffer) return NULL;
+
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+
+ tbm_surface_map(tsurface, TBM_SURF_OPTION_READ, &src_info);
+ tbm_surface_unmap(tsurface);
+
+ new_tsurface = tbm_surface_create(src_info.width, src_info.height, src_info.format);
+
+ tbm_surface_map(new_tsurface, TBM_SURF_OPTION_WRITE, &dst_info);
+ tbm_surface_unmap(new_tsurface);
+
+ /* copy from src to dst */
+ memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
+
+ return new_tsurface;
+}
+
+static void
+_e_comp_hwc_destroy_copied_surface(tbm_surface_h tbm_surface)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tbm_surface);
+
+ tbm_surface_internal_unref(tbm_surface);
+}
+
+static E_Comp_Wl_Buffer *
+_e_comp_hwc_client_create_backup_buffer(E_Comp_Hwc_Client *hwc_client)
+{
+ E_Comp_Wl_Buffer *buffer = NULL;
+ tbm_surface_h tsurface = NULL;
+
+ tsurface = _e_comp_hwc_create_copied_surface(hwc_client->ec, EINA_TRUE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, NULL);
+
+ if (!(buffer = E_NEW(E_Comp_Wl_Buffer, 1)))
+ {
+ _e_comp_hwc_destroy_copied_surface(tsurface);
+ return NULL;
+ }
+
+ buffer->type = E_COMP_WL_BUFFER_TYPE_TBM;
+ buffer->w = tbm_surface_get_width(tsurface);
+ buffer->h = tbm_surface_get_height(tsurface);
+ buffer->resource = NULL;
+ buffer->tbm_surface = tsurface;
+ wl_signal_init(&buffer->destroy_signal);
+
+ return buffer;
+}
+
+static void
+_e_comp_hwc_client_destroy_backup_buffer(E_Comp_Wl_Buffer *buffer)
+{
+ if (!buffer) return;
+ if (buffer->tbm_surface)
+ {
+ _e_comp_hwc_destroy_copied_surface(buffer->tbm_surface);
+ buffer->tbm_surface = NULL;
+ }
+
+ E_FREE(buffer);
+}
+
static void
_e_comp_hwc_update_client_fps()
{
return EINA_TRUE;
}
+static void
+_e_comp_hwc_client_cb_del(void *data EINA_UNUSED, E_Client *ec)
+{
+ E_Comp_Hwc_Client *hwc_client = NULL;
+ Eina_List *l = NULL;
+
+ /* destroy the hwc_client */
+ EINA_LIST_FOREACH(g_hwc->hwc_clients, l, hwc_client)
+ {
+ if (!hwc_client) continue;
+ if (hwc_client->ec == ec)
+ {
+ g_hwc->hwc_clients = eina_list_remove_list(g_hwc->hwc_clients, l);
+ if (hwc_client->backup_buffer)
+ _e_comp_hwc_client_destroy_backup_buffer(hwc_client->backup_buffer);
+ free(hwc_client);
+ break;
+ }
+ }
+}
+
+
+E_Comp_Hwc_Client *
+_e_comp_hwc_client_find(E_Client *ec)
+{
+ E_Comp_Hwc_Client *hwc_client = NULL;
+ const Eina_List *l;
+
+ EINA_LIST_FOREACH(g_hwc->hwc_clients, l, hwc_client)
+ {
+ if (!hwc_client) continue;
+ if (hwc_client->ec == ec) return hwc_client;
+ }
+
+ return NULL;
+}
+
+
static Eina_Bool
_e_comp_hwc_renderer_activate(E_Comp_Hwc_Renderer *hwc_renderer, E_Client *ec)
{
hwc_renderer->activated_ec = ec;
+ /* register the hwc client */
+ E_Comp_Hwc_Client *hwc_client = _e_comp_hwc_client_find(ec);
+ if (!hwc_client)
+ {
+ hwc_client = E_NEW(E_Comp_Hwc_Client, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_client, EINA_FALSE);
+ hwc_client->ec = ec;
+ hwc_client->activated = EINA_TRUE;
+ /* add hwc_client to the list */
+ g_hwc->hwc_clients = eina_list_append(g_hwc->hwc_clients, hwc_client);
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p created.\n", hwc_client);
+#endif
+ }
+ else
+ {
+ hwc_client->activated = EINA_TRUE;
+ }
+
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p activated.\n", hwc_client);
+#endif
+
return EINA_TRUE;
}
struct wl_resource *wl_surface = NULL;
E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
E_Client *ec = NULL;
+ E_Comp_Hwc_Client *hwc_client = NULL;
if (!hwc_renderer->activated_ec)
{
if (hwc_renderer->hwc_layer->hwc->trace_debug)
ELOGF("HWC", "Deactivate", ec->pixmap, ec);
+ hwc_client = _e_comp_hwc_client_find(ec);
+ EINA_SAFETY_ON_NULL_GOTO(hwc_client, done);
+
+ if (!hwc_client->activated) goto done;
+
EINA_SAFETY_ON_NULL_GOTO(wl_comp_data, done);
wl_surface = _e_comp_hwc_wl_surface_get(ec);
/* deactive */
wayland_tbm_server_client_queue_deactivate(cqueue);
+ if (hwc_client->backup_buffer)
+ {
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p The previous backup_buffer exists. destroy it.\n");
+#endif
+ _e_comp_hwc_client_destroy_backup_buffer(hwc_client->backup_buffer);
+ }
+
+ /* get the tsurface for setting the native surface with it
+ compositing is processed not calling e_comp_update_cb*/
+ hwc_client->buffer = e_pixmap_resource_get(ec->pixmap);
+ hwc_client->backup_buffer = _e_comp_hwc_client_create_backup_buffer(hwc_client);
+ hwc_client->activated = EINA_FALSE;
+ hwc_client->wait_for_commit = EINA_TRUE;
+
+ /* set the backup buffer resource to the pixmap */
+ e_pixmap_resource_set(ec->pixmap, hwc_client->backup_buffer);
+
+ e_comp->nocomp = 0;
+ e_comp->nocomp_ec = NULL;
+
+ /* force update */
+ e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
+ e_comp_object_dirty(ec->frame);
+ e_comp_object_render(ec->frame);
+
+ /* set the native surface with tbm type for compositing */
+ e_comp_object_native_surface_set(ec->frame, EINA_TRUE);
+
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p deactivated\n", hwc_client);
+#endif
+
done:
hwc_renderer->activated_ec = NULL;
E_Comp_Hwc_Commit_Data *data = NULL;
tdm_output_dpms dpms_value;
+#if HWC_DUMP
+ char fname[1024] = {0, };
+#endif
+
error = tdm_output_get_dpms(toutput, &dpms_value);
if (error != TDM_ERROR_NONE)
{
}
}
+#if HWC_DUMP
+ if (is_canvas)
+ snprintf(fname, sizeof(fname), "hwc_output_commit_canvas");
+ else
+ {
+ Ecore_Window win;
+ win = e_client_util_win_get(data->ec);
+ snprintf(fname, sizeof(fname), "hwc_output_commit_0x%08x", win);
+ }
+ tbm_internal_surface_dump_buffer(tsurface, fname);
+#endif
+
return EINA_TRUE;
}
E_Comp_Hwc_Renderer *hwc_renderer = hwc_layer->hwc_renderer;
E_Pixmap *pixmap = ec->pixmap;
tbm_surface_h tsurface = NULL;
+ E_Comp_Hwc_Client *hwc_client = NULL;
if (hwc_layer->hwc->trace_debug)
ELOGF("HWC", "Display Client", ec->pixmap, ec);
+ hwc_client = _e_comp_hwc_client_find(ec);
+ EINA_SAFETY_ON_NULL_RETURN(hwc_client);
+
+ if (hwc_client->backup_buffer)
+ {
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p display client. destroy the backup_buffer.\n", hwc_client);
+#endif
+ _e_comp_hwc_client_destroy_backup_buffer(hwc_client->backup_buffer);
+ hwc_client->backup_buffer = NULL;
+ }
+
/* acquire the surface from the client_queue */
tsurface = _e_comp_hwc_renderer_recieve_surface(hwc_renderer, ec);
if (!tsurface)
evas_event_callback_add(e_comp->evas, EVAS_CALLBACK_RENDER_POST, _e_comp_hwc_canvas_render_post, hwc);
+ e_client_hook_add(E_CLIENT_HOOK_DEL, _e_comp_hwc_client_cb_del, NULL);
+
return EINA_TRUE;
fail:
INF("HWC: hwc trace_debug is %s", onoff?"ON":"OFF");
}
+static Eina_Bool
+_e_comp_hwc_check_buffer_scanout(E_Client *ec)
+{
+ tbm_surface_h tsurface = NULL;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+ E_Pixmap *pixmap = ec->pixmap;
+ uint32_t flags = 0;
+ E_Comp_Wl_Buffer *buffer = NULL;
+
+ buffer = e_pixmap_resource_get(pixmap);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, EINA_FALSE);
+
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, EINA_FALSE);
+
+ flags = wayland_tbm_server_get_buffer_flags(wl_comp_data->tbm.server, buffer->resource);
+ if (flags != HWC_SURFACE_TYPE_PRIMARY)
+ return EINA_FALSE;;
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+e_comp_hwc_native_surface_set(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ E_Comp_Hwc_Client *hwc_client = NULL;
+
+ /* check the hwc_client */
+ hwc_client = _e_comp_hwc_client_find(ec);
+ if (!hwc_client) return EINA_FALSE;
+
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p update client\n", hwc_client);
+#endif
+
+ /* check the scanout buffer */
+ if (!_e_comp_hwc_check_buffer_scanout(ec))
+ {
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p not scanout buffer\n", hwc_client);
+#endif
+ return EINA_FALSE;
+ }
+
+ if (hwc_client->wait_for_commit &&
+ hwc_client->backup_buffer)
+ {
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p NEVER BE HEAR.\n", hwc_client);
+#endif
+ _e_comp_hwc_client_destroy_backup_buffer(hwc_client->backup_buffer);
+ hwc_client->buffer = NULL;
+ }
+
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p copy and native set\n", hwc_client);
+#endif
+
+ return EINA_TRUE;
+}
+
+void
+e_comp_hwc_client_commit(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ E_Comp_Hwc_Client *hwc_client = NULL;
+
+ hwc_client = _e_comp_hwc_client_find(ec);
+ if (!hwc_client) return;
+
+ if (hwc_client->wait_for_commit)
+ {
+#ifdef USE_DLOG_HWC
+ HWC_DLOG("hwc_client,%p commit after deactivated....\n", hwc_client);
+#endif
+ hwc_client->wait_for_commit = EINA_FALSE;
+ }
+}
+
EINTERN Eina_Bool
e_comp_hwc_plane_init(E_Zone *zone)
{
;
}
+Eina_Bool
+e_comp_hwc_native_surface_set(E_Client *ec)
+{
+ return EINA_FALSE;
+}
+
+void
+e_comp_hwc_client_commit(E_Client *ec)
+{
+ ;
+}
+
EINTERN Eina_Bool
e_comp_hwc_plane_init(E_Zone *zone)
{