libpepper_la_SOURCES += modules/wayland/wayland-internal.h \
modules/wayland/wayland-common.c \
modules/wayland/wayland-output.c \
- modules/wayland/wayland-input.c
+ modules/wayland/wayland-input.c \
+ modules/wayland/wayland-shm-buffer.c
endif
# drm backend
}
static pepper_bool_t
-gl_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
+gl_renderer_read_pixels(pepper_renderer_t *r, void *target,
+ int x, int y, int w, int h,
void *pixels, pepper_format_t format)
{
gl_renderer_t *renderer = (gl_renderer_t *)r;
return PEPPER_TRUE;
}
-static pepper_bool_t
-gl_renderer_set_render_target(pepper_renderer_t *r, void *target)
-{
- /* Can't change gl renderer's render target. */
- return PEPPER_FALSE;
-}
-
static void
-gl_renderer_draw(pepper_renderer_t *r, void *data)
+gl_renderer_draw(pepper_renderer_t *r, void *target, void *data)
{
gl_renderer_t *renderer = (gl_renderer_t *)r;
renderer->base.destroy = gl_renderer_destroy;
renderer->base.read_pixels = gl_renderer_read_pixels;
- renderer->base.set_render_target = gl_renderer_set_render_target;
renderer->base.draw = gl_renderer_draw;
return &renderer->base;
{
conn->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
}
+ else if (strcmp(interface, "wl_shm") == 0)
+ {
+ conn->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ }
}
static void
loop = wl_display_get_event_loop(compositor_display);
conn->event_source = wl_event_loop_add_fd(loop, conn->fd, WL_EVENT_READABLE,
handle_wayland_event, conn);
+ wl_event_source_check(conn->event_source);
wl_list_init(&conn->seat_list);
wl_signal_init(&conn->destroy_signal);
struct wl_signal destroy_signal;
+ struct wl_shm *shm;
+
};
struct wayland_shm_buffer
{
+ wayland_output_t *output;
+ struct wl_list link;
+
struct wl_buffer *buffer;
+
void *pixels;
+ int stride;
int size;
+ int w, h;
+
pixman_image_t *image;
pixman_region32_t damage;
- void *data;
- struct wl_list link;
+ void *data;
};
struct wayland_output
pepper_renderer_t *renderer;
+ void (*render_pre)(wayland_output_t *output);
+ void (*render_post)(wayland_output_t *output);
+
struct {
- /* list containing free wl_shm_buffers. */
+ /* list containing free buffers. */
struct wl_list free_buffers;
+
+ /* list containing attached but not released (from the compositor) buffers. */
+ struct wl_list attached_buffers;
+
+ /* current render target buffer. */
+ wayland_shm_buffer_t *current_buffer;
} shm;
#if ENABLE_WAYLAND_BACKEND_EGL
void
wayland_handle_global_seat(pepper_wayland_t *conn, struct wl_registry *registry,
uint32_t name, uint32_t version);
+
+wayland_shm_buffer_t *
+wayland_shm_buffer_create(wayland_output_t *output);
+
+void
+wayland_shm_buffer_destroy(wayland_shm_buffer_t *buffer);
shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges,
int32_t w, int32_t h)
{
- wayland_output_t *output = data;
+ wayland_output_t *output = data;
+ wayland_shm_buffer_t *buffer, *next;
PEPPER_IGNORE(shell_surface);
PEPPER_IGNORE(edges);
output->w = w;
output->h = h;
+ /* Destroy free buffers immediately. */
+ wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, link)
+ wayland_shm_buffer_destroy(buffer);
+
+ /* Orphan attached buffers. They will be destroyed when the compositor releases them. */
+ wl_list_for_each_safe(buffer, next, &output->shm.attached_buffers, link)
+ {
+ buffer->output = NULL;
+ wl_list_remove(&buffer->link);
+ }
+
+ PEPPER_ASSERT(wl_list_empty(&output->shm.free_buffers));
+ PEPPER_ASSERT(wl_list_empty(&output->shm.attached_buffers));
+
+ /* We are ready to emit mode change signal. */
wl_signal_emit(&output->mode_change_signal, NULL);
}
}
static void
+frame_done(void *data, struct wl_callback *callback, uint32_t time)
+{
+ wayland_output_t *output = data;
+
+ wl_callback_destroy(callback);
+ wl_signal_emit(&output->frame_signal, NULL);
+}
+
+static const struct wl_callback_listener frame_listener =
+{
+ frame_done,
+};
+
+static void
wayland_output_repaint(void *o)
{
- wayland_output_t *output = o;
+ wayland_output_t *output = o;
+ struct wl_callback *callback;
+
+ if (output->render_pre)
+ output->render_pre(output);
/* TODO: Pass rendering data to the renderer. maybe view list? or scene graph data? */
- output->renderer->draw(output->renderer, NULL);
+ output->renderer->draw(output->renderer, output->shm.current_buffer->image, NULL);
+
+ if (output->render_post)
+ output->render_post(output);
+
+ callback = wl_surface_frame(output->surface);
+ wl_callback_add_listener(callback, &frame_listener, output);
+ wl_surface_commit(output->surface);
+ wl_display_flush(output->conn->display);
}
static void
wayland_output_destroy(output);
}
+static void
+pixman_render_pre(wayland_output_t *output)
+{
+ wayland_shm_buffer_t *buffer = NULL;
+
+ if (wl_list_empty(&output->shm.free_buffers))
+ {
+ buffer = wayland_shm_buffer_create(output);
+ }
+ else
+ {
+ buffer = wl_container_of(output->shm.free_buffers.next, buffer, link);
+ wl_list_remove(&buffer->link);
+ }
+
+ wl_list_insert(output->shm.attached_buffers.prev, &buffer->link);
+ output->shm.current_buffer = buffer;
+}
+
+static void
+pixman_render_post(wayland_output_t *output)
+{
+ wl_surface_attach(output->surface, output->shm.current_buffer->buffer, 0, 0);
+ wl_surface_damage(output->surface, 0, 0, output->w, output->h);
+}
+
static pepper_bool_t
init_gl_renderer(wayland_output_t *output)
{
init_pixman_renderer(wayland_output_t *output)
{
wl_list_init(&output->shm.free_buffers);
+ wl_list_init(&output->shm.attached_buffers);
output->renderer = pepper_pixman_renderer_create();
if (output->renderer)
+ {
+ output->render_pre = pixman_render_pre;
+ output->render_post = pixman_render_post;
return PEPPER_TRUE;
+ }
return PEPPER_FALSE;
}
output->surface = wl_compositor_create_surface(conn->compositor);
output->shell_surface = wl_shell_get_shell_surface(conn->shell, output->surface);
wl_shell_surface_add_listener(output->shell_surface, &shell_surface_listener, output);
+ wl_shell_surface_set_toplevel(output->shell_surface);
/* Add compositor base class output object for this output. */
base = pepper_compositor_add_output(conn->pepper, &wayland_output_interface, output);
--- /dev/null
+#include "wayland-internal.h"
+#include <pepper-os-compat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static void
+buffer_release(void *data, struct wl_buffer *buf)
+{
+ wayland_shm_buffer_t *buffer = data;
+
+ if (buffer->output)
+ {
+ /* Move to free buffer list. */
+ wl_list_remove(&buffer->link);
+ wl_list_insert(buffer->output->shm.free_buffers.next, &buffer->link);
+ }
+ else
+ {
+ /* Orphaned buffer due to output resize or something. Destroy it. */
+ wayland_shm_buffer_destroy(buffer);
+ }
+}
+
+static const struct wl_buffer_listener buffer_listener =
+{
+ buffer_release,
+};
+
+wayland_shm_buffer_t *
+wayland_shm_buffer_create(wayland_output_t *output)
+{
+ wayland_shm_buffer_t *buffer;
+ int fd;
+ struct wl_shm_pool *pool;
+
+ buffer = pepper_calloc(1, sizeof(wayland_shm_buffer_t));
+ if (!buffer)
+ return NULL;
+
+ buffer->output = output;
+ wl_list_init(&buffer->link);
+
+ buffer->w = output->w;
+ buffer->h = output->h;
+ buffer->stride = buffer->w * 4;
+ buffer->size = buffer->stride * buffer->h;
+
+ fd = pepper_create_anonymous_file(buffer->size);
+
+ if (fd < 0)
+ {
+ PEPPER_ERROR("Failed to create anonymous file");
+ goto error;
+ }
+
+ buffer->pixels = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (!buffer->pixels)
+ {
+ PEPPER_ERROR("mmap() failed for fd=%d\n", fd);
+ goto error;
+ }
+
+ pool = wl_shm_create_pool(output->conn->shm, fd, buffer->size);
+ buffer->buffer = wl_shm_pool_create_buffer(pool, 0, buffer->w, buffer->h,
+ buffer->stride, WL_SHM_FORMAT_ARGB8888);
+ wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ buffer->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, buffer->w, buffer->h,
+ buffer->pixels, buffer->stride);
+ pixman_region32_init_rect(&buffer->damage, 0, 0, buffer->w, buffer->h);
+
+ return buffer;
+
+error:
+ if (fd >= 0)
+ close(fd);
+
+ if (buffer)
+ pepper_free(buffer);
+
+ return NULL;
+}
+
+void
+wayland_shm_buffer_destroy(wayland_shm_buffer_t *buffer)
+{
+ pixman_region32_fini(&buffer->damage);
+ pixman_image_unref(buffer->image);
+ wl_buffer_destroy(buffer->buffer);
+ munmap(buffer->pixels, buffer->size);
+ wl_list_remove(&buffer->link);
+}
{
/* We can repaint a frame immediately if it is not in pending state. */
pepper_output_repaint(output);
- return;
}
}
output->frame.frame_listener.notify = handle_output_frame;
interface->add_frame_listener(data, &output->frame.frame_listener);
+ pepper_output_schedule_repaint(output);
+
return output;
}
{
void (*destroy)(pepper_renderer_t *renderer);
- pepper_bool_t (*read_pixels)(pepper_renderer_t *renderer, int x, int y, int w, int h,
+ pepper_bool_t (*read_pixels)(pepper_renderer_t *renderer, void *target,
+ int x, int y, int w, int h,
void *pixels, pepper_format_t format);
- pepper_bool_t (*set_render_target)(pepper_renderer_t *renderer, void *target);
- void (*draw)(pepper_renderer_t *renderer, void *data /* TODO: */);
+ void (*draw)(pepper_renderer_t *renderer, void *data, void *target);
};
PEPPER_API void
struct pixman_renderer
{
pepper_renderer_t base;
-
- pixman_image_t *target;
};
static PEPPER_INLINE pixman_format_code_t
pixman_renderer_destroy(pepper_renderer_t *r)
{
pixman_renderer_t *renderer = (pixman_renderer_t *)r;
-
- if (renderer->target)
- pixman_image_unref(renderer->target);
-
pepper_free(renderer);
}
static pepper_bool_t
-pixman_renderer_read_pixels(pepper_renderer_t *r, int x, int y, int w, int h,
+pixman_renderer_read_pixels(pepper_renderer_t *r, void *target,
+ int x, int y, int w, int h,
void *pixels, pepper_format_t format)
{
- pixman_renderer_t *renderer = (pixman_renderer_t *)r;
+ pixman_image_t *image = (pixman_image_t *)target;
pixman_image_t *dst;
pixman_format_code_t pixman_format;
int stride;
- if (!renderer->target)
+ if (!image)
return PEPPER_FALSE;
pixman_format = get_pixman_format(format);
return PEPPER_FALSE;
}
- pixman_image_composite(PIXMAN_OP_SRC, renderer->target, NULL, dst, x, y, 0, 0, 0, 0, w, h);
- return PEPPER_TRUE;
-}
-
-static pepper_bool_t
-pixman_renderer_set_render_target(pepper_renderer_t *r, void *target)
-{
- pixman_renderer_t *renderer = (pixman_renderer_t *)r;
- pixman_image_t *image = target;
-
- if (renderer->target)
- pixman_image_unref(renderer->target);
-
- pixman_image_ref(image);
- renderer->target = image;
-
+ pixman_image_composite(PIXMAN_OP_SRC, image, NULL, dst, x, y, 0, 0, 0, 0, w, h);
return PEPPER_TRUE;
}
static void
-pixman_renderer_draw(pepper_renderer_t *r, void *data)
+pixman_renderer_draw(pepper_renderer_t *r, void *target, void *data)
{
- pixman_renderer_t *renderer = (pixman_renderer_t *)r;
+ pixman_image_t *image = (pixman_image_t *)target;
- if (renderer->target)
+ if (image)
{
/* TODO: */
- pixman_image_t *image = renderer->target;
pixman_fill(pixman_image_get_data(image),
- pixman_image_get_stride(image),
+ pixman_image_get_stride(image) / sizeof(uint32_t),
PIXMAN_FORMAT_BPP(pixman_image_get_format(image)),
0, 0,
pixman_image_get_width(image),
renderer->base.destroy = pixman_renderer_destroy;
renderer->base.read_pixels = pixman_renderer_read_pixels;
- renderer->base.set_render_target = pixman_renderer_set_render_target;
renderer->base.draw = pixman_renderer_draw;
return &renderer->base;