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.
This commit is contained in:
committed by
Kristian Høgsberg
parent
f9b2541df1
commit
47b87d5ec0
+147
-71
@@ -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[])
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user