Add wp_viewporter support

(Based heavily on initial work by Boram Park)
This commit is contained in:
Derek Foreman 2016-09-27 17:00:54 -05:00
parent abb97ca0fb
commit b591105d8f
8 changed files with 425 additions and 3 deletions

View File

@ -225,7 +225,8 @@ ENLIGHTENMENTHEADERS += \
src/bin/e_comp_wl_data.h \
src/bin/e_comp_wl_dmabuf.h \
src/bin/e_comp_wl_input.h \
src/bin/e_comp_wl.h
src/bin/e_comp_wl.h \
src/bin/e_comp_wl_scaler.h
endif
enlightenment_gen_src =
@ -431,7 +432,8 @@ src/bin/e_comp_wl_data.c \
src/bin/e_comp_wl_input.c \
src/bin/e_comp_wl_dmabuf.c \
src/bin/e_comp_wl.c \
src/bin/e_comp_wl_extensions.c
src/bin/e_comp_wl_extensions.c \
src/bin/e_comp_wl_scaler.c
enlightenment_gen_src += \
src/bin/generated/linux-dmabuf-unstable-v1-server-protocol.h \
@ -441,7 +443,9 @@ src/bin/generated/session-recovery-server-protocol.h \
src/bin/generated/www-protocol.c \
src/bin/generated/www-server-protocol.h \
src/bin/generated/screenshooter-protocol.c \
src/bin/generated/screenshooter-server-protocol.h
src/bin/generated/screenshooter-server-protocol.h \
src/bin/generated/viewporter-protocol.c \
src/bin/generated/viewporter-server-protocol.h
src/bin/e_comp_wl_extensions.c: \
src/bin/generated/screenshooter-server-protocol.h \
@ -453,6 +457,9 @@ src/bin/e_comp_wl.c: \
src/bin/e_comp_wl_dmabuf.c: \
src/bin/generated/linux-dmabuf-unstable-v1-server-protocol.h
src/bin/e_comp_wl_scaler.c: \
src/bin/generated/viewporter-server-protocol.h
endif
src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DE_LOGGING=1 @WAYLAND_CFLAGS@ @WAYLAND_EGL_CFLAGS@ @ECORE_X_CFLAGS@

View File

@ -3867,6 +3867,26 @@ e_comp_object_dirty(Evas_Object *obj)
e_comp_object_render(obj);
}
E_API void
e_comp_object_map_set(Evas_Object *obj, Evas_Map *map)
{
Eina_List *l;
Evas_Object *o;
API_ENTRY;
evas_object_map_set(obj, map);
evas_object_map_enable_set(obj, map ? EINA_TRUE : EINA_FALSE);
EINA_LIST_FOREACH(cw->obj_mirror, l, o)
{
Evas_Map *map2 = evas_map_dup(map);
evas_object_map_set(o, map2);
evas_object_map_enable_set(o, map2 ? EINA_TRUE : EINA_FALSE);
evas_map_free(map2);
}
}
E_API Eina_Bool
e_comp_object_render(Evas_Object *obj)
{

View File

@ -91,6 +91,7 @@ E_API Eina_Bool e_comp_object_effect_start(Evas_Object *obj, Edje_Signal_Cb end_
E_API Eina_Bool e_comp_object_effect_stop(Evas_Object *obj, Edje_Signal_Cb end_cb);
E_API E_Comp_Object_Mover *e_comp_object_effect_mover_add(int pri, const char *sig, E_Comp_Object_Mover_Cb provider, const void *data);
E_API void e_comp_object_effect_mover_del(E_Comp_Object_Mover *prov);
E_API void e_comp_object_map_set(Evas_Object *obj, Evas_Map *map);
#endif
#endif

View File

@ -1247,6 +1247,12 @@ _e_comp_wl_surface_state_init(E_Comp_Wl_Surface_State *state, int w, int h)
state->opaque = eina_tiler_new(w, h);
eina_tiler_tile_size_set(state->opaque, 1, 1);
state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
state->buffer_viewport.buffer.scale = 1;
state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
state->buffer_viewport.surface.width = -1;
state->buffer_viewport.changed = 0;
}
static void
@ -1299,6 +1305,157 @@ _e_comp_wl_surface_state_attach(E_Client *ec, E_Comp_Wl_Surface_State *state)
e_pixmap_refresh(ec->pixmap);
}
static void
_e_comp_wl_map_transform(int width, int height, uint32_t transform, int32_t scale,
int sx, int sy, int *dx, int *dy)
{
switch (transform)
{
case WL_OUTPUT_TRANSFORM_NORMAL:
default:
*dx = sx, *dy = sy;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED:
*dx = width - sx, *dy = sy;
break;
case WL_OUTPUT_TRANSFORM_90:
*dx = height - sy, *dy = sx;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
*dx = height - sy, *dy = width - sx;
break;
case WL_OUTPUT_TRANSFORM_180:
*dx = width - sx, *dy = height - sy;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
*dx = sx, *dy = height - sy;
break;
case WL_OUTPUT_TRANSFORM_270:
*dx = sy, *dy = width - sx;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
*dx = sy, *dy = sx;
break;
}
*dx *= scale;
*dy *= scale;
}
static void
_e_comp_wl_map_size_cal_from_buffer(E_Client *ec, int32_t *ow, int32_t *oh)
{
E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
int32_t width, height, pw, ph;
if (!e_pixmap_size_get(ec->pixmap, &pw, &ph)) return;
switch (vp->buffer.transform)
{
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
width = ph / vp->buffer.scale;
height = pw / vp->buffer.scale;
break;
default:
width = pw / vp->buffer.scale;
height = ph / vp->buffer.scale;
break;
}
*ow = width;
*oh = height;
}
static void
_e_comp_wl_map_size_cal_from_viewport(E_Client *ec, int32_t bw, int32_t bh, int32_t *ow, int32_t *oh)
{
E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
int32_t width, height;
width = bw;
height = bh;
if (width != 0 && vp->surface.width != -1)
{
*ow = vp->surface.width;
*oh = vp->surface.height;
return;
}
if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1))
{
int32_t w = wl_fixed_to_int(wl_fixed_from_int(1) - 1 + vp->buffer.src_width);
int32_t h = wl_fixed_to_int(wl_fixed_from_int(1) - 1 + vp->buffer.src_height);
*ow = w ?: 1;
*oh = h ?: 1;
return;
}
*ow = width;
*oh = height;
}
static void
_e_comp_wl_map_apply(E_Client *ec)
{
E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
Evas_Map *map;
int x1, y1, x2, y2, x, y;
int32_t w, h, vw, vh;
_e_comp_wl_map_size_cal_from_buffer(ec, &w, &h);
_e_comp_wl_map_size_cal_from_viewport(ec, w, h, &vw, &vh);
map = evas_map_new(4);
evas_map_util_points_populate_from_geometry(map,
ec->x, ec->y,
vw, vh, 0);
if (vp->buffer.src_width == wl_fixed_from_int(-1))
{
x1 = 0.0;
y1 = 0.0;
x2 = w;
y2 = h;
}
else
{
x1 = wl_fixed_to_int(vp->buffer.src_x);
y1 = wl_fixed_to_int(vp->buffer.src_y);
x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
}
_e_comp_wl_map_transform(w, h,
vp->buffer.transform, vp->buffer.scale,
x1, y1, &x, &y);
evas_map_point_image_uv_set(map, 0, x, y);
_e_comp_wl_map_transform(w, h,
vp->buffer.transform, vp->buffer.scale,
x2, y1, &x, &y);
evas_map_point_image_uv_set(map, 1, x, y);
_e_comp_wl_map_transform(w, h,
vp->buffer.transform, vp->buffer.scale,
x2, y2, &x, &y);
evas_map_point_image_uv_set(map, 2, x, y);
_e_comp_wl_map_transform(w, h,
vp->buffer.transform, vp->buffer.scale,
x1, y2, &x, &y);
evas_map_point_image_uv_set(map, 3, x, y);
e_comp_object_map_set(ec->frame, map);
evas_map_free(map);
}
static void
_e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
{
@ -1322,6 +1479,8 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
e_client_unignore(ec);
}
ec->comp_data->scaler.buffer_viewport = state->buffer_viewport;
if (state->new_attach)
_e_comp_wl_surface_state_attach(ec, state);
@ -1470,6 +1629,12 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
}
}
if (e_pixmap_usable_get(ec->pixmap) && state->buffer_viewport.changed)
{
_e_comp_wl_map_apply(ec);
state->buffer_viewport.changed = 0;
}
state->sx = 0;
state->sy = 0;
state->new_attach = EINA_FALSE;
@ -2420,6 +2585,11 @@ _e_comp_wl_client_cb_new(void *data EINA_UNUSED, E_Client *ec)
/* set initial client data properties */
ec->comp_data->mapped = EINA_FALSE;
ec->comp_data->scaler.buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
ec->comp_data->scaler.buffer_viewport.buffer.scale = 1;
ec->comp_data->scaler.buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
ec->comp_data->scaler.buffer_viewport.surface.width = -1;
/* add this client to the hash */
/* eina_hash_add(clients_win_hash, &win, ec); */
}

View File

@ -43,6 +43,7 @@
})
typedef struct _E_Comp_Wl_Buffer E_Comp_Wl_Buffer;
typedef struct _E_Comp_Wl_Buffer_Viewport E_Comp_Wl_Buffer_Viewport;
typedef struct _E_Comp_Wl_Subsurf_Data E_Comp_Wl_Subsurf_Data;
typedef struct _E_Comp_Wl_Surface_State E_Comp_Wl_Surface_State;
typedef struct _E_Comp_Wl_Client_Data E_Comp_Wl_Client_Data;
@ -64,6 +65,26 @@ struct _E_Comp_Wl_Buffer
uint32_t busy;
};
struct _E_Comp_Wl_Buffer_Viewport {
struct
{
uint32_t transform; /* wl_surface.set_buffer_transform */
int32_t scale; /* wl_surface.set_scaling_factor */
/* If src_width != wl_fixed_from_int(-1), then and only then src_* are used. */
wl_fixed_t src_x, src_y;
wl_fixed_t src_width, src_height;
} buffer;
struct
{
/* If width == -1, the size is inferred from the buffer. */
int32_t width, height;
} surface;
int changed;
};
struct _E_Comp_Wl_Surface_State
{
int sx, sy;
@ -72,6 +93,7 @@ struct _E_Comp_Wl_Surface_State
struct wl_listener buffer_destroy_listener;
Eina_List *damages, *frames;
Eina_Tiler *input, *opaque;
E_Comp_Wl_Buffer_Viewport buffer_viewport;
Eina_Bool new_attach : 1;
Eina_Bool has_data : 1;
};
@ -309,6 +331,12 @@ struct _E_Comp_Wl_Client_Data
int32_t x, y;
} popup;
struct
{
struct wl_resource *viewport;
E_Comp_Wl_Buffer_Viewport buffer_viewport;
} scaler;
int32_t on_outputs; /* Bitfield of the outputs this client is present on */
E_Maximize max;

View File

@ -6,6 +6,7 @@
#include "screenshooter-server-protocol.h"
#include "session-recovery-server-protocol.h"
#include "www-server-protocol.h"
#include "e_comp_wl_scaler.h"
static void
_e_comp_wl_extensions_client_move_begin(void *d EINA_UNUSED, E_Client *ec)
@ -280,6 +281,8 @@ e_comp_wl_extensions_init(void)
GLOBAL_CREATE_OR_RETURN(screenshooter, zwp_screenshooter_interface, 1);
GLOBAL_CREATE_OR_RETURN(www, www_interface, 1);
e_scaler_init();
ecore_event_handler_add(ECORE_WL2_EVENT_SYNC_DONE, _dmabuf_add, NULL);
e_client_hook_add(E_CLIENT_HOOK_MOVE_BEGIN, _e_comp_wl_extensions_client_move_begin, NULL);

186
src/bin/e_comp_wl_scaler.c Normal file
View File

@ -0,0 +1,186 @@
#define E_COMP_WL
#include "e.h"
#include "viewporter-server-protocol.h"
static void
_e_viewport_destroy(struct wl_resource *resource)
{
E_Client *ec = wl_resource_get_user_data(resource);
E_Comp_Client_Data *cdata;
if (e_object_is_del(E_OBJECT(ec))) return;
EINA_SAFETY_ON_NULL_RETURN(cdata = ec->comp_data);
EINA_SAFETY_ON_NULL_RETURN(cdata->scaler.viewport);
cdata->scaler.viewport = NULL;
cdata->pending.buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
cdata->pending.buffer_viewport.surface.width = -1;
cdata->pending.buffer_viewport.changed = 1;
}
static void
_e_viewport_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_e_viewport_cb_set_source(struct wl_client *client EINA_UNUSED,
struct wl_resource *resource,
wl_fixed_t src_x,
wl_fixed_t src_y,
wl_fixed_t src_width,
wl_fixed_t src_height)
{
E_Client *ec = wl_resource_get_user_data(resource);
E_Comp_Client_Data *cdata;
if (e_object_is_del(E_OBJECT(ec))) return;
EINA_SAFETY_ON_NULL_RETURN(cdata = ec->comp_data);
EINA_SAFETY_ON_NULL_RETURN(cdata->scaler.viewport);
if (src_width == wl_fixed_from_int(-1) && src_height == wl_fixed_from_int(-1))
{
/* unset source size */
cdata->pending.buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
cdata->pending.buffer_viewport.changed = 1;
return;
}
if (src_width <= 0 || src_height <= 0)
{
wl_resource_post_error(resource,
WP_VIEWPORT_ERROR_BAD_VALUE,
"source size must be positive (%fx%f)",
wl_fixed_to_double(src_width),
wl_fixed_to_double(src_height));
return;
}
cdata->pending.buffer_viewport.buffer.src_x = src_x;
cdata->pending.buffer_viewport.buffer.src_y = src_y;
cdata->pending.buffer_viewport.buffer.src_width = src_width;
cdata->pending.buffer_viewport.buffer.src_height = src_height;
cdata->pending.buffer_viewport.changed = 1;
}
static void
_e_viewport_cb_set_destination(struct wl_client *client EINA_UNUSED,
struct wl_resource *resource,
int32_t dst_width,
int32_t dst_height)
{
E_Client *ec = wl_resource_get_user_data(resource);
E_Comp_Client_Data *cdata;
if (e_object_is_del(E_OBJECT(ec))) return;
EINA_SAFETY_ON_NULL_RETURN(cdata = ec->comp_data);
EINA_SAFETY_ON_NULL_RETURN(cdata->scaler.viewport);
if (dst_width == -1 && dst_height == -1)
{
/* unset destination size */
cdata->pending.buffer_viewport.surface.width = -1;
cdata->pending.buffer_viewport.changed = 1;
return;
}
if (dst_width <= 0 || dst_height <= 0)
{
wl_resource_post_error(resource,
WP_VIEWPORT_ERROR_BAD_VALUE,
"destination size must be positive (%dx%d)",
dst_width, dst_height);
return;
}
cdata->pending.buffer_viewport.surface.width = dst_width;
cdata->pending.buffer_viewport.surface.height = dst_height;
cdata->pending.buffer_viewport.changed = 1;
}
static const struct wp_viewport_interface _e_viewport_interface = {
_e_viewport_cb_destroy,
_e_viewport_cb_set_source,
_e_viewport_cb_set_destination
};
static void
_e_scaler_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
_e_scaler_cb_get_viewport(struct wl_client *client EINA_UNUSED, struct wl_resource *scaler, uint32_t id, struct wl_resource *surface_resource)
{
int version = wl_resource_get_version(scaler);
E_Client *ec;
struct wl_resource *res;
E_Comp_Client_Data *cdata;
if (!(ec = wl_resource_get_user_data(surface_resource))) return;
if (e_object_is_del(E_OBJECT(ec))) return;
if (!(cdata = ec->comp_data)) return;
if (cdata->scaler.viewport)
{
wl_resource_post_error(scaler,
WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
"a viewport for that surface already exists");
return;
}
res = wl_resource_create(client, &wp_viewport_interface, version, id);
if (res == NULL)
{
wl_client_post_no_memory(client);
return;
}
cdata->scaler.viewport = res;
wl_resource_set_implementation(res, &_e_viewport_interface, ec, _e_viewport_destroy);
}
static const struct wp_viewporter_interface _e_scaler_interface =
{
_e_scaler_cb_destroy,
_e_scaler_cb_get_viewport
};
static void
_e_scaler_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct wl_resource *res;
if (!(res = wl_resource_create(client, &wp_viewporter_interface, MIN(version, 2), id)))
{
ERR("Could not create scaler resource: %m");
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(res, &_e_scaler_interface, NULL, NULL);
}
Eina_Bool
e_scaler_init(void)
{
E_Comp_Wl_Data *cdata;
if (!e_comp) return EINA_FALSE;
if (!(cdata = e_comp->wl_comp_data)) return EINA_FALSE;
if (!cdata->wl.disp) return EINA_FALSE;
/* try to add scaler to wayland globals */
if (!wl_global_create(cdata->wl.disp, &wp_viewporter_interface, 1,
cdata, _e_scaler_cb_bind))
{
ERR("Could not add scaler to wayland globals: %m");
return EINA_FALSE;
}
return EINA_TRUE;
}

View File

@ -0,0 +1,7 @@
#ifndef E_COMP_WL_SCALER_H
#define E_COMP_WL_SCALER_H
Eina_Bool e_scaler_init(void);
#endif