On Mon, Jan 07, 2013 at 08:39:50PM +0300, Vasily Khoruzhick wrote: > When --use-shm is passed to weston and x11 backend is active, > it will use SHM surfaces with pixman renderer instead of EGL > > Signed-off-by: Vasily Khoruzhick <[email protected]> > --- > v2: - handle missing MIT-SHM extension gracefully (tested with Xnest) > - follow libc convention of error handling > - get rid of xcb-aux dependency
Looks good, committed. Is there a reason you don't just use visual_type->depth instead of get_depth_of_visual()? Maybe I'm missing something. Also, to test the pixman renderer with desktop shell, I have to comment out #define HAVE_CAIRO_EGL 1 in config.h, since we don't have a configure option to disable that. If you feel like making a patch to add --disable-egl or such, that would be great. And of course, it would be nice to make the pixman-renderer work with the kms backend. Anyway, thanks a lot, I really appreciate this work. It's a great validation of the weston_renderer infrastructure and of course it's very cool that we can now run weston without hw acceleration without having to rely on sw mesa. Kristian > src/compositor-x11.c | 355 > +++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 342 insertions(+), 13 deletions(-) > > diff --git a/src/compositor-x11.c b/src/compositor-x11.c > index 04a1803..a994a97 100644 > --- a/src/compositor-x11.c > +++ b/src/compositor-x11.c > @@ -1,6 +1,7 @@ > /* > * Copyright © 2008-2011 Kristian Høgsberg > * Copyright © 2010-2011 Intel Corporation > + * Copyright © 2013 Vasily Khoruzhick <[email protected]> > * > * Permission to use, copy, modify, distribute, and sell this software and > * its documentation for any purpose is hereby granted without fee, provided > @@ -33,9 +34,11 @@ > #include <unistd.h> > #include <errno.h> > #include <sys/time.h> > +#include <sys/shm.h> > #include <linux/input.h> > > #include <xcb/xcb.h> > +#include <xcb/shm.h> > #ifdef HAVE_XCB_XKB > #include <xcb/xkb.h> > #endif > @@ -47,6 +50,7 @@ > > #include "compositor.h" > #include "gl-renderer.h" > +#include "pixman-renderer.h" > #include "../shared/config-parser.h" > #include "../shared/cairo-util.h" > > @@ -79,6 +83,7 @@ struct x11_compositor { > struct xkb_keymap *xkb_keymap; > unsigned int has_xkb; > uint8_t xkb_event_base; > + int use_shm; > > /* We could map multi-pointer X to multiple wayland seats, but > * for now we only support core X input. */ > @@ -107,6 +112,15 @@ struct x11_output { > xcb_window_t window; > struct weston_mode mode; > struct wl_event_source *finish_frame_timer; > + > + xcb_gc_t gc; > + xcb_shm_seg_t segment; > + pixman_image_t *hw_surface; > + pixman_image_t *shadow_surface; > + int shm_id; > + void *buf; > + void *shadow_buf; > + uint8_t depth; > }; > > static struct xkb_keymap * > @@ -307,16 +321,95 @@ x11_input_destroy(struct x11_compositor *compositor) > } > > static void > -x11_output_repaint(struct weston_output *output_base, > - pixman_region32_t *damage) > +x11_output_repaint_gl(struct weston_output *output_base, > + pixman_region32_t *damage) > +{ > + struct x11_output *output = (struct x11_output *)output_base; > + struct weston_compositor *ec = output->base.compositor; > + > + ec->renderer->repaint_output(output_base, damage); > + > + pixman_region32_subtract(&ec->primary_plane.damage, > + &ec->primary_plane.damage, damage); > + > + wl_event_source_timer_update(output->finish_frame_timer, 10); > +} > + > +static void > +x11_output_repaint_shm(struct weston_output *output_base, > + pixman_region32_t *damage) > { > struct x11_output *output = (struct x11_output *)output_base; > struct weston_compositor *ec = output->base.compositor; > + struct x11_compositor *c = (struct x11_compositor *)ec; > + pixman_box32_t *rects; > + int nrects, i, src_x, src_y, x1, y1, x2, y2, width, height; > + xcb_void_cookie_t cookie; > + xcb_generic_error_t *err; > > + pixman_renderer_output_set_buffer(output_base, output->shadow_surface); > ec->renderer->repaint_output(output_base, damage); > > + width = pixman_image_get_width(output->shadow_surface); > + height = pixman_image_get_height(output->shadow_surface); > + rects = pixman_region32_rectangles(damage, &nrects); > + for (i = 0; i < nrects; i++) { > + switch (output_base->transform) { > + default: > + case WL_OUTPUT_TRANSFORM_NORMAL: > + x1 = rects[i].x1; > + x2 = rects[i].x2; > + y1 = rects[i].y1; > + y2 = rects[i].y2; > + break; > + case WL_OUTPUT_TRANSFORM_180: > + x1 = width - rects[i].x2; > + x2 = width - rects[i].x1; > + y1 = height - rects[i].y2; > + y2 = height - rects[i].y1; > + break; > + case WL_OUTPUT_TRANSFORM_90: > + x1 = height - rects[i].y2; > + x2 = height - rects[i].y1; > + y1 = rects[i].x1; > + y2 = rects[i].x2; > + break; > + case WL_OUTPUT_TRANSFORM_270: > + x1 = rects[i].y1; > + x2 = rects[i].y2; > + y1 = width - rects[i].x2; > + y2 = width - rects[i].x1; > + break; > + } > + src_x = x1; > + src_y = y1; > + > + pixman_image_composite32(PIXMAN_OP_SRC, > + output->shadow_surface, /* src */ > + NULL /* mask */, > + output->hw_surface, /* dest */ > + src_x, src_y, /* src_x, src_y */ > + 0, 0, /* mask_x, mask_y */ > + x1, y1, /* dest_x, dest_y */ > + x2 - x1, /* width */ > + y2 - y1 /* height */); > + } > + > pixman_region32_subtract(&ec->primary_plane.damage, > &ec->primary_plane.damage, damage); > + cookie = xcb_shm_put_image_checked(c->conn, output->window, output->gc, > + > pixman_image_get_width(output->hw_surface), > + > pixman_image_get_height(output->hw_surface), > + 0, 0, > + > pixman_image_get_width(output->hw_surface), > + > pixman_image_get_height(output->hw_surface), > + 0, 0, output->depth, > XCB_IMAGE_FORMAT_Z_PIXMAP, > + 0, output->segment, 0); > + err = xcb_request_check(c->conn, cookie); > + if (err != NULL) { > + weston_log("Failed to put shm image, err: %d\n", > err->error_code); > + free(err); > + } > > wl_event_source_timer_update(output->finish_frame_timer, 10); > } > @@ -336,6 +429,28 @@ finish_frame_handler(void *data) > } > > static void > +x11_output_deinit_shm(struct x11_compositor *c, struct x11_output *output) > +{ > + xcb_void_cookie_t cookie; > + xcb_generic_error_t *err; > + xcb_free_gc(c->conn, output->gc); > + > + pixman_image_unref(output->hw_surface); > + output->hw_surface = NULL; > + cookie = xcb_shm_detach_checked(c->conn, output->segment); > + err = xcb_request_check(c->conn, cookie); > + if (err) { > + weston_log("xcb_shm_detach failed, error %d\n", > err->error_code); > + free(err); > + } > + shmdt(output->buf); > + > + pixman_image_unref(output->shadow_surface); > + output->shadow_surface = NULL; > + free(output->shadow_buf); > +} > + > +static void > x11_output_destroy(struct weston_output *output_base) > { > struct x11_output *output = (struct x11_output *)output_base; > @@ -345,7 +460,11 @@ x11_output_destroy(struct weston_output *output_base) > wl_list_remove(&output->base.link); > wl_event_source_remove(output->finish_frame_timer); > > - gl_renderer_output_destroy(output_base); > + if (compositor->use_shm) { > + pixman_renderer_output_destroy(output_base); > + x11_output_deinit_shm(compositor, output); > + } else > + gl_renderer_output_destroy(output_base); > > xcb_destroy_window(compositor->conn, output->window); > > @@ -456,6 +575,186 @@ x11_output_wait_for_map(struct x11_compositor *c, > struct x11_output *output) > } > } > > +static xcb_visualtype_t * > +find_visual_by_id(xcb_screen_t *screen, > + xcb_visualid_t id) > +{ > + xcb_depth_iterator_t i; > + xcb_visualtype_iterator_t j; > + for (i = xcb_screen_allowed_depths_iterator(screen); > + i.rem; > + xcb_depth_next(&i)) { > + for (j = xcb_depth_visuals_iterator(i.data); > + j.rem; > + xcb_visualtype_next(&j)) { > + if (j.data->visual_id == id) > + return j.data; > + } > + } > + return 0; > +} > + > +static uint8_t > +get_depth_of_visual(xcb_screen_t *screen, > + xcb_visualid_t id) > +{ > + xcb_depth_iterator_t i; > + xcb_visualtype_iterator_t j; > + for (i = xcb_screen_allowed_depths_iterator(screen); > + i.rem; > + xcb_depth_next(&i)) { > + for (j = xcb_depth_visuals_iterator(i.data); > + j.rem; > + xcb_visualtype_next(&j)) { > + if (j.data->visual_id == id) > + return i.data->depth; > + } > + } > + return 0; > +} > + > +static int > +x11_output_init_shm(struct x11_compositor *c, struct x11_output *output, > + int width, int height) > +{ > + xcb_screen_iterator_t iter; > + xcb_visualtype_t *visual_type; > + xcb_format_iterator_t fmt; > + xcb_void_cookie_t cookie; > + xcb_generic_error_t *err; > + int shadow_width, shadow_height; > + pixman_transform_t transform; > + const xcb_query_extension_reply_t *ext; > + int bitsperpixel = 0; > + pixman_format_code_t pixman_format; > + > + /* Check if SHM is available */ > + ext = xcb_get_extension_data(c->conn, &xcb_shm_id); > + if (ext == NULL || !ext->present) { > + /* SHM is missing */ > + weston_log("SHM extension is not available\n"); > + errno = ENOENT; > + return -1; > + } > + > + iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn)); > + visual_type = find_visual_by_id(iter.data, iter.data->root_visual); > + if (!visual_type) { > + weston_log("Failed to lookup visual for root window\n"); > + errno = ENOENT; > + return -1; > + } > + weston_log("Found visual, bits per value: %d, red_mask: %.8x, > green_mask: %.8x, blue_mask: %.8x\n", > + visual_type->bits_per_rgb_value, > + visual_type->red_mask, > + visual_type->green_mask, > + visual_type->blue_mask); > + output->depth = get_depth_of_visual(iter.data, iter.data->root_visual); > + weston_log("Visual depth is %d\n", output->depth); > + > + for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(c->conn)); > + fmt.rem; > + xcb_format_next(&fmt)) { > + if (fmt.data->depth == output->depth) { > + bitsperpixel = fmt.data->bits_per_pixel; > + break; > + } > + } > + weston_log("Found format for depth %d, bpp: %d\n", > + output->depth, bitsperpixel); > + > + if (bitsperpixel == 32 && > + visual_type->red_mask == 0xff0000 && > + visual_type->green_mask == 0x00ff00 && > + visual_type->blue_mask == 0x0000ff) { > + weston_log("Will use x8r8g8b8 format for SHM surfaces\n"); > + pixman_format = PIXMAN_x8r8g8b8; > + } else { > + weston_log("Can't find appropriate format for SHM pixmap\n"); > + errno = ENOTSUP; > + return -1; > + } > + > + > + /* Create SHM segment and attach it */ > + output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / > 8), IPC_CREAT | S_IRWXU); > + if (output->shm_id == -1) { > + weston_log("x11shm: failed to allocate SHM segment\n"); > + return -1; > + } > + output->buf = shmat(output->shm_id, NULL, 0 /* read/write */); > + if (-1 == (long)output->buf) { > + weston_log("x11shm: failed to attach SHM segment\n"); > + return -1; > + } > + output->segment = xcb_generate_id(c->conn); > + cookie = xcb_shm_attach_checked(c->conn, output->segment, > output->shm_id, 1); > + err = xcb_request_check(c->conn, cookie); > + if (err) { > + weston_log("x11shm: xcb_shm_attach error %d\n", > err->error_code); > + free(err); > + return -1; > + } > + > + shmctl(output->shm_id, IPC_RMID, NULL); > + > + /* Now create pixman image */ > + output->hw_surface = pixman_image_create_bits(pixman_format, width, > height, output->buf, > + width * (bitsperpixel / 8)); > + pixman_transform_init_identity(&transform); > + switch (output->base.transform) { > + default: > + case WL_OUTPUT_TRANSFORM_NORMAL: > + shadow_width = width; > + shadow_height = height; > + pixman_transform_rotate(&transform, > + NULL, 0, 0); > + pixman_transform_translate(&transform, NULL, > + 0, 0); > + break; > + case WL_OUTPUT_TRANSFORM_180: > + shadow_width = width; > + shadow_height = height; > + pixman_transform_rotate(&transform, > + NULL, -pixman_fixed_1, 0); > + pixman_transform_translate(NULL, &transform, > + pixman_int_to_fixed(shadow_width), > + pixman_int_to_fixed(shadow_height)); > + break; > + case WL_OUTPUT_TRANSFORM_270: > + shadow_width = height; > + shadow_height = width; > + pixman_transform_rotate(&transform, > + NULL, 0, pixman_fixed_1); > + pixman_transform_translate(&transform, > + NULL, > + pixman_int_to_fixed(shadow_width), > + 0); > + break; > + case WL_OUTPUT_TRANSFORM_90: > + shadow_width = height; > + shadow_height = width; > + pixman_transform_rotate(&transform, > + NULL, 0, -pixman_fixed_1); > + pixman_transform_translate(&transform, > + NULL, > + 0, > + pixman_int_to_fixed(shadow_height)); > + break; > + } > + output->shadow_buf = malloc(width * height * (bitsperpixel / 8)); > + output->shadow_surface = pixman_image_create_bits(pixman_format, > shadow_width, shadow_height, > + output->shadow_buf, shadow_width * (bitsperpixel / 8)); > + /* No need in transform for normal output */ > + if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL) > + pixman_image_set_transform(output->shadow_surface, &transform); > + > + output->gc = xcb_generate_id(c->conn); > + xcb_create_gc(c->conn, output->gc, output->window, 0, NULL); > + > + return 0; > +} > + > static struct x11_output * > x11_compositor_create_output(struct x11_compositor *c, int x, int y, > int width, int height, int fullscreen, > @@ -562,7 +861,10 @@ x11_compositor_create_output(struct x11_compositor *c, > int x, int y, > x11_output_wait_for_map(c, output); > > output->base.origin = output->base.current; > - output->base.repaint = x11_output_repaint; > + if (c->use_shm) > + output->base.repaint = x11_output_repaint_shm; > + else > + output->base.repaint = x11_output_repaint_gl; > output->base.destroy = x11_output_destroy; > output->base.assign_planes = NULL; > output->base.set_backlight = NULL; > @@ -574,8 +876,17 @@ x11_compositor_create_output(struct x11_compositor *c, > int x, int y, > weston_output_init(&output->base, &c->base, > x, y, width, height, transform); > > - if (gl_renderer_output_create(&output->base, output->window) < 0) > - return NULL; > + if (c->use_shm) { > + if (x11_output_init_shm(c, output, width, height) < 0) > + return NULL; > + if (pixman_renderer_output_create(&output->base) < 0) { > + x11_output_deinit_shm(c, output); > + return NULL; > + } > + } else { > + if (gl_renderer_output_create(&output->base, output->window) < > 0) > + return NULL; > + } > > loop = wl_display_get_event_loop(c->base.wl_display); > output->finish_frame_timer = > @@ -1108,7 +1419,10 @@ x11_destroy(struct weston_compositor *ec) > > weston_compositor_shutdown(ec); /* destroys outputs, too */ > > - gl_renderer_destroy(ec); > + if (compositor->use_shm) > + pixman_renderer_destroy(ec); > + else > + gl_renderer_destroy(ec); > > XCloseDisplay(compositor->dpy); > free(ec); > @@ -1118,6 +1432,7 @@ static struct weston_compositor * > x11_compositor_create(struct wl_display *display, > int fullscreen, > int no_input, > + int use_shm, > int argc, char *argv[], const char *config_file) > { > struct x11_compositor *c; > @@ -1156,15 +1471,23 @@ x11_compositor_create(struct wl_display *display, > x11_compositor_get_resources(c); > > c->base.wl_display = display; > - if (gl_renderer_create(&c->base, c->dpy, gl_renderer_opaque_attribs, > - NULL) < 0) > - goto err_xdisplay; > + c->use_shm = use_shm; > + if (c->use_shm) { > + if (pixman_renderer_init(&c->base) < 0) > + goto err_xdisplay; > + } > + else { > + if (gl_renderer_create(&c->base, c->dpy, > gl_renderer_opaque_attribs, > + NULL) < 0) > + goto err_xdisplay; > + } > + weston_log("Using %s renderer\n", use_shm ? "pixman" : "gl"); > > c->base.destroy = x11_destroy; > c->base.restore = x11_restore; > > if (x11_input_create(c, no_input) < 0) > - goto err_gl; > + goto err_renderer; > > width = option_width ? option_width : 1024; > height = option_height ? option_height : 640; > @@ -1208,8 +1531,11 @@ x11_compositor_create(struct wl_display *display, > > err_x11_input: > x11_input_destroy(c); > -err_gl: > - gl_renderer_destroy(&c->base); > +err_renderer: > + if (c->use_shm) > + pixman_renderer_destroy(&c->base); > + else > + gl_renderer_destroy(&c->base); > err_xdisplay: > XCloseDisplay(c->dpy); > err_free: > @@ -1298,6 +1624,7 @@ backend_init(struct wl_display *display, int argc, char > *argv[], > { > int fullscreen = 0; > int no_input = 0; > + int use_shm = 0; > > const struct weston_option x11_options[] = { > { WESTON_OPTION_INTEGER, "width", 0, &option_width }, > @@ -1305,6 +1632,7 @@ backend_init(struct wl_display *display, int argc, char > *argv[], > { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &fullscreen }, > { WESTON_OPTION_INTEGER, "output-count", 0, &option_count }, > { WESTON_OPTION_BOOLEAN, "no-input", 0, &no_input }, > + { WESTON_OPTION_BOOLEAN, "use-shm", 0, &use_shm }, > }; > > parse_options(x11_options, ARRAY_LENGTH(x11_options), argc, argv); > @@ -1328,5 +1656,6 @@ backend_init(struct wl_display *display, int argc, char > *argv[], > return x11_compositor_create(display, > fullscreen, > no_input, > + use_shm, > argc, argv, config_file); > } > -- > 1.8.1 > > _______________________________________________ > wayland-devel mailing list > [email protected] > http://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
