nested: Add double-buffered state semantics to the nested example
The buffer and frame callback state on the surfaces in the nested compositor example are now double-buffered so that they only take effect when the commit request is received. This doesn't really make much difference for the current state that the example has but it will be useful when more state is added in later patches.
This commit is contained in:
parent
6bf23879e9
commit
15a8d340fd
130
clients/nested.c
130
clients/nested.c
@ -86,6 +86,16 @@ struct nested_surface {
|
||||
GLuint texture;
|
||||
struct wl_list link;
|
||||
cairo_surface_t *cairo_surface;
|
||||
|
||||
struct {
|
||||
/* wl_surface.attach */
|
||||
int newly_attached;
|
||||
struct nested_buffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
|
||||
/* wl_surface.frame */
|
||||
struct wl_list frame_callback_list;
|
||||
} pending;
|
||||
};
|
||||
|
||||
struct nested_frame_callback {
|
||||
@ -353,6 +363,11 @@ static void
|
||||
destroy_surface(struct wl_resource *resource)
|
||||
{
|
||||
struct nested_surface *surface = wl_resource_get_user_data(resource);
|
||||
struct nested_frame_callback *cb, *next;
|
||||
|
||||
wl_list_for_each_safe(cb, next,
|
||||
&surface->pending.frame_callback_list, link)
|
||||
wl_resource_destroy(cb->resource);
|
||||
|
||||
nested_buffer_reference(&surface->buffer_ref, NULL);
|
||||
|
||||
@ -374,45 +389,75 @@ surface_attach(struct wl_client *client,
|
||||
{
|
||||
struct nested_surface *surface = wl_resource_get_user_data(resource);
|
||||
struct nested *nested = surface->nested;
|
||||
EGLint format, width, height;
|
||||
struct nested_buffer *buffer = NULL;
|
||||
|
||||
if (buffer_resource) {
|
||||
int format;
|
||||
|
||||
if (!query_buffer(nested->egl_display, (void *) buffer_resource,
|
||||
EGL_TEXTURE_FORMAT, &format)) {
|
||||
wl_resource_post_error(buffer_resource,
|
||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
"attaching non-egl wl_buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case EGL_TEXTURE_RGB:
|
||||
case EGL_TEXTURE_RGBA:
|
||||
break;
|
||||
default:
|
||||
wl_resource_post_error(buffer_resource,
|
||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
"invalid format");
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = nested_buffer_from_resource(buffer_resource);
|
||||
if (buffer == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->pending.buffer)
|
||||
wl_list_remove(&surface->pending.buffer_destroy_listener.link);
|
||||
|
||||
surface->pending.buffer = buffer;
|
||||
surface->pending.newly_attached = 1;
|
||||
if (buffer) {
|
||||
wl_signal_add(&buffer->destroy_signal,
|
||||
&surface->pending.buffer_destroy_listener);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nested_surface_attach(struct nested_surface *surface,
|
||||
struct nested_buffer *buffer)
|
||||
{
|
||||
struct nested *nested = surface->nested;
|
||||
EGLint width, height;
|
||||
cairo_device_t *device;
|
||||
struct nested_buffer *buffer =
|
||||
nested_buffer_from_resource(buffer_resource);
|
||||
|
||||
nested_buffer_reference(&surface->buffer_ref, buffer);
|
||||
|
||||
if (!query_buffer(nested->egl_display, (void *) buffer_resource,
|
||||
EGL_TEXTURE_FORMAT, &format)) {
|
||||
fprintf(stderr, "attaching non-egl wl_buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->image != EGL_NO_IMAGE_KHR)
|
||||
destroy_image(nested->egl_display, surface->image);
|
||||
if (surface->cairo_surface)
|
||||
cairo_surface_destroy(surface->cairo_surface);
|
||||
|
||||
switch (format) {
|
||||
case EGL_TEXTURE_RGB:
|
||||
case EGL_TEXTURE_RGBA:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unhandled format: %x\n", format);
|
||||
return;
|
||||
}
|
||||
|
||||
surface->image = create_image(nested->egl_display, NULL,
|
||||
EGL_WAYLAND_BUFFER_WL, buffer_resource,
|
||||
EGL_WAYLAND_BUFFER_WL, buffer->resource,
|
||||
NULL);
|
||||
if (surface->image == EGL_NO_IMAGE_KHR) {
|
||||
fprintf(stderr, "failed to create img\n");
|
||||
return;
|
||||
}
|
||||
|
||||
query_buffer(nested->egl_display,
|
||||
(void *) buffer_resource, EGL_WIDTH, &width);
|
||||
query_buffer(nested->egl_display,
|
||||
(void *) buffer_resource, EGL_HEIGHT, &height);
|
||||
query_buffer(nested->egl_display, (void *) buffer->resource,
|
||||
EGL_WIDTH, &width);
|
||||
query_buffer(nested->egl_display, (void *) buffer->resource,
|
||||
EGL_HEIGHT, &height);
|
||||
|
||||
device = display_get_cairo_device(nested->display);
|
||||
surface->cairo_surface =
|
||||
@ -420,8 +465,6 @@ surface_attach(struct wl_client *client,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
surface->texture,
|
||||
width, height);
|
||||
|
||||
window_schedule_redraw(nested->window);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -446,7 +489,6 @@ surface_frame(struct wl_client *client,
|
||||
{
|
||||
struct nested_frame_callback *callback;
|
||||
struct nested_surface *surface = wl_resource_get_user_data(resource);
|
||||
struct nested *nested = surface->nested;
|
||||
|
||||
callback = malloc(sizeof *callback);
|
||||
if (callback == NULL) {
|
||||
@ -459,7 +501,8 @@ surface_frame(struct wl_client *client,
|
||||
wl_resource_set_implementation(callback->resource, NULL, callback,
|
||||
destroy_frame_callback);
|
||||
|
||||
wl_list_insert(nested->frame_callback_list.prev, &callback->link);
|
||||
wl_list_insert(surface->pending.frame_callback_list.prev,
|
||||
&callback->link);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -481,6 +524,25 @@ surface_set_input_region(struct wl_client *client,
|
||||
static void
|
||||
surface_commit(struct wl_client *client, struct wl_resource *resource)
|
||||
{
|
||||
struct nested_surface *surface = wl_resource_get_user_data(resource);
|
||||
struct nested *nested = surface->nested;
|
||||
|
||||
/* wl_surface.attach */
|
||||
if (surface->pending.newly_attached)
|
||||
nested_surface_attach(surface, surface->pending.buffer);
|
||||
|
||||
if (surface->pending.buffer) {
|
||||
wl_list_remove(&surface->pending.buffer_destroy_listener.link);
|
||||
surface->pending.buffer = NULL;
|
||||
}
|
||||
surface->pending.newly_attached = 0;
|
||||
|
||||
/* wl_surface.frame */
|
||||
wl_list_insert_list(&nested->frame_callback_list,
|
||||
&surface->pending.frame_callback_list);
|
||||
wl_list_init(&surface->pending.frame_callback_list);
|
||||
|
||||
window_schedule_redraw(nested->window);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -501,6 +563,16 @@ static const struct wl_surface_interface surface_interface = {
|
||||
surface_set_buffer_transform
|
||||
};
|
||||
|
||||
static void
|
||||
surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct nested_surface *surface =
|
||||
container_of(listener, struct nested_surface,
|
||||
pending.buffer_destroy_listener);
|
||||
|
||||
surface->pending.buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
compositor_create_surface(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id)
|
||||
@ -516,6 +588,10 @@ compositor_create_surface(struct wl_client *client,
|
||||
|
||||
surface->nested = nested;
|
||||
|
||||
wl_list_init(&surface->pending.frame_callback_list);
|
||||
surface->pending.buffer_destroy_listener.notify =
|
||||
surface_handle_pending_buffer_destroy;
|
||||
|
||||
display_acquire_window_surface(nested->display,
|
||||
nested->window, NULL);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user