diff --git a/libweston/backend-drm/state-helpers.c b/libweston/backend-drm/state-helpers.c index dbcef7696..a9ae24337 100644 --- a/libweston/backend-drm/state-helpers.c +++ b/libweston/backend-drm/state-helpers.c @@ -224,13 +224,8 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state, struct weston_paint_node *pnode, uint64_t zpos) { - struct drm_output *output = state->handle->output; - struct weston_view *ev = pnode->view; - struct weston_buffer *buffer = ev->surface->buffer_ref.buffer; - pixman_region32_t dest_rect; - pixman_box32_t *box; - struct weston_coord corners[2]; - float sxf1, syf1, sxf2, syf2; + struct weston_surface *surface = pnode->surface; + struct weston_buffer *buffer = surface->buffer_ref.buffer; uint16_t min_alpha = state->plane->alpha_min; uint16_t max_alpha = state->plane->alpha_max; @@ -243,58 +238,16 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state, assert(pnode->valid_transform); state->rotation = drm_rotation_from_output_transform(state->plane, pnode->transform); - box = pixman_region32_extents(&ev->transform.boundingbox); - - /* First calculate the destination co-ordinates by taking the - * area of the view which is visible on this output, performing any - * transforms to account for output rotation and scale as necessary. */ - pixman_region32_init(&dest_rect); - pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox, - &output->base.region); - weston_region_global_to_output(&dest_rect, &output->base, &dest_rect); - - box = pixman_region32_extents(&dest_rect); - - state->dest_x = box->x1; - state->dest_y = box->y1; - state->dest_w = box->x2 - box->x1; - state->dest_h = box->y2 - box->y1; - - /* Now calculate the source rectangle, by transforming the destination - * rectangle by the output to buffer matrix. */ - corners[0] = weston_matrix_transform_coord( - &pnode->output_to_buffer_matrix, - weston_coord(box->x1, box->y1)); - corners[1] = weston_matrix_transform_coord( - &pnode->output_to_buffer_matrix, - weston_coord(box->x2, box->y2)); - sxf1 = corners[0].x; - syf1 = corners[0].y; - sxf2 = corners[1].x; - syf2 = corners[1].y; - pixman_region32_fini(&dest_rect); - - /* Make sure that our post-transform coordinates are in the - * right order. - */ - if (sxf1 > sxf2) { - float temp = sxf1; - - sxf1 = sxf2; - sxf2 = temp; - } - if (syf1 > syf2) { - float temp = syf1; - - syf1 = syf2; - syf2 = temp; - } + state->dest_x = pnode->output_dest.x; + state->dest_y = pnode->output_dest.y; + state->dest_w = pnode->output_dest.width; + state->dest_h = pnode->output_dest.height; /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */ - state->src_x = wl_fixed_from_double(sxf1) << 8; - state->src_y = wl_fixed_from_double(syf1) << 8; - state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8; - state->src_h = wl_fixed_from_double(syf2 - syf1) << 8; + state->src_x = wl_fixed_from_double(pnode->buffer_source_x) << 8; + state->src_y = wl_fixed_from_double(pnode->buffer_source_y) << 8; + state->src_w = wl_fixed_from_double(pnode->buffer_source_width) << 8; + state->src_h = wl_fixed_from_double(pnode->buffer_source_height) << 8; /* Clamp our source co-ordinates to surface bounds; it's possible * for intermediate translations to give us slightly incorrect diff --git a/libweston/compositor.c b/libweston/compositor.c index 8259f9795..71337197c 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -195,6 +195,107 @@ get_placeholder_color(struct weston_paint_node *pnode, color->a = 1.0; } +/* If we have a valid transform, we can compute an output destination + * rectangle and a buffer source rectangle that backends can use for plane + * setup. + */ +static void +paint_node_update_rectangles(struct weston_paint_node *pnode) +{ + struct weston_view *view = pnode->view; + struct weston_output *output = pnode->output; + pixman_region32_t dest_rect; + pixman_box32_t *box; + struct weston_coord corners[2]; + float sxf1, syf1, sxf2, syf2; + + box = pixman_region32_extents(&view->transform.boundingbox); + + /* First calculate the destination co-ordinates by taking the + * area of the view which is visible on this output, performing any + * transforms to account for output rotation and scale as necessary. */ + pixman_region32_init(&dest_rect); + pixman_region32_intersect(&dest_rect, &view->transform.boundingbox, + &output->region); + weston_region_global_to_output(&dest_rect, output, &dest_rect); + + box = pixman_region32_extents(&dest_rect); + pnode->output_dest.x = box->x1; + pnode->output_dest.y = box->y1; + pnode->output_dest.width = box->x2 - box->x1; + pnode->output_dest.height = box->y2 - box->y1; + + /* Now calculate the source rectangle, by transforming the destination + * rectangle by the output to buffer matrix. */ + corners[0] = weston_matrix_transform_coord(&pnode->output_to_buffer_matrix, + weston_coord(box->x1, box->y1)); + corners[1] = weston_matrix_transform_coord(&pnode->output_to_buffer_matrix, + weston_coord(box->x2, box->y2)); + sxf1 = corners[0].x; + syf1 = corners[0].y; + sxf2 = corners[1].x; + syf2 = corners[1].y; + pixman_region32_fini(&dest_rect); + + /* Make sure that our post-transform coordinates are in the + * right order. + */ + if (sxf1 > sxf2) { + float temp = sxf1; + + sxf1 = sxf2; + sxf2 = temp; + } + if (syf1 > syf2) { + float temp = syf1; + + syf1 = syf2; + syf2 = temp; + } + pnode->buffer_source_x = sxf1; + pnode->buffer_source_y = syf1; + pnode->buffer_source_width = sxf2 - sxf1; + pnode->buffer_source_height = syf2 - syf1; +} + +static void +paint_node_rebuild_regions(struct weston_paint_node *pnode) +{ + struct weston_surface *surface = pnode->surface; + struct weston_view *view = pnode->view; + pixman_region32_t *surface_opaque = &pnode->surface_opaque; + pixman_region32_t *surface_blend = &pnode->surface_blend; + + pixman_region32_fini(surface_opaque); + pixman_region32_fini(surface_blend); + + if (pnode->is_fully_opaque) { + pixman_region32_init_rect(surface_opaque, 0, 0, + surface->width, + surface->height); + } else { + pixman_region32_init(surface_opaque); + pixman_region32_copy(surface_opaque, &pnode->surface->opaque); + } + + if (view->geometry.scissor_enabled) + pixman_region32_intersect(surface_opaque, + surface_opaque, + &pnode->view->geometry.scissor); + + /* blended region is whole surface minus opaque region: */ + pixman_region32_init_rect(surface_blend, 0, 0, + surface->width, surface->height); + + if (view->geometry.scissor_enabled) + pixman_region32_intersect(surface_opaque, + surface_opaque, + &view->geometry.scissor); + + pixman_region32_subtract(surface_blend, surface_blend, + surface_opaque); +} + /* Paint nodes contain filter and transform information that needs to be * up to date before assign_planes() is called. But there are also * damage related bits that must be updated after assign_planes() @@ -224,8 +325,13 @@ paint_node_update_early(struct weston_paint_node *pnode) pnode->valid_transform = weston_matrix_to_transform(mat, &pnode->transform); + if (pnode->valid_transform) + paint_node_update_rectangles(pnode); } + if (view_dirty) + paint_node_rebuild_regions(pnode); + buffer = pnode->surface->buffer_ref.buffer; pnode->draw_solid = false; pnode->is_fully_transparent = false; @@ -441,9 +547,14 @@ weston_paint_node_create(struct weston_surface *surface, pixman_region32_init(&pnode->clipped_view); pixman_region32_copy(&pnode->visible, &view->transform.boundingbox); + pixman_region32_init(&pnode->surface_opaque); + pixman_region32_init(&pnode->surface_blend); + pnode->plane = &pnode->output->primary_plane; pnode->plane_next = NULL; + pnode->view_transform_matrix = &view->transform.matrix; + pnode->need_hole = false; pnode->status = WESTON_PAINT_NODE_ALL_DIRTY & ~WESTON_PAINT_NODE_PLANE_DIRTY; @@ -499,6 +610,8 @@ weston_paint_node_destroy(struct weston_paint_node *pnode) pixman_region32_fini(&pnode->visible); pixman_region32_fini(&pnode->visible_previous); pixman_region32_fini(&pnode->clipped_view); + pixman_region32_fini(&pnode->surface_opaque); + pixman_region32_fini(&pnode->surface_blend); free(pnode->internal_name); free(pnode); } diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 79212d0ce..ae85675fd 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -689,6 +689,7 @@ struct weston_paint_node { /* struct weston_view::paint_node_list */ struct wl_list view_link; struct weston_view *view; + struct weston_matrix *view_transform_matrix; /* struct weston_output::paint_node_list */ struct wl_list output_link; @@ -705,6 +706,20 @@ struct weston_paint_node { bool valid_transform; enum wl_output_transform transform; + /* The paint node's output destination rectangle, only valid if valid_transform + * is true */ + struct weston_geometry output_dest; + /* The paint node's buffer source rectangle, only valid if valid_transform + * is true */ + float buffer_source_x; + float buffer_source_y; + float buffer_source_width; + float buffer_source_height; + + /* Opaqure region in surface co-ordinates */ + pixman_region32_t surface_opaque; + /* Blended region in surface co-ordinates */ + pixman_region32_t surface_blend; /* struct weston_output::paint_node_z_order_list */ struct wl_list z_order_link; diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index ca948e784..a550cd87e 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -350,44 +350,34 @@ draw_node_translated(struct weston_paint_node *pnode, pixman_region32_t *repaint_global) { struct weston_output *output = pnode->output; - struct weston_surface *surface = pnode->surface; - struct weston_view *view = pnode->view; - /* non-opaque region in surface coordinates: */ - pixman_region32_t surface_blend; /* region to be painted in output coordinates: */ pixman_region32_t repaint_output; pixman_region32_init(&repaint_output); - /* Blended region is whole surface minus opaque region, - * unless surface alpha forces us to blend all. - */ - pixman_region32_init_rect(&surface_blend, 0, 0, - surface->width, surface->height); - - if (!(view->alpha < 1.0)) { - pixman_region32_subtract(&surface_blend, &surface_blend, - &surface->opaque); - - if (pixman_region32_not_empty(&surface->opaque)) { - region_intersect_only_translation(&repaint_output, - repaint_global, - &surface->opaque, - view); - weston_region_global_to_output(&repaint_output, - output, - &repaint_output); - - repaint_region(pnode, &repaint_output, NULL, - PIXMAN_OP_SRC); - } - } - - if (pixman_region32_not_empty(&surface_blend)) { + if (pixman_region32_not_empty(&pnode->surface_opaque)) { region_intersect_only_translation(&repaint_output, repaint_global, - &surface_blend, view); + &pnode->surface_opaque, + pnode->view); + weston_region_global_to_output(&repaint_output, + output, + &repaint_output); + + if (pnode->view_alpha < 1.0) + repaint_region(pnode, &repaint_output, NULL, + PIXMAN_OP_OVER); + else + repaint_region(pnode, &repaint_output, NULL, + PIXMAN_OP_SRC); + } + + if (pixman_region32_not_empty(&pnode->surface_blend)) { + region_intersect_only_translation(&repaint_output, + repaint_global, + &pnode->surface_blend, + pnode->view); weston_region_global_to_output(&repaint_output, output, &repaint_output); @@ -395,7 +385,6 @@ draw_node_translated(struct weston_paint_node *pnode, repaint_region(pnode, &repaint_output, NULL, PIXMAN_OP_OVER); } - pixman_region32_fini(&surface_blend); pixman_region32_fini(&repaint_output); } @@ -405,7 +394,6 @@ draw_node_source_clipped(struct weston_paint_node *pnode, { struct weston_surface *surface = pnode->surface; struct weston_output *output = pnode->output; - struct weston_view *view = pnode->view; pixman_region32_t surf_region; pixman_region32_t buffer_region; pixman_region32_t repaint_output; @@ -415,11 +403,10 @@ draw_node_source_clipped(struct weston_paint_node *pnode, * opaque separately has no benefit. */ - pixman_region32_init_rect(&surf_region, 0, 0, - surface->width, surface->height); - if (view->geometry.scissor_enabled) - pixman_region32_intersect(&surf_region, &surf_region, - &view->geometry.scissor); + pixman_region32_init(&surf_region); + pixman_region32_union(&surf_region, + &pnode->surface_opaque, + &pnode->surface_blend); pixman_region32_init(&buffer_region); weston_surface_to_buffer_region(surface, &surf_region, &buffer_region); diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index df9867def..e4d5d4726 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -1728,7 +1728,7 @@ prepare_solid_draw(struct gl_shader_config *sconf, .variant = SHADER_VARIANT_SOLID, .input_is_premult = true, }, - .projection = pnode->view->transform.matrix, + .projection = *pnode->view_transform_matrix, .view_alpha = pnode->view_alpha, .unicolor = { pnode->solid.r, pnode->solid.g, @@ -1917,7 +1917,7 @@ prepare_textured_draw(struct gl_shader_config *sconf, *sconf = (struct gl_shader_config) { .req.texcoord_input = SHADER_TEXCOORD_INPUT_SURFACE, - .projection = pnode->view->transform.matrix, + .projection = *pnode->view_transform_matrix, .surface_to_buffer = pnode->surface->surface_to_buffer_matrix, .view_alpha = pnode->view_alpha, @@ -2405,7 +2405,6 @@ repaint_region(struct gl_renderer *gr, struct weston_paint_node *pnode, struct clipper_quad *quads, int nquads, - pixman_region32_t *region, struct gl_shader_config *sconf, bool opaque) { @@ -2416,12 +2415,18 @@ repaint_region(struct gl_renderer *gr, int i, j, n, nrects, positions_size, barycentrics_size, indices_size; int nvtx = 0, nidx = 0; bool wireframe = gr->debug_mode == DEBUG_MODE_WIREFRAME; + pixman_region32_t *region; /* Build-time sub-mesh constants. Clipping emits 8 vertices max. * store_indices() store at most 10 indices. */ const int nvtx_max = 8; const int nidx_max = 10; + if (opaque) + region = &pnode->surface_opaque; + else + region = &pnode->surface_blend; + rects = pixman_region32_rectangles(region, &nrects); assert((nrects > 0) && (nquads > 0)); @@ -2595,10 +2600,6 @@ draw_paint_node(struct weston_paint_node *pnode, struct gl_surface_state *gs = get_surface_state(pnode->surface); /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; - /* opaque region in surface coordinates: */ - pixman_region32_t surface_opaque; - /* non-opaque region in surface coordinates: */ - pixman_region32_t surface_blend; struct gl_shader_config sconf; struct clipper_quad *quads = NULL; int nquads; @@ -2638,51 +2639,23 @@ draw_paint_node(struct weston_paint_node *pnode, goto out; } - if (pnode->is_fully_opaque) { - pixman_region32_init_rect(&surface_opaque, 0, 0, - pnode->surface->width, - pnode->surface->height); - } else { - pixman_region32_init(&surface_opaque); - pixman_region32_copy(&surface_opaque, &pnode->surface->opaque); - } - - if (pnode->view->geometry.scissor_enabled) - pixman_region32_intersect(&surface_opaque, - &surface_opaque, - &pnode->view->geometry.scissor); - - /* blended region is whole surface minus opaque region: */ - pixman_region32_init_rect(&surface_blend, 0, 0, - pnode->surface->width, pnode->surface->height); - if (pnode->view->geometry.scissor_enabled) - pixman_region32_intersect(&surface_blend, &surface_blend, - &pnode->view->geometry.scissor); - pixman_region32_subtract(&surface_blend, &surface_blend, - &surface_opaque); - gl_log_paint_node_bbox_and_region(gr, "repaint region", &repaint); transform_damage(pnode, &repaint, &quads, &nquads); - if (pixman_region32_not_empty(&surface_opaque)) { - gl_log_paint_node_bbox_and_region(gr, "opaque region", &surface_opaque); - repaint_region(gr, pnode, quads, nquads, &surface_opaque, - &sconf, true); + if (pixman_region32_not_empty(&pnode->surface_opaque)) { + gl_log_paint_node_bbox_and_region(gr, "opaque region", &pnode->surface_opaque); + repaint_region(gr, pnode, quads, nquads, &sconf, true); gs->used_in_output_repaint = true; } - if (pixman_region32_not_empty(&surface_blend)) { - gl_log_paint_node_bbox_and_region(gr, "blended region", &surface_blend); - repaint_region(gr, pnode, quads, nquads, &surface_blend, &sconf, - false); + if (pixman_region32_not_empty(&pnode->surface_blend)) { + gl_log_paint_node_bbox_and_region(gr, "blended region", &pnode->surface_blend); + repaint_region(gr, pnode, quads, nquads, &sconf, false); gs->used_in_output_repaint = true; } free(quads); - pixman_region32_fini(&surface_blend); - pixman_region32_fini(&surface_opaque); - out: pixman_region32_fini(&repaint); } diff --git a/libweston/renderer-vulkan/vulkan-renderer.c b/libweston/renderer-vulkan/vulkan-renderer.c index fa53e99a1..507e420cb 100644 --- a/libweston/renderer-vulkan/vulkan-renderer.c +++ b/libweston/renderer-vulkan/vulkan-renderer.c @@ -1523,7 +1523,7 @@ vulkan_pipeline_config_init_for_paint_node(struct vulkan_pipeline_config *pconf, .renderpass = vo->renderpass, .green_tint = (vr->debug_mode == DEBUG_MODE_FRAGMENT), }, - .projection = pnode->view->transform.matrix, + .projection = *pnode->view_transform_matrix, .surface_to_buffer = pnode->surface->surface_to_buffer_matrix, .view_alpha = pnode->view_alpha, @@ -1633,7 +1633,7 @@ static void repaint_region(struct vulkan_renderer *vr, struct weston_paint_node *pnode, pixman_region32_t *region, - pixman_region32_t *surf_region, + bool opaque, const struct vulkan_pipeline_config *pconf, struct vulkan_renderer_frame *fr) { @@ -1642,12 +1642,18 @@ repaint_region(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline; VkCommandBuffer cmd_buffer = fr->cmd_buffer; uint32_t nfans; + pixman_region32_t *surf_region; struct wl_array vertices; struct wl_array vtxcnt; wl_array_init(&vertices); wl_array_init(&vtxcnt); + if (opaque) + surf_region = &pnode->surface_opaque; + else + surf_region = &pnode->surface_blend; + /* The final region to be painted is the intersection of 'region' and * 'surf_region'. However, 'region' is in the global coordinates, and * 'surf_region' is in the surface-local coordinates. @@ -1772,10 +1778,6 @@ draw_paint_node(struct weston_paint_node *pnode, struct weston_buffer *buffer = vs->buffer_ref.buffer; /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; - /* opaque region in surface coordinates: */ - pixman_region32_t surface_opaque; - /* non-opaque region in surface coordinates: */ - pixman_region32_t surface_blend; struct vulkan_pipeline_config pconf; struct vulkan_pipeline *pipeline; @@ -1813,30 +1815,7 @@ draw_paint_node(struct weston_paint_node *pnode, image_view, sampler, &vb->descriptor_set); - if (pnode->is_fully_opaque) { - pixman_region32_init_rect(&surface_opaque, 0, 0, - pnode->surface->width, - pnode->surface->height); - } else { - pixman_region32_init(&surface_opaque); - pixman_region32_copy(&surface_opaque, &pnode->surface->opaque); - } - - if (pnode->view->geometry.scissor_enabled) - pixman_region32_intersect(&surface_opaque, - &surface_opaque, - &pnode->view->geometry.scissor); - - /* blended region is whole surface minus opaque region: */ - pixman_region32_init_rect(&surface_blend, 0, 0, - pnode->surface->width, pnode->surface->height); - if (pnode->view->geometry.scissor_enabled) - pixman_region32_intersect(&surface_blend, &surface_blend, - &pnode->view->geometry.scissor); - pixman_region32_subtract(&surface_blend, &surface_blend, - &surface_opaque); - - if (pixman_region32_not_empty(&surface_opaque)) { + if (pixman_region32_not_empty(&pnode->surface_opaque)) { struct vulkan_pipeline_config alt = pconf; if (alt.req.variant == PIPELINE_VARIANT_RGBA) @@ -1844,19 +1823,16 @@ draw_paint_node(struct weston_paint_node *pnode, alt.req.blend = (pnode->view_alpha < 1.0); - repaint_region(vr, pnode, &repaint, &surface_opaque, &alt, fr); + repaint_region(vr, pnode, &repaint, true, &alt, fr); vs->used_in_output_repaint = true; } pconf.req.blend = true; - if (pixman_region32_not_empty(&surface_blend)) { - repaint_region(vr, pnode, &repaint, &surface_blend, &pconf, fr); + if (pixman_region32_not_empty(&pnode->surface_blend)) { + repaint_region(vr, pnode, &repaint, false, &pconf, fr); vs->used_in_output_repaint = true; } - pixman_region32_fini(&surface_blend); - pixman_region32_fini(&surface_opaque); - out: pixman_region32_fini(&repaint); }