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:
Robert Mader 2018-11-26 19:40:57 +01:00
parent 452ef4d5bb
commit e4de9ed580
3 changed files with 121 additions and 31 deletions

View File

@ -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_transform (surface_actor, surface->buffer_transform);
for (l = surface->subsurfaces; l; l = l->next)
{
MetaWaylandSurface *subsurface_surface = l->data;

View File

@ -32,7 +32,6 @@
#include "clutter/wayland/clutter-wayland-compositor.h"
#include "clutter/wayland/clutter-wayland-surface.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.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
surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *surface_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_region_t *scaled_region;
cairo_region_t *transformed_region;
int i, n_rectangles;
/* 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,
* i.e. scaled with 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
* damage is already in that scale. */
cairo_region_union (scaled_region, buffer_region);
cairo_region_union (transformed_region, buffer_region);
/* 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
* coordinate space, i.e. same as the buffer. */
/* 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++)
{
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),
rect.x, rect.y,
@ -305,6 +341,7 @@ surface_process_damage (MetaWaylandSurface *surface,
}
cairo_region_destroy (scaled_region);
cairo_region_destroy (transformed_region);
}
void
@ -400,6 +437,8 @@ pending_state_init (MetaWaylandPendingState *state)
state->has_new_geometry = FALSE;
state->has_new_min_size = FALSE;
state->has_new_max_size = FALSE;
state->has_new_buffer_transform = FALSE;
}
static void
@ -507,6 +546,12 @@ merge_pending_state (MetaWaylandPendingState *from,
if (from->scale > 0)
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)
{
to->buffer_destroy_handler_id =
@ -682,6 +727,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
if (pending->scale > 0)
surface->scale = pending->scale;
if (pending->has_new_buffer_transform)
surface->buffer_transform = pending->buffer_transform;
if (meta_wayland_surface_get_actor (surface) &&
(!cairo_region_is_empty (pending->surface_damage) ||
!cairo_region_is_empty (pending->buffer_damage)))
@ -926,12 +974,55 @@ wl_surface_commit (struct wl_client *client,
meta_wayland_surface_commit (surface);
}
static void
wl_surface_set_buffer_transform (struct wl_client *client,
struct wl_resource *resource,
int32_t transform)
static MetaMonitorTransform
transform_from_wl_output_transform (int32_t transform_value)
{
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
@ -1750,33 +1841,25 @@ meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface)
int
meta_wayland_surface_get_width (MetaWaylandSurface *surface)
{
MetaWaylandBuffer *buffer;
int width;
buffer = surface->buffer_ref.buffer;
if (buffer)
{
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
return cogl_texture_get_width (texture) / surface->scale;
}
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
width = get_buffer_height (surface);
else
{
return 0;
}
width = get_buffer_width (surface);
return width / surface->scale;
}
int
meta_wayland_surface_get_height (MetaWaylandSurface *surface)
{
MetaWaylandBuffer *buffer;
int height;
buffer = surface->buffer_ref.buffer;
if (buffer)
{
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
return cogl_texture_get_height (texture) / surface->scale;
}
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
height = get_buffer_width (surface);
else
{
return 0;
}
height = get_buffer_height (surface);
return height / surface->scale;
}

View File

@ -27,6 +27,7 @@
#include "backends/meta-monitor-manager-private.h"
#include "clutter/clutter.h"
#include "compositor/meta-shaped-texture-private.h"
#include "compositor/meta-surface-actor.h"
#include "meta/meta-cursor-tracker.h"
#include "wayland/meta-wayland-pointer-constraints.h"
@ -109,6 +110,9 @@ struct _MetaWaylandPendingState
gboolean has_new_max_size;
int new_max_width;
int new_max_height;
gboolean has_new_buffer_transform;
MetaMonitorTransform buffer_transform;
};
struct _MetaWaylandDragDestFuncs
@ -142,6 +146,7 @@ struct _MetaWaylandSurface
int32_t offset_x, offset_y;
GList *subsurfaces;
GHashTable *outputs_to_destroy_notify_id;
MetaMonitorTransform buffer_transform;
/* Buffer reference state. */
struct {