wayland/surface: Add support for buffer transforms
This adds the required bits to wayland surfaces and ties them up to the compositor parts. The central part here is to recalculate the surface size accordingly and to translate surface damage into buffer damage. The choosen approach additionally lays groundwork for wp_viewporter support, which is closely related in its nature. A further explanation of buffer transforms from the specification: > The purpose of this request is to allow clients to render content > according to the output transform, thus permitting the compositor > to use certain optimizations even if the display is rotated. > Using hardware overlays and scanning out a client buffer for > fullscreen surfaces are examples of such optimizations.
This commit is contained in:
parent
452ef4d5bb
commit
e4de9ed580
3 changed files with 121 additions and 31 deletions
|
@ -205,6 +205,8 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
|
||||||
meta_surface_actor_set_opaque_region (surface_actor, NULL);
|
meta_surface_actor_set_opaque_region (surface_actor, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta_surface_actor_set_transform (surface_actor, surface->buffer_transform);
|
||||||
|
|
||||||
for (l = surface->subsurfaces; l; l = l->next)
|
for (l = surface->subsurfaces; l; l = l->next)
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *subsurface_surface = l->data;
|
MetaWaylandSurface *subsurface_surface = l->data;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "clutter/wayland/clutter-wayland-compositor.h"
|
#include "clutter/wayland/clutter-wayland-compositor.h"
|
||||||
#include "clutter/wayland/clutter-wayland-surface.h"
|
#include "clutter/wayland/clutter-wayland-surface.h"
|
||||||
#include "cogl/cogl-wayland-server.h"
|
#include "cogl/cogl-wayland-server.h"
|
||||||
#include "compositor/meta-shaped-texture-private.h"
|
|
||||||
#include "compositor/meta-surface-actor-wayland.h"
|
#include "compositor/meta-surface-actor-wayland.h"
|
||||||
#include "compositor/meta-surface-actor.h"
|
#include "compositor/meta-surface-actor.h"
|
||||||
#include "compositor/meta-window-actor-private.h"
|
#include "compositor/meta-window-actor-private.h"
|
||||||
|
@ -253,14 +252,47 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_buffer_width (MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
||||||
|
return cogl_texture_get_width (texture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_buffer_height (MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
||||||
|
return cogl_texture_get_height (texture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
surface_process_damage (MetaWaylandSurface *surface,
|
surface_process_damage (MetaWaylandSurface *surface,
|
||||||
cairo_region_t *surface_region,
|
cairo_region_t *surface_region,
|
||||||
cairo_region_t *buffer_region)
|
cairo_region_t *buffer_region)
|
||||||
{
|
{
|
||||||
MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
||||||
cairo_rectangle_int_t surface_rect;
|
cairo_rectangle_int_t surface_rect;
|
||||||
cairo_region_t *scaled_region;
|
cairo_region_t *scaled_region;
|
||||||
|
cairo_region_t *transformed_region;
|
||||||
int i, n_rectangles;
|
int i, n_rectangles;
|
||||||
|
|
||||||
/* If the client destroyed the buffer it attached before committing, but
|
/* If the client destroyed the buffer it attached before committing, but
|
||||||
|
@ -282,22 +314,26 @@ surface_process_damage (MetaWaylandSurface *surface,
|
||||||
/* The damage region must be in the same coordinate space as the buffer,
|
/* The damage region must be in the same coordinate space as the buffer,
|
||||||
* i.e. scaled with surface->scale. */
|
* i.e. scaled with surface->scale. */
|
||||||
scaled_region = meta_region_scale (surface_region, surface->scale);
|
scaled_region = meta_region_scale (surface_region, surface->scale);
|
||||||
|
transformed_region = meta_region_transform (scaled_region,
|
||||||
|
surface->buffer_transform,
|
||||||
|
get_buffer_width (surface),
|
||||||
|
get_buffer_height (surface));
|
||||||
|
|
||||||
/* Now add the buffer damage on top of the scaled damage region, as buffer
|
/* Now add the buffer damage on top of the scaled damage region, as buffer
|
||||||
* damage is already in that scale. */
|
* damage is already in that scale. */
|
||||||
cairo_region_union (scaled_region, buffer_region);
|
cairo_region_union (transformed_region, buffer_region);
|
||||||
|
|
||||||
/* First update the buffer. */
|
/* First update the buffer. */
|
||||||
meta_wayland_buffer_process_damage (buffer, scaled_region);
|
meta_wayland_buffer_process_damage (buffer, transformed_region);
|
||||||
|
|
||||||
/* Now damage the actor. The actor expects damage in the unscaled texture
|
/* Now damage the actor. The actor expects damage in the unscaled texture
|
||||||
* coordinate space, i.e. same as the buffer. */
|
* coordinate space, i.e. same as the buffer. */
|
||||||
/* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
|
/* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
|
||||||
n_rectangles = cairo_region_num_rectangles (scaled_region);
|
n_rectangles = cairo_region_num_rectangles (transformed_region);
|
||||||
for (i = 0; i < n_rectangles; i++)
|
for (i = 0; i < n_rectangles; i++)
|
||||||
{
|
{
|
||||||
cairo_rectangle_int_t rect;
|
cairo_rectangle_int_t rect;
|
||||||
cairo_region_get_rectangle (scaled_region, i, &rect);
|
cairo_region_get_rectangle (transformed_region, i, &rect);
|
||||||
|
|
||||||
meta_surface_actor_process_damage (meta_wayland_surface_get_actor (surface),
|
meta_surface_actor_process_damage (meta_wayland_surface_get_actor (surface),
|
||||||
rect.x, rect.y,
|
rect.x, rect.y,
|
||||||
|
@ -305,6 +341,7 @@ surface_process_damage (MetaWaylandSurface *surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_region_destroy (scaled_region);
|
cairo_region_destroy (scaled_region);
|
||||||
|
cairo_region_destroy (transformed_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -400,6 +437,8 @@ pending_state_init (MetaWaylandPendingState *state)
|
||||||
state->has_new_geometry = FALSE;
|
state->has_new_geometry = FALSE;
|
||||||
state->has_new_min_size = FALSE;
|
state->has_new_min_size = FALSE;
|
||||||
state->has_new_max_size = FALSE;
|
state->has_new_max_size = FALSE;
|
||||||
|
|
||||||
|
state->has_new_buffer_transform = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -507,6 +546,12 @@ merge_pending_state (MetaWaylandPendingState *from,
|
||||||
if (from->scale > 0)
|
if (from->scale > 0)
|
||||||
to->scale = from->scale;
|
to->scale = from->scale;
|
||||||
|
|
||||||
|
if (from->has_new_buffer_transform)
|
||||||
|
{
|
||||||
|
to->buffer_transform = from->buffer_transform;
|
||||||
|
to->has_new_buffer_transform = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (to->buffer && to->buffer_destroy_handler_id == 0)
|
if (to->buffer && to->buffer_destroy_handler_id == 0)
|
||||||
{
|
{
|
||||||
to->buffer_destroy_handler_id =
|
to->buffer_destroy_handler_id =
|
||||||
|
@ -682,6 +727,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
|
||||||
if (pending->scale > 0)
|
if (pending->scale > 0)
|
||||||
surface->scale = pending->scale;
|
surface->scale = pending->scale;
|
||||||
|
|
||||||
|
if (pending->has_new_buffer_transform)
|
||||||
|
surface->buffer_transform = pending->buffer_transform;
|
||||||
|
|
||||||
if (meta_wayland_surface_get_actor (surface) &&
|
if (meta_wayland_surface_get_actor (surface) &&
|
||||||
(!cairo_region_is_empty (pending->surface_damage) ||
|
(!cairo_region_is_empty (pending->surface_damage) ||
|
||||||
!cairo_region_is_empty (pending->buffer_damage)))
|
!cairo_region_is_empty (pending->buffer_damage)))
|
||||||
|
@ -926,12 +974,55 @@ wl_surface_commit (struct wl_client *client,
|
||||||
meta_wayland_surface_commit (surface);
|
meta_wayland_surface_commit (surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static MetaMonitorTransform
|
||||||
wl_surface_set_buffer_transform (struct wl_client *client,
|
transform_from_wl_output_transform (int32_t transform_value)
|
||||||
struct wl_resource *resource,
|
|
||||||
int32_t transform)
|
|
||||||
{
|
{
|
||||||
g_warning ("TODO: support set_buffer_transform request");
|
enum wl_output_transform transform = transform_value;
|
||||||
|
|
||||||
|
switch (transform)
|
||||||
|
{
|
||||||
|
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||||
|
return META_MONITOR_TRANSFORM_NORMAL;
|
||||||
|
case WL_OUTPUT_TRANSFORM_90:
|
||||||
|
return META_MONITOR_TRANSFORM_90;
|
||||||
|
case WL_OUTPUT_TRANSFORM_180:
|
||||||
|
return META_MONITOR_TRANSFORM_180;
|
||||||
|
case WL_OUTPUT_TRANSFORM_270:
|
||||||
|
return META_MONITOR_TRANSFORM_270;
|
||||||
|
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||||
|
return META_MONITOR_TRANSFORM_FLIPPED;
|
||||||
|
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||||
|
return META_MONITOR_TRANSFORM_FLIPPED_90;
|
||||||
|
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||||
|
return META_MONITOR_TRANSFORM_FLIPPED_180;
|
||||||
|
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||||
|
return META_MONITOR_TRANSFORM_FLIPPED_270;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_surface_set_buffer_transform (struct wl_client *client,
|
||||||
|
struct wl_resource *resource,
|
||||||
|
int32_t transform)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||||
|
MetaMonitorTransform buffer_transform;
|
||||||
|
|
||||||
|
buffer_transform = transform_from_wl_output_transform (transform);
|
||||||
|
|
||||||
|
if (buffer_transform == -1)
|
||||||
|
{
|
||||||
|
wl_resource_post_error (resource,
|
||||||
|
WL_SURFACE_ERROR_INVALID_TRANSFORM,
|
||||||
|
"Trying to set invalid buffer_transform of %d\n",
|
||||||
|
transform);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface->pending->buffer_transform = buffer_transform;
|
||||||
|
surface->pending->has_new_buffer_transform = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1750,33 +1841,25 @@ meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface)
|
||||||
int
|
int
|
||||||
meta_wayland_surface_get_width (MetaWaylandSurface *surface)
|
meta_wayland_surface_get_width (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
MetaWaylandBuffer *buffer;
|
int width;
|
||||||
|
|
||||||
buffer = surface->buffer_ref.buffer;
|
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
|
||||||
if (buffer)
|
width = get_buffer_height (surface);
|
||||||
{
|
|
||||||
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
|
||||||
return cogl_texture_get_width (texture) / surface->scale;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
width = get_buffer_width (surface);
|
||||||
return 0;
|
|
||||||
}
|
return width / surface->scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
meta_wayland_surface_get_height (MetaWaylandSurface *surface)
|
meta_wayland_surface_get_height (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
MetaWaylandBuffer *buffer;
|
int height;
|
||||||
|
|
||||||
buffer = surface->buffer_ref.buffer;
|
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
|
||||||
if (buffer)
|
height = get_buffer_width (surface);
|
||||||
{
|
|
||||||
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
|
||||||
return cogl_texture_get_height (texture) / surface->scale;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
height = get_buffer_height (surface);
|
||||||
return 0;
|
|
||||||
}
|
return height / surface->scale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "backends/meta-monitor-manager-private.h"
|
#include "backends/meta-monitor-manager-private.h"
|
||||||
#include "clutter/clutter.h"
|
#include "clutter/clutter.h"
|
||||||
|
#include "compositor/meta-shaped-texture-private.h"
|
||||||
#include "compositor/meta-surface-actor.h"
|
#include "compositor/meta-surface-actor.h"
|
||||||
#include "meta/meta-cursor-tracker.h"
|
#include "meta/meta-cursor-tracker.h"
|
||||||
#include "wayland/meta-wayland-pointer-constraints.h"
|
#include "wayland/meta-wayland-pointer-constraints.h"
|
||||||
|
@ -109,6 +110,9 @@ struct _MetaWaylandPendingState
|
||||||
gboolean has_new_max_size;
|
gboolean has_new_max_size;
|
||||||
int new_max_width;
|
int new_max_width;
|
||||||
int new_max_height;
|
int new_max_height;
|
||||||
|
|
||||||
|
gboolean has_new_buffer_transform;
|
||||||
|
MetaMonitorTransform buffer_transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWaylandDragDestFuncs
|
struct _MetaWaylandDragDestFuncs
|
||||||
|
@ -142,6 +146,7 @@ struct _MetaWaylandSurface
|
||||||
int32_t offset_x, offset_y;
|
int32_t offset_x, offset_y;
|
||||||
GList *subsurfaces;
|
GList *subsurfaces;
|
||||||
GHashTable *outputs_to_destroy_notify_id;
|
GHashTable *outputs_to_destroy_notify_id;
|
||||||
|
MetaMonitorTransform buffer_transform;
|
||||||
|
|
||||||
/* Buffer reference state. */
|
/* Buffer reference state. */
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Reference in a new issue