[PATCH 3/3] compositor: unify plane and output handling
Jesse Barnes
jbarnes at virtuousgeek.org
Wed Jan 25 14:00:34 PST 2012
Plane and output handling are mostly the same; they both create fbs for
display and then assign them to either the primary or one of the overlay
planes. So unify them using a new drm_buffer_reference object, making
the plane handling code work much better.
---
src/compositor-drm.c | 411 +++++++++++++++++++++++++++++++++++++-------------
src/compositor.c | 62 +++-----
src/compositor.h | 6 +-
3 files changed, 336 insertions(+), 143 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 2cab9d5..e7feee2 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -67,6 +67,16 @@ struct drm_mode {
drmModeModeInfo mode_info;
};
+struct drm_buffer_reference {
+ struct drm_compositor *compositor;
+ struct wl_buffer *buffer;
+ struct wl_listener buffer_destroy_listener;
+ struct wl_buffer *pending_buffer;
+ struct wl_listener pending_buffer_destroy_listener;
+ uint32_t fb_id;
+ uint32_t pending_fb_id;
+};
+
struct drm_output {
struct weston_output base;
@@ -77,12 +87,11 @@ struct drm_output {
uint32_t fb_id[2];
EGLImageKHR image[2];
struct gbm_bo *bo[2];
- uint32_t current;
+ uint32_t current;
struct wl_list sprite_list;
- uint32_t fs_surf_fb_id;
- uint32_t pending_fs_surf_fb_id;
+ struct drm_buffer_reference fb_reference;
};
/*
@@ -90,12 +99,16 @@ struct drm_output {
* blending display contents.
*/
struct drm_sprite {
+ struct drm_buffer_reference ref;
+
+ uint32_t fb_id;
+ uint32_t current;
+
struct wl_list link;
struct wl_list output_link;
uint32_t possible_crtcs;
uint32_t plane_id;
- uint32_t fb_id;
uint32_t count_formats;
int32_t src_x, src_y;
@@ -106,45 +119,113 @@ struct drm_sprite {
uint32_t formats[];
};
-/**
- * drm_queue_scanout_surface - add a surface to the pending output list
- * @output: output using scanout surface
- * @es: surface to queue
- *
- * When we queue a page flip, we need to make sure the buffer is marked
- * busy until the flip completes. Call this function to do that for
- * buffers that will be flipped to.
- */
static int
-drm_queue_scanout_surface(struct weston_output *output,
- struct weston_surface *es)
+surface_is_fullscreen(struct weston_output *output,
+ struct weston_surface *es)
{
- /* assert output->pending_scanout_buffer == NULL */
- output->pending_scanout_buffer = es->buffer;
- output->pending_scanout_buffer->busy_count++;
+ if (es->x != output->x ||
+ es->y != output->y ||
+ es->width != output->current->width ||
+ es->height != output->current->height)
+ return 0;
- wl_list_insert(output->pending_scanout_buffer->resource.destroy_listener_list.prev,
- &output->pending_scanout_buffer_destroy_listener.link);
+ return -1;
+}
+
+static int
+surface_is_primary(struct weston_compositor *ec, struct weston_surface *es)
+{
+ struct weston_surface *primary;
+ primary = container_of(ec->surface_list.next, struct weston_surface,
+ link);
+ if (es == primary)
+ return -1;
return 0;
}
+static int
+surface_is_cursor(struct weston_compositor *ec, struct weston_surface *es)
+{
+ if (!es->buffer)
+ return -1;
+ return 0;
+}
+
+static void
+handle_buffer_destroy(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct drm_buffer_reference *reference =
+ container_of(listener, struct drm_buffer_reference,
+ buffer_destroy_listener);
+
+ reference->buffer = NULL;
+
+ if (!reference->pending_buffer)
+ weston_compositor_schedule_repaint(&reference->compositor->base);
+}
+
static void
-drm_dequeue_scanout_surface(struct weston_output *output)
+handle_pending_buffer_destroy(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
{
- if (output->scanout_buffer) {
- weston_buffer_post_release(output->scanout_buffer);
- wl_list_remove(&output->scanout_buffer_destroy_listener.link);
- output->scanout_buffer = NULL;
+ struct drm_buffer_reference *reference =
+ container_of(listener, struct drm_buffer_reference,
+ pending_buffer_destroy_listener);
+
+ reference->pending_buffer = NULL;
+
+ weston_compositor_schedule_repaint(&reference->compositor->base);
+}
+
+static void
+drm_buffer_reference_queue(struct drm_buffer_reference *reference,
+ struct wl_buffer *buffer, uint32_t fb_id)
+{
+ reference->pending_buffer = buffer;
+ reference->pending_buffer->busy_count++;
+
+ wl_list_insert(reference->pending_buffer->resource.destroy_listener_list.prev,
+ &reference->pending_buffer_destroy_listener.link);
+ reference->pending_fb_id = fb_id;
+}
+
+static uint32_t
+drm_buffer_reference_shift(struct drm_buffer_reference *reference)
+{
+ uint32_t old_fb_id = 0;
+
+ if (reference->buffer) {
+ weston_buffer_post_release(reference->buffer);
+ wl_list_remove(&reference->buffer_destroy_listener.link);
+ reference->buffer = NULL;
+ old_fb_id = reference->fb_id;
+ reference->fb_id = 0;
}
- if (output->pending_scanout_buffer) {
- output->scanout_buffer = output->pending_scanout_buffer;
- wl_list_remove(&output->pending_scanout_buffer_destroy_listener.link);
- wl_list_insert(output->scanout_buffer->resource.destroy_listener_list.prev,
- &output->scanout_buffer_destroy_listener.link);
- output->pending_scanout_buffer = NULL;
+ if (reference->pending_buffer) {
+ reference->buffer = reference->pending_buffer;
+ wl_list_remove(&reference->pending_buffer_destroy_listener.link);
+ wl_list_insert(reference->buffer->resource.destroy_listener_list.prev,
+ &reference->buffer_destroy_listener.link);
+ reference->pending_buffer = NULL;
+ reference->fb_id = reference->pending_fb_id;
+ reference->pending_fb_id = 0;
}
+
+ return old_fb_id;
+}
+
+static void
+drm_buffer_reference_init(struct drm_buffer_reference *reference,
+ struct drm_compositor *compositor)
+{
+ reference->compositor = compositor;
+
+ reference->buffer_destroy_listener.func = handle_buffer_destroy;
+ reference->pending_buffer_destroy_listener.func =
+ handle_pending_buffer_destroy;
}
static int
@@ -169,14 +250,20 @@ drm_output_present(struct weston_output *output_base)
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
+ struct drm_sprite *s;
uint32_t fb_id = 0;
+ uint32_t flags = 0;
+ int ret, queued_sprite = 0;
glFlush();
+ /*
+ * First, flip the scanout surface onto the screen.
+ */
output->current ^= 1;
- if (output->pending_fs_surf_fb_id != 0) {
- fb_id = output->pending_fs_surf_fb_id;
+ if (output->fb_reference.pending_fb_id != 0) {
+ fb_id = output->fb_reference.pending_fb_id;
} else {
fb_id = output->fb_id[output->current ^ 1];
}
@@ -188,36 +275,93 @@ drm_output_present(struct weston_output *output_base)
return -1;
}
+ /*
+ * Now, update all the sprite surfaces
+ */
+ wl_list_for_each(s, &output->sprite_list, output_link) {
+ if (s->ref.pending_fb_id)
+ fb_id = s->ref.pending_fb_id;
+ else
+ continue;
+
+ ret = drmModeSetPlane(c->drm.fd, s->plane_id,
+ output->crtc_id, fb_id, flags,
+ s->dest_x, s->dest_y,
+ s->dest_w, s->dest_h,
+ s->src_x, s->src_y,
+ s->src_w, s->src_h);
+ if (ret)
+ fprintf(stderr, "setplane failed: %d: %s\n",
+ ret, strerror(errno));
+ queued_sprite = 1;
+ s->fb_id = fb_id;
+ }
+
+ /*
+ * Request a vblank event for the next seqno so we can free up
+ * the sprite surfaces.
+ */
+ if (queued_sprite) {
+ drmVBlank vbl = {
+ .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+ .request.sequence = 1,
+ };
+
+ vbl.request.signal = (unsigned long)output;
+ ret = drmWaitVBlank(c->drm.fd, &vbl);
+ if (ret) {
+ fprintf(stderr, "vblank event request failed: %d: %s\n",
+ ret, strerror(errno));
+ }
+ }
+
return 0;
}
static void
-page_flip_handler(int fd, unsigned int frame,
- unsigned int sec, unsigned int usec, void *data)
+vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
+ void *data)
{
struct drm_output *output = (struct drm_output *) data;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
- uint32_t msecs;
+ struct drm_sprite *s;
+ uint32_t old_fb_id;
- if (output->fs_surf_fb_id) {
- drmModeRmFB(c->drm.fd, output->fs_surf_fb_id);
- output->fs_surf_fb_id = 0;
+ /* Free the FBs for the sprites */
+ wl_list_for_each(s, &output->sprite_list, output_link) {
+ old_fb_id = drm_buffer_reference_shift(&s->ref);
+ /*
+ * Only remove the old fb here, not the current one. If no
+ * overlays are in use, the last one will be removed in
+ * the disable_unused call.
+ */
+ if (old_fb_id && old_fb_id != s->fb_id)
+ drmModeRmFB(c->drm.fd, old_fb_id);
}
+}
- if (output->pending_fs_surf_fb_id) {
- output->fs_surf_fb_id = output->pending_fs_surf_fb_id;
- output->pending_fs_surf_fb_id = 0;
- }
+static void
+page_flip_handler(int fd, unsigned int frame,
+ unsigned int sec, unsigned int usec, void *data)
+{
+ struct drm_output *output = (struct drm_output *) data;
+ struct drm_compositor *c =
+ (struct drm_compositor *) output->base.compositor;
+ uint32_t msecs, old_fb_id;
+
+ old_fb_id = drm_buffer_reference_shift(&output->fb_reference);
+ if (old_fb_id)
+ drmModeRmFB(c->drm.fd, old_fb_id);
- drm_dequeue_scanout_surface(&output->base);
msecs = sec * 1000 + usec / 1000;
weston_output_finish_frame(&output->base, msecs);
}
static int
-drm_output_prepare_scanout_surface(struct weston_output *output_base,
- struct weston_surface *es)
+drm_prepare_scanout_surface(struct weston_output *output_base,
+ struct weston_surface *es,
+ struct drm_buffer_reference *ref)
{
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
@@ -226,13 +370,8 @@ drm_output_prepare_scanout_surface(struct weston_output *output_base,
int ret;
uint32_t fb_id = 0;
struct gbm_bo *bo;
-
- if (es->x != output->base.x ||
- es->y != output->base.y ||
- es->width != output->base.current->width ||
- es->height != output->base.current->height ||
- es->image == EGL_NO_IMAGE_KHR)
- return -1;
+ uint32_t drm_format = DRM_FORMAT_XRGB8888, flags = 0;
+ uint32_t handles[4], pitches[4], offsets[4];
bo = gbm_bo_create_from_egl_image(c->gbm,
c->base.display, es->image,
@@ -247,76 +386,127 @@ drm_output_prepare_scanout_surface(struct weston_output *output_base,
if (handle == 0)
return -1;
- ret = drmModeAddFB(c->drm.fd,
- output->base.current->width,
- output->base.current->height,
- 24, 32, stride, handle, &fb_id);
+ handles[0] = handle;
+ pitches[0] = stride;
+ offsets[0] = 0;
+ ret = drmModeAddFB2(c->drm.fd, es->width, es->height, drm_format,
+ handles, pitches, offsets, &fb_id, flags);
if (ret)
return -1;
- output->pending_fs_surf_fb_id = fb_id;
+ drm_buffer_reference_queue(ref, es->buffer, fb_id);
return 0;
}
static int
-drm_assign_overlay_surface(struct weston_output *output_base,
- struct weston_surface *es)
+drm_output_prepare_scanout_surface(struct weston_output *output_base,
+ struct weston_surface *es)
+{
+ struct drm_output *output = (struct drm_output *) output_base;
+
+ if (!surface_is_fullscreen(output_base, es) ||
+ es->image == EGL_NO_IMAGE_KHR)
+ return -1;
+
+ return drm_prepare_scanout_surface(output_base, es,
+ &output->fb_reference);
+}
+
+static int
+drm_surface_format_supported(struct weston_surface *es)
+{
+ int ret = 0;
+ enum wl_shm_format format;
+
+ format = wl_shm_buffer_get_format(es->buffer);
+ switch (format) {
+ case WL_SHM_FORMAT_ARGB8888:
+ default:
+#ifdef DEBUG_PLANES
+ /*
+ * Enable this code to test non-overlapping surfaces even
+ * if they need alpha blending.
+ */
+ if (es->overlapped)
+ ret = 0;
+ else
+ ret = 1;
+#endif
+ break;
+ case WL_SHM_FORMAT_XRGB8888:
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+drm_disable_unused_sprites(struct weston_output *output_base)
{
struct weston_compositor *ec = output_base->compositor;
struct drm_compositor *c =(struct drm_compositor *) ec;
struct drm_output *output = (struct drm_output *) output_base;
struct drm_sprite *s;
- int found = 0;
- EGLint handle, stride;
- struct gbm_bo *bo;
- uint32_t fb_id = 0;
- uint32_t handles[4], pitches[4], offsets[4];
int ret;
wl_list_for_each(s, &output->sprite_list, output_link) {
- if (!s->fb_id) {
- found = 1;
+ if (!s->ref.pending_fb_id) {
+ ret = drmModeSetPlane(c->drm.fd, s->plane_id,
+ output->crtc_id, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ if (ret)
+ fprintf(stderr,
+ "failed to disable plane: %d: %s\n",
+ ret, strerror(errno));
+ drmModeRmFB(c->drm.fd, s->fb_id);
break;
}
}
+}
- /* No sprites available */
- if (!found)
+static int
+drm_assign_overlay_surface(struct weston_output *output_base,
+ struct weston_surface *es)
+{
+ struct drm_output *output = (struct drm_output *) output_base;
+ struct drm_sprite *s;
+ int found = 0;
+ int ret;
+
+ if (es->image == EGL_NO_IMAGE_KHR)
return -1;
- bo = gbm_bo_create_from_egl_image(c->gbm, c->base.display, es->image,
- es->width, es->height,
- GBM_BO_USE_SCANOUT);
- handle = gbm_bo_get_handle(bo).s32;
- stride = gbm_bo_get_pitch(bo);
+ if (!drm_surface_format_supported(es))
+ return -1;
- gbm_bo_destroy(bo);
+ wl_list_for_each(s, &output->sprite_list, output_link) {
+ if (!s->ref.pending_fb_id) {
+ found = 1;
+ break;
+ }
+ }
- if (!handle)
+ /* No sprites available */
+ if (!found)
return -1;
- handles[0] = handle;
- pitches[0] = stride;
- offsets[0] = 0;
-
- ret = drmModeAddFB2(c->drm.fd, es->width, es->height,
- DRM_FORMAT_XRGB8888, handles, pitches, offsets,
- &fb_id, 0);
+ ret = drm_prepare_scanout_surface(output_base, es, &s->ref);
if (ret) {
fprintf(stderr, "addfb2 failed: %d\n", ret);
return -1;
}
- ret = drmModeSetPlane(c->drm.fd, s->plane_id, output->crtc_id, fb_id, 0,
- es->x, es->y, es->width, es->height, 0, 0,
- es->width, es->height);
- if (ret) {
- fprintf(stderr, "setplane failed %d: %s\n", ret,
- strerror(errno));
- return -1;
- }
+ s->dest_x = es->x;
+ s->dest_y = es->y;
+ s->dest_w = es->width;
+ s->dest_h = es->height;
+ s->src_x = 0;
+ s->src_y = 0;
+ s->src_w = es->width;
+ s->src_h = es->height;
return 0;
}
@@ -330,10 +520,8 @@ drm_assign_planes(struct weston_output *output)
es = container_of(ec->surface_list.next, struct weston_surface, link);
if (es->visual == WESTON_RGB_VISUAL) {
- if (!drm_output_prepare_scanout_surface(output, es)) {
- drm_queue_scanout_surface(output, es);
+ if (!drm_output_prepare_scanout_surface(output, es))
scanout = es;
- }
}
/*
@@ -349,14 +537,27 @@ drm_assign_planes(struct weston_output *output)
* the client buffer can be used directly for the sprite surface
* as we do for flipping full screen surfaces.
*/
- wl_list_for_each_reverse(es, &ec->surface_list, link) {
- if (es == scanout)
+ wl_list_for_each(es, &ec->surface_list, link) {
+ if (surface_is_primary(ec, es))
continue;
+ if (surface_is_cursor(ec, es))
+ continue;
+
+ /* FIXME: if an upper surface is on a hw plane, we don't
+ * need to track its overlap.
+ * FIXME: try to assign hw cursors here too, they're just
+ * special overlays
+ */
if (!drm_assign_overlay_surface(output, es))
pixman_region32_init(&es->damage);
+ else
+ pixman_region32_init_rect(&es->damage, es->x, es->y,
+ es->width, es->height);
}
+ drm_disable_unused_sprites(output);
+
return 0;
}
@@ -483,6 +684,7 @@ on_drm_input(int fd, uint32_t mask, void *data)
memset(&evctx, 0, sizeof evctx);
evctx.version = DRM_EVENT_CONTEXT_VERSION;
evctx.page_flip_handler = page_flip_handler;
+ evctx.vblank_handler = vblank_handler;
drmHandleEvent(fd, &evctx);
return 1;
@@ -635,6 +837,8 @@ create_sprites(struct drm_compositor *ec)
drmModeFreePlane(plane);
ec->sprite_allocator = (1 << sprite->plane_id);
+ drm_buffer_reference_init(&sprite->ref, ec);
+ sprite->fb_id = -1;
wl_list_insert(&ec->sprite_list, &sprite->link);
}
@@ -696,13 +900,14 @@ create_output_for_connector(struct drm_compositor *ec,
drmModeFreeEncoder(encoder);
wl_list_for_each(sprite, &ec->sprite_list, link) {
- for (i = 0; i < resources->count_crtcs; i++)
- if (sprite->possible_crtcs & (1 << i)) {
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (resources->crtcs[i] != output->crtc_id)
+ continue;
+
+ if (sprite->possible_crtcs & (1 << i))
wl_list_insert(&output->sprite_list,
&sprite->output_link);
- fprintf(stderr, "found sprite %d\n",
- sprite->plane_id);
- }
+ }
}
for (i = 0; i < connector->count_modes; i++) {
@@ -778,7 +983,7 @@ create_output_for_connector(struct drm_compositor *ec,
wl_list_insert(ec->base.output_list.prev, &output->base.link);
- output->pending_fs_surf_fb_id = 0;
+ drm_buffer_reference_init(&output->fb_reference, ec);
output->base.assign_planes = drm_assign_planes;
output->base.prepare_render = drm_output_prepare_render;
output->base.present = drm_output_present;
@@ -985,7 +1190,7 @@ drm_compositor_create_cursor_image(struct weston_compositor *ec,
bo = gbm_bo_create(c->gbm,
/* width, height, */ 64, 64,
GBM_BO_FORMAT_ARGB8888,
- GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_RENDERING);
+ GBM_BO_USE_CURSOR_64X64);
image = ec->create_image(c->base.display, NULL,
EGL_NATIVE_PIXMAP_KHR, bo, NULL);
diff --git a/src/compositor.c b/src/compositor.c
index 51038fa..5bc40a7 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -171,36 +171,6 @@ surface_handle_buffer_destroy(struct wl_listener *listener,
es->buffer = NULL;
}
-static void
-output_handle_scanout_buffer_destroy(struct wl_listener *listener,
- struct wl_resource *resource,
- uint32_t time)
-{
- struct weston_output *output =
- container_of(listener, struct weston_output,
- scanout_buffer_destroy_listener);
-
- output->scanout_buffer = NULL;
-
- if (!output->pending_scanout_buffer)
- weston_compositor_schedule_repaint(output->compositor);
-}
-
-static void
-output_handle_pending_scanout_buffer_destroy(struct wl_listener *listener,
- struct wl_resource *resource,
- uint32_t time)
-{
- struct weston_output *output =
- container_of(listener, struct weston_output,
- pending_scanout_buffer_destroy_listener);
-
- output->pending_scanout_buffer = NULL;
-
- weston_compositor_schedule_repaint(output->compositor);
-}
-
-
WL_EXPORT struct weston_surface *
weston_surface_create(struct weston_compositor *compositor,
int32_t x, int32_t y, int32_t width, int32_t height)
@@ -213,6 +183,7 @@ weston_surface_create(struct weston_compositor *compositor,
wl_list_init(&surface->link);
wl_list_init(&surface->buffer_link);
+ wl_list_init(&surface->output_link);
glGenTextures(1, &surface->texture);
glBindTexture(GL_TEXTURE_2D, surface->texture);
@@ -230,6 +201,7 @@ weston_surface_create(struct weston_compositor *compositor,
surface->width = width;
surface->height = height;
surface->alpha = 255;
+ surface->overlapped = 0;
surface->fullscreen_output = NULL;
surface->buffer = NULL;
@@ -394,6 +366,7 @@ destroy_surface(struct wl_resource *resource)
weston_surface_flush_damage(surface);
wl_list_remove(&surface->link);
+ wl_list_remove(&surface->output_link);
weston_compositor_repick(compositor);
if (surface->saved_texture == 0)
@@ -767,7 +740,8 @@ weston_output_repaint(struct weston_output *output)
{
struct weston_compositor *ec = output->compositor;
struct weston_surface *es;
- pixman_region32_t opaque, new_damage, total_damage, repaint;
+ pixman_region32_t opaque, new_damage, total_damage, repaint, overlap,
+ surf_intersect;
output->prepare_render(output);
@@ -801,12 +775,33 @@ weston_output_repaint(struct weston_output *output)
es = container_of(ec->surface_list.next, struct weston_surface, link);
+ pixman_region32_init(&overlap);
+
wl_list_for_each(es, &ec->surface_list, link) {
+ pixman_region32_init(&surf_intersect);
+
+ /* Set 'overlap' flags on each surface */
+ pixman_region32_intersect_rect(&surf_intersect, &overlap,
+ es->x, es->y,
+ es->width, es->height);
+ es->overlapped = pixman_region32_not_empty(&surf_intersect);
+
+ /* Sum the regions into the overlap area */
+ pixman_region32_union_rect(&overlap, &overlap, es->x, es->y,
+ es->width, es->height);
+
+ pixman_region32_fini(&surf_intersect);
+ }
+
+ wl_list_for_each(es, &ec->surface_list, link) {
+ /* Sum the damage for the screen by walking each surf damage */
pixman_region32_copy(&es->damage, &total_damage);
pixman_region32_subtract(&total_damage, &total_damage,
&es->opaque);
}
+ pixman_region32_fini(&overlap);
+
if (output->assign_planes)
/* This will queue flips for the fbs and sprites where
* applicable and clear the damage for those surfaces.
@@ -1795,11 +1790,6 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
output->flags = flags;
weston_output_move(output, x, y);
- output->scanout_buffer_destroy_listener.func =
- output_handle_scanout_buffer_destroy;
- output->pending_scanout_buffer_destroy_listener.func =
- output_handle_pending_scanout_buffer_destroy;
-
wl_list_init(&output->frame_callback_list);
wl_display_add_global(c->wl_display,
diff --git a/src/compositor.h b/src/compositor.h
index 759937b..3f8b783 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -82,10 +82,6 @@ struct weston_output {
struct weston_mode *current;
struct wl_list mode_list;
- struct wl_buffer *scanout_buffer;
- struct wl_listener scanout_buffer_destroy_listener;
- struct wl_buffer *pending_scanout_buffer;
- struct wl_listener pending_scanout_buffer_destroy_listener;
int (*prepare_render)(struct weston_output *output);
int (*present)(struct weston_output *output);
@@ -237,9 +233,11 @@ struct weston_surface {
int32_t pitch;
struct wl_list link;
struct wl_list buffer_link;
+ struct wl_list output_link;
struct weston_transform *transform;
uint32_t alpha;
uint32_t visual;
+ int overlapped;
/*
* Which output to vsync this surface to.
--
1.7.4.1
More information about the wayland-devel
mailing list