nested: Add a ‘renderer’ mechanism with a vtable

Eventually the nested compositor example will want to be able to cope
with either rendering as it does now with a blit to an intermediate
surface or by attaching the client buffers directly to a subsurface
without copying. This patch moves the code that is specific to the
blitting mechanism into a separate set of functions with a vtable to
make it easier to add the second way of rendering in a later patch.
dev
Neil Roberts 11 years ago committed by Kristian Høgsberg
parent f9b2541df1
commit 47b87d5ec0
  1. 218
      clients/nested.c

@ -58,6 +58,8 @@ struct nested {
struct program *texture_program; struct program *texture_program;
struct wl_list surface_list; struct wl_list surface_list;
const struct nested_renderer *renderer;
}; };
struct nested_region { struct nested_region {
@ -79,12 +81,9 @@ struct nested_buffer_reference {
struct nested_surface { struct nested_surface {
struct wl_resource *resource; struct wl_resource *resource;
struct nested_buffer_reference buffer_ref;
struct nested *nested; struct nested *nested;
EGLImageKHR *image; EGLImageKHR *image;
GLuint texture;
struct wl_list link; struct wl_list link;
cairo_surface_t *cairo_surface;
struct wl_list frame_callback_list; struct wl_list frame_callback_list;
@ -100,6 +99,15 @@ struct nested_surface {
/* wl_surface.damage */ /* wl_surface.damage */
pixman_region32_t damage; pixman_region32_t damage;
} pending; } pending;
void *renderer_data;
};
/* Data used for the blit renderer */
struct nested_blit_surface {
struct nested_buffer_reference buffer_ref;
GLuint texture;
cairo_surface_t *cairo_surface;
}; };
struct nested_frame_callback { struct nested_frame_callback {
@ -107,6 +115,16 @@ struct nested_frame_callback {
struct wl_list link; struct wl_list link;
}; };
struct nested_renderer {
void (* surface_init)(struct nested_surface *surface);
void (* surface_fini)(struct nested_surface *surface);
void (* render_clients)(struct nested *nested, cairo_t *cr);
void (* surface_attach)(struct nested_surface *surface,
struct nested_buffer *buffer);
};
static const struct nested_renderer nested_blit_renderer;
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
static PFNEGLCREATEIMAGEKHRPROC create_image; static PFNEGLCREATEIMAGEKHRPROC create_image;
static PFNEGLDESTROYIMAGEKHRPROC destroy_image; static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
@ -208,23 +226,6 @@ flush_surface_frame_callback_list(struct nested_surface *surface,
wl_display_flush_clients(surface->nested->child_display); wl_display_flush_clients(surface->nested->child_display);
} }
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct nested *nested = data;
struct nested_surface *surface;
wl_list_for_each(surface, &nested->surface_list, link)
flush_surface_frame_callback_list(surface, time);
if (callback)
wl_callback_destroy(callback);
}
static const struct wl_callback_listener frame_listener = {
frame_callback
};
static void static void
redraw_handler(struct widget *widget, void *data) redraw_handler(struct widget *widget, void *data)
{ {
@ -232,8 +233,6 @@ redraw_handler(struct widget *widget, void *data)
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_t *cr; cairo_t *cr;
struct rectangle allocation; struct rectangle allocation;
struct wl_callback *callback;
struct nested_surface *s;
widget_get_allocation(nested->widget, &allocation); widget_get_allocation(nested->widget, &allocation);
@ -249,34 +248,11 @@ redraw_handler(struct widget *widget, void *data)
cairo_set_source_rgba(cr, 0, 0, 0, 0.8); cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_fill(cr); cairo_fill(cr);
wl_list_for_each(s, &nested->surface_list, link) { nested->renderer->render_clients(nested, cr);
display_acquire_window_surface(nested->display,
nested->window, NULL);
glBindTexture(GL_TEXTURE_2D, s->texture);
image_target_texture_2d(GL_TEXTURE_2D, s->image);
display_release_window_surface(nested->display,
nested->window);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_surface(cr, s->cairo_surface,
allocation.x + 10,
allocation.y + 10);
cairo_rectangle(cr, allocation.x + 10,
allocation.y + 10,
allocation.width - 10,
allocation.height - 10);
cairo_fill(cr);
}
cairo_destroy(cr); cairo_destroy(cr);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
callback = wl_surface_frame(window_get_wl_surface(nested->window));
wl_callback_add_listener(callback, &frame_listener, nested);
} }
static void static void
@ -377,6 +353,7 @@ static void
destroy_surface(struct wl_resource *resource) destroy_surface(struct wl_resource *resource)
{ {
struct nested_surface *surface = wl_resource_get_user_data(resource); struct nested_surface *surface = wl_resource_get_user_data(resource);
struct nested *nested = surface->nested;
struct nested_frame_callback *cb, *next; struct nested_frame_callback *cb, *next;
wl_list_for_each_safe(cb, next, wl_list_for_each_safe(cb, next,
@ -387,10 +364,10 @@ destroy_surface(struct wl_resource *resource)
&surface->pending.frame_callback_list, link) &surface->pending.frame_callback_list, link)
wl_resource_destroy(cb->resource); wl_resource_destroy(cb->resource);
nested_buffer_reference(&surface->buffer_ref, NULL);
pixman_region32_fini(&surface->pending.damage); pixman_region32_fini(&surface->pending.damage);
nested->renderer->surface_fini(surface);
wl_list_remove(&surface->link); wl_list_remove(&surface->link);
free(surface); free(surface);
@ -456,15 +433,9 @@ nested_surface_attach(struct nested_surface *surface,
struct nested_buffer *buffer) struct nested_buffer *buffer)
{ {
struct nested *nested = surface->nested; struct nested *nested = surface->nested;
EGLint width, height;
cairo_device_t *device;
nested_buffer_reference(&surface->buffer_ref, buffer);
if (surface->image != EGL_NO_IMAGE_KHR) if (surface->image != EGL_NO_IMAGE_KHR)
destroy_image(nested->egl_display, surface->image); destroy_image(nested->egl_display, surface->image);
if (surface->cairo_surface)
cairo_surface_destroy(surface->cairo_surface);
surface->image = create_image(nested->egl_display, NULL, surface->image = create_image(nested->egl_display, NULL,
EGL_WAYLAND_BUFFER_WL, buffer->resource, EGL_WAYLAND_BUFFER_WL, buffer->resource,
@ -474,17 +445,7 @@ nested_surface_attach(struct nested_surface *surface,
return; return;
} }
query_buffer(nested->egl_display, (void *) buffer->resource, nested->renderer->surface_attach(surface, buffer);
EGL_WIDTH, &width);
query_buffer(nested->egl_display, (void *) buffer->resource,
EGL_HEIGHT, &height);
device = display_get_cairo_device(nested->display);
surface->cairo_surface =
cairo_gl_surface_create_for_texture(device,
CAIRO_CONTENT_COLOR_ALPHA,
surface->texture,
width, height);
} }
static void static void
@ -633,12 +594,7 @@ compositor_create_surface(struct wl_client *client,
display_acquire_window_surface(nested->display, display_acquire_window_surface(nested->display,
nested->window, NULL); nested->window, NULL);
glGenTextures(1, &surface->texture); nested->renderer->surface_init(surface);
glBindTexture(GL_TEXTURE_2D, surface->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
display_release_window_surface(nested->display, nested->window); display_release_window_surface(nested->display, nested->window);
@ -776,6 +732,8 @@ nested_init_compositor(struct nested *nested)
return -1; return -1;
} }
nested->renderer = &nested_blit_renderer;
return 0; return 0;
} }
@ -813,6 +771,124 @@ nested_destroy(struct nested *nested)
free(nested); free(nested);
} }
static void
blit_surface_init(struct nested_surface *surface)
{
struct nested_blit_surface *blit_surface =
zalloc(sizeof *blit_surface);
glGenTextures(1, &blit_surface->texture);
glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
surface->renderer_data = blit_surface;
}
static void
blit_surface_fini(struct nested_surface *surface)
{
struct nested_blit_surface *blit_surface = surface->renderer_data;
nested_buffer_reference(&blit_surface->buffer_ref, NULL);
glDeleteTextures(1, &blit_surface->texture);
free(blit_surface);
}
static void
blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct nested *nested = data;
struct nested_surface *surface;
wl_list_for_each(surface, &nested->surface_list, link)
flush_surface_frame_callback_list(surface, time);
if (callback)
wl_callback_destroy(callback);
}
static const struct wl_callback_listener blit_frame_listener = {
blit_frame_callback
};
static void
blit_render_clients(struct nested *nested,
cairo_t *cr)
{
struct nested_surface *s;
struct rectangle allocation;
struct wl_callback *callback;
widget_get_allocation(nested->widget, &allocation);
wl_list_for_each(s, &nested->surface_list, link) {
struct nested_blit_surface *blit_surface = s->renderer_data;
display_acquire_window_surface(nested->display,
nested->window, NULL);
glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
image_target_texture_2d(GL_TEXTURE_2D, s->image);
display_release_window_surface(nested->display,
nested->window);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_surface(cr, blit_surface->cairo_surface,
allocation.x + 10,
allocation.y + 10);
cairo_rectangle(cr, allocation.x + 10,
allocation.y + 10,
allocation.width - 10,
allocation.height - 10);
cairo_fill(cr);
}
callback = wl_surface_frame(window_get_wl_surface(nested->window));
wl_callback_add_listener(callback, &blit_frame_listener, nested);
}
static void
blit_surface_attach(struct nested_surface *surface,
struct nested_buffer *buffer)
{
struct nested *nested = surface->nested;
struct nested_blit_surface *blit_surface = surface->renderer_data;
EGLint width, height;
cairo_device_t *device;
nested_buffer_reference(&blit_surface->buffer_ref, buffer);
if (blit_surface->cairo_surface)
cairo_surface_destroy(blit_surface->cairo_surface);
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);
blit_surface->cairo_surface =
cairo_gl_surface_create_for_texture(device,
CAIRO_CONTENT_COLOR_ALPHA,
blit_surface->texture,
width, height);
}
static const struct nested_renderer
nested_blit_renderer = {
.surface_init = blit_surface_init,
.surface_fini = blit_surface_fini,
.render_clients = blit_render_clients,
.surface_attach = blit_surface_attach
};
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {

Loading…
Cancel
Save