diff options
Diffstat (limited to 'src/pixman-renderer.c')
-rw-r--r-- | src/pixman-renderer.c | 346 |
1 files changed, 180 insertions, 166 deletions
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 987c5393..26f6f279 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -37,14 +37,24 @@ struct pixman_output_state { }; struct pixman_surface_state { + struct weston_surface *surface; + pixman_image_t *image; struct weston_buffer_reference buffer_ref; + + struct wl_listener buffer_destroy_listener; + struct wl_listener surface_destroy_listener; + struct wl_listener renderer_destroy_listener; }; struct pixman_renderer { struct weston_renderer base; + int repaint_debug; pixman_image_t *debug_color; + struct weston_binding *debug_binding; + + struct wl_signal destroy_signal; }; static inline struct pixman_output_state * @@ -53,9 +63,15 @@ get_output_state(struct weston_output *output) return (struct pixman_output_state *)output->renderer_state; } +static int +pixman_renderer_create_surface(struct weston_surface *surface); + static inline struct pixman_surface_state * get_surface_state(struct weston_surface *surface) { + if (!surface->renderer_state) + pixman_renderer_create_surface(surface); + return (struct pixman_surface_state *)surface->renderer_state; } @@ -112,127 +128,27 @@ pixman_renderer_read_pixels(struct weston_output *output, } static void -box_scale(pixman_box32_t *dst, int scale) -{ - dst->x1 *= scale; - dst->x2 *= scale; - dst->y1 *= scale; - dst->y2 *= scale; -} - -static void -scale_region (pixman_region32_t *region, int scale) -{ - pixman_box32_t *rects, *scaled_rects; - int nrects, i; - - if (scale != 1) { - rects = pixman_region32_rectangles(region, &nrects); - scaled_rects = calloc(nrects, sizeof(pixman_box32_t)); - - for (i = 0; i < nrects; i++) { - scaled_rects[i] = rects[i]; - box_scale(&scaled_rects[i], scale); - } - pixman_region32_clear(region); - - pixman_region32_init_rects (region, scaled_rects, nrects); - free (scaled_rects); - } -} - -static void -transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform) -{ - pixman_box32_t *rects, *transformed_rects; - int nrects, i; - - if (transform == WL_OUTPUT_TRANSFORM_NORMAL) - return; - - rects = pixman_region32_rectangles(region, &nrects); - transformed_rects = calloc(nrects, sizeof(pixman_box32_t)); - - for (i = 0; i < nrects; i++) { - switch (transform) { - default: - case WL_OUTPUT_TRANSFORM_NORMAL: - transformed_rects[i].x1 = rects[i].x1; - transformed_rects[i].y1 = rects[i].y1; - transformed_rects[i].x2 = rects[i].x2; - transformed_rects[i].y2 = rects[i].y2; - break; - case WL_OUTPUT_TRANSFORM_90: - transformed_rects[i].x1 = height - rects[i].y2; - transformed_rects[i].y1 = rects[i].x1; - transformed_rects[i].x2 = height - rects[i].y1; - transformed_rects[i].y2 = rects[i].x2; - break; - case WL_OUTPUT_TRANSFORM_180: - transformed_rects[i].x1 = width - rects[i].x2; - transformed_rects[i].y1 = height - rects[i].y2; - transformed_rects[i].x2 = width - rects[i].x1; - transformed_rects[i].y2 = height - rects[i].y1; - break; - case WL_OUTPUT_TRANSFORM_270: - transformed_rects[i].x1 = rects[i].y1; - transformed_rects[i].y1 = width - rects[i].x2; - transformed_rects[i].x2 = rects[i].y2; - transformed_rects[i].y2 = width - rects[i].x1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - transformed_rects[i].x1 = width - rects[i].x2; - transformed_rects[i].y1 = rects[i].y1; - transformed_rects[i].x2 = width - rects[i].x1; - transformed_rects[i].y2 = rects[i].y2; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - transformed_rects[i].x1 = height - rects[i].y2; - transformed_rects[i].y1 = width - rects[i].x2; - transformed_rects[i].x2 = height - rects[i].y1; - transformed_rects[i].y2 = width - rects[i].x1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - transformed_rects[i].x1 = rects[i].x1; - transformed_rects[i].y1 = height - rects[i].y2; - transformed_rects[i].x2 = rects[i].x2; - transformed_rects[i].y2 = height - rects[i].y1; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - transformed_rects[i].x1 = rects[i].y1; - transformed_rects[i].y1 = rects[i].x1; - transformed_rects[i].x2 = rects[i].y2; - transformed_rects[i].y2 = rects[i].x2; - break; - } - } - pixman_region32_clear(region); - - pixman_region32_init_rects (region, transformed_rects, nrects); - free (transformed_rects); -} - -static void region_global_to_output(struct weston_output *output, pixman_region32_t *region) { pixman_region32_translate(region, -output->x, -output->y); - transform_region (region, output->width, output->height, output->transform); - scale_region (region, output->current_scale); + weston_transformed_region(output->width, output->height, + output->transform, output->current_scale, + region, region); } #define D2F(v) pixman_double_to_fixed((double)v) static void -repaint_region(struct weston_surface *es, struct weston_output *output, +repaint_region(struct weston_view *ev, struct weston_output *output, pixman_region32_t *region, pixman_region32_t *surf_region, pixman_op_t pixman_op) { struct pixman_renderer *pr = (struct pixman_renderer *) output->compositor->renderer; - struct pixman_surface_state *ps = get_surface_state(es); + struct pixman_surface_state *ps = get_surface_state(ev->surface); struct pixman_output_state *po = get_output_state(output); pixman_region32_t final_region; - float surface_x, surface_y; + float view_x, view_y; pixman_transform_t transform; pixman_fixed_t fw, fh; @@ -246,11 +162,11 @@ repaint_region(struct weston_surface *es, struct weston_output *output, pixman_region32_copy(&final_region, surf_region); /* Convert from surface to global coordinates */ - if (!es->transform.enabled) { - pixman_region32_translate(&final_region, es->geometry.x, es->geometry.y); + if (!ev->transform.enabled) { + pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y); } else { - weston_surface_to_global_float(es, 0, 0, &surface_x, &surface_y); - pixman_region32_translate(&final_region, (int)surface_x, (int)surface_y); + weston_view_to_global_float(ev, 0, 0, &view_x, &view_y); + pixman_region32_translate(&final_region, (int)view_x, (int)view_y); } /* We need to paint the intersection */ @@ -314,22 +230,22 @@ repaint_region(struct weston_surface *es, struct weston_output *output, pixman_double_to_fixed (output->x), pixman_double_to_fixed (output->y)); - if (es->transform.enabled) { + if (ev->transform.enabled) { /* Pixman supports only 2D transform matrix, but Weston uses 3D, * so we're omitting Z coordinate here */ pixman_transform_t surface_transform = {{ - { D2F(es->transform.matrix.d[0]), - D2F(es->transform.matrix.d[4]), - D2F(es->transform.matrix.d[12]), + { D2F(ev->transform.matrix.d[0]), + D2F(ev->transform.matrix.d[4]), + D2F(ev->transform.matrix.d[12]), }, - { D2F(es->transform.matrix.d[1]), - D2F(es->transform.matrix.d[5]), - D2F(es->transform.matrix.d[13]), + { D2F(ev->transform.matrix.d[1]), + D2F(ev->transform.matrix.d[5]), + D2F(ev->transform.matrix.d[13]), }, - { D2F(es->transform.matrix.d[3]), - D2F(es->transform.matrix.d[7]), - D2F(es->transform.matrix.d[15]), + { D2F(ev->transform.matrix.d[3]), + D2F(ev->transform.matrix.d[7]), + D2F(ev->transform.matrix.d[15]), } }}; @@ -337,15 +253,37 @@ repaint_region(struct weston_surface *es, struct weston_output *output, pixman_transform_multiply (&transform, &surface_transform, &transform); } else { pixman_transform_translate(&transform, NULL, - pixman_double_to_fixed ((double)-es->geometry.x), - pixman_double_to_fixed ((double)-es->geometry.y)); + pixman_double_to_fixed ((double)-ev->geometry.x), + pixman_double_to_fixed ((double)-ev->geometry.y)); } + if (ev->surface->buffer_viewport.viewport_set) { + double viewport_x, viewport_y, viewport_width, viewport_height; + double ratio_x, ratio_y; + + viewport_x = wl_fixed_to_double(ev->surface->buffer_viewport.src_x); + viewport_y = wl_fixed_to_double(ev->surface->buffer_viewport.src_y); + viewport_width = wl_fixed_to_double(ev->surface->buffer_viewport.src_width); + viewport_height = wl_fixed_to_double(ev->surface->buffer_viewport.src_height); + + ratio_x = viewport_width / ev->surface->buffer_viewport.dst_width; + ratio_y = viewport_height / ev->surface->buffer_viewport.dst_height; + + pixman_transform_scale(&transform, NULL, + pixman_double_to_fixed(ratio_x), + pixman_double_to_fixed(ratio_y)); + pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(viewport_x), + pixman_double_to_fixed(viewport_y)); + } + + pixman_transform_scale(&transform, NULL, + pixman_double_to_fixed(ev->surface->buffer_viewport.scale), + pixman_double_to_fixed(ev->surface->buffer_viewport.scale)); - fw = pixman_int_to_fixed(es->geometry.width); - fh = pixman_int_to_fixed(es->geometry.height); + fw = pixman_int_to_fixed(pixman_image_get_width(ps->image)); + fh = pixman_int_to_fixed(pixman_image_get_height(ps->image)); - switch (es->buffer_transform) { + switch (ev->surface->buffer_viewport.transform) { case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_180: @@ -357,7 +295,7 @@ repaint_region(struct weston_surface *es, struct weston_output *output, break; } - switch (es->buffer_transform) { + switch (ev->surface->buffer_viewport.transform) { default: case WL_OUTPUT_TRANSFORM_NORMAL: case WL_OUTPUT_TRANSFORM_FLIPPED: @@ -379,17 +317,16 @@ repaint_region(struct weston_surface *es, struct weston_output *output, break; } - pixman_transform_scale(&transform, NULL, - pixman_double_to_fixed ((double)es->buffer_scale), - pixman_double_to_fixed ((double)es->buffer_scale)); - pixman_image_set_transform(ps->image, &transform); - if (es->transform.enabled || output->current_scale != es->buffer_scale) + if (ev->transform.enabled || output->current_scale != ev->surface->buffer_viewport.scale) pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0); else pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0); + if (ps->buffer_ref.buffer) + wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer); + pixman_image_composite32(pixman_op, ps->image, /* src */ NULL /* mask */, @@ -400,6 +337,9 @@ repaint_region(struct weston_surface *es, struct weston_output *output, pixman_image_get_width (po->shadow_image), /* width */ pixman_image_get_height (po->shadow_image) /* height */); + if (ps->buffer_ref.buffer) + wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer); + if (pr->repaint_debug) pixman_image_composite32(PIXMAN_OP_OVER, pr->debug_color, /* src */ @@ -417,10 +357,10 @@ repaint_region(struct weston_surface *es, struct weston_output *output, } static void -draw_surface(struct weston_surface *es, struct weston_output *output, - pixman_region32_t *damage) /* in global coordinates */ +draw_view(struct weston_view *ev, struct weston_output *output, + pixman_region32_t *damage) /* in global coordinates */ { - struct pixman_surface_state *ps = get_surface_state(es); + struct pixman_surface_state *ps = get_surface_state(ev->surface); /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; /* non-opaque region in surface coordinates: */ @@ -432,8 +372,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output, pixman_region32_init(&repaint); pixman_region32_intersect(&repaint, - &es->transform.boundingbox, damage); - pixman_region32_subtract(&repaint, &repaint, &es->clip); + &ev->transform.boundingbox, damage); + pixman_region32_subtract(&repaint, &repaint, &ev->clip); if (!pixman_region32_not_empty(&repaint)) goto out; @@ -444,21 +384,21 @@ draw_surface(struct weston_surface *es, struct weston_output *output, } /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */ - if (es->transform.enabled && - es->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) { - repaint_region(es, output, &repaint, NULL, PIXMAN_OP_OVER); + if (ev->transform.enabled && + ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) { + repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER); } else { /* blended region is whole surface minus opaque region: */ pixman_region32_init_rect(&surface_blend, 0, 0, - es->geometry.width, es->geometry.height); - pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque); + ev->surface->width, ev->surface->height); + pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque); - if (pixman_region32_not_empty(&es->opaque)) { - repaint_region(es, output, &repaint, &es->opaque, PIXMAN_OP_SRC); + if (pixman_region32_not_empty(&ev->surface->opaque)) { + repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC); } if (pixman_region32_not_empty(&surface_blend)) { - repaint_region(es, output, &repaint, &surface_blend, PIXMAN_OP_OVER); + repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER); } pixman_region32_fini(&surface_blend); } @@ -471,11 +411,11 @@ static void repaint_surfaces(struct weston_output *output, pixman_region32_t *damage) { struct weston_compositor *compositor = output->compositor; - struct weston_surface *surface; + struct weston_view *view; - wl_list_for_each_reverse(surface, &compositor->surface_list, link) - if (surface->plane == &compositor->primary_plane) - draw_surface(surface, output, damage); + wl_list_for_each_reverse(view, &compositor->view_list, link) + if (view->plane == &compositor->primary_plane) + draw_view(view, output, damage); } static void @@ -529,6 +469,22 @@ pixman_renderer_flush_damage(struct weston_surface *surface) } static void +buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data) +{ + struct pixman_surface_state *ps; + + ps = container_of(listener, struct pixman_surface_state, + buffer_destroy_listener); + + if (ps->image) { + pixman_image_unref(ps->image); + ps->image = NULL; + } + + ps->buffer_destroy_listener.notify = NULL; +} + +static void pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { struct pixman_surface_state *ps = get_surface_state(es); @@ -537,6 +493,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) weston_buffer_reference(&ps->buffer_ref, buffer); + if (ps->buffer_destroy_listener.notify) { + wl_list_remove(&ps->buffer_destroy_listener.link); + ps->buffer_destroy_listener.notify = NULL; + } + if (ps->image) { pixman_image_unref(ps->image); ps->image = NULL; @@ -578,12 +539,60 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) buffer->width, buffer->height, wl_shm_buffer_get_data(shm_buffer), wl_shm_buffer_get_stride(shm_buffer)); + + ps->buffer_destroy_listener.notify = + buffer_state_handle_buffer_destroy; + wl_signal_add(&buffer->destroy_signal, + &ps->buffer_destroy_listener); +} + +static void +pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps) +{ + wl_list_remove(&ps->surface_destroy_listener.link); + wl_list_remove(&ps->renderer_destroy_listener.link); + if (ps->buffer_destroy_listener.notify) { + wl_list_remove(&ps->buffer_destroy_listener.link); + ps->buffer_destroy_listener.notify = NULL; + } + + ps->surface->renderer_state = NULL; + + if (ps->image) { + pixman_image_unref(ps->image); + ps->image = NULL; + } + weston_buffer_reference(&ps->buffer_ref, NULL); + free(ps); +} + +static void +surface_state_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct pixman_surface_state *ps; + + ps = container_of(listener, struct pixman_surface_state, + surface_destroy_listener); + + pixman_renderer_surface_state_destroy(ps); +} + +static void +surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data) +{ + struct pixman_surface_state *ps; + + ps = container_of(listener, struct pixman_surface_state, + renderer_destroy_listener); + + pixman_renderer_surface_state_destroy(ps); } static int pixman_renderer_create_surface(struct weston_surface *surface) { struct pixman_surface_state *ps; + struct pixman_renderer *pr = get_renderer(surface->compositor); ps = calloc(1, sizeof *ps); if (!ps) @@ -591,6 +600,18 @@ pixman_renderer_create_surface(struct weston_surface *surface) surface->renderer_state = ps; + ps->surface = surface; + + ps->surface_destroy_listener.notify = + surface_state_handle_surface_destroy; + wl_signal_add(&surface->destroy_signal, + &ps->surface_destroy_listener); + + ps->renderer_destroy_listener.notify = + surface_state_handle_renderer_destroy; + wl_signal_add(&pr->destroy_signal, + &ps->renderer_destroy_listener); + return 0; } @@ -615,22 +636,14 @@ pixman_renderer_surface_set_color(struct weston_surface *es, } static void -pixman_renderer_destroy_surface(struct weston_surface *surface) +pixman_renderer_destroy(struct weston_compositor *ec) { - struct pixman_surface_state *ps = get_surface_state(surface); + struct pixman_renderer *pr = get_renderer(ec); - if (ps->image) { - pixman_image_unref(ps->image); - ps->image = NULL; - } - weston_buffer_reference(&ps->buffer_ref, NULL); - free(ps); -} + wl_signal_emit(&pr->destroy_signal, pr); + weston_binding_destroy(pr->debug_binding); + free(pr); -static void -pixman_renderer_destroy(struct weston_compositor *ec) -{ - free(ec->renderer); ec->renderer = NULL; } @@ -660,7 +673,7 @@ pixman_renderer_init(struct weston_compositor *ec) { struct pixman_renderer *renderer; - renderer = malloc(sizeof *renderer); + renderer = calloc(1, sizeof *renderer); if (renderer == NULL) return -1; @@ -670,19 +683,20 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.repaint_output = pixman_renderer_repaint_output; renderer->base.flush_damage = pixman_renderer_flush_damage; renderer->base.attach = pixman_renderer_attach; - renderer->base.create_surface = pixman_renderer_create_surface; renderer->base.surface_set_color = pixman_renderer_surface_set_color; - renderer->base.destroy_surface = pixman_renderer_destroy_surface; renderer->base.destroy = pixman_renderer_destroy; ec->renderer = &renderer->base; ec->capabilities |= WESTON_CAP_ROTATION_ANY; ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP; - weston_compositor_add_debug_binding(ec, KEY_R, - debug_binding, ec); + renderer->debug_binding = + weston_compositor_add_debug_binding(ec, KEY_R, + debug_binding, ec); wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565); + wl_signal_init(&renderer->destroy_signal); + return 0; } |