From efbbc0fd5849340478991ae578591f315575297a Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 16 Mar 2026 13:30:46 -0500 Subject: [PATCH 1/4] compositor: Store the output desination and buffer source rects in pnode Instead of having the drm backend calculate these per frame, let's store them in the paint node when they change. Signed-off-by: Derek Foreman --- libweston/backend-drm/state-helpers.c | 67 ++++----------------------- libweston/compositor.c | 65 ++++++++++++++++++++++++++ libweston/libweston-internal.h | 9 ++++ 3 files changed, 84 insertions(+), 57 deletions(-) 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 5c9462e77..ab244deca 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -195,6 +195,69 @@ 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; +} + /* 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,6 +287,8 @@ 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); } buffer = pnode->surface->buffer_ref.buffer; diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 65f754c25..91f40ef96 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -703,6 +703,15 @@ 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; /* struct weston_output::paint_node_z_order_list */ struct wl_list z_order_link; From 14d59f6ab106d86520605852601ca0f89de940f9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 17 Mar 2026 11:21:04 -0500 Subject: [PATCH 2/4] compositor,renderers: Move surface opaque and blended regions into pnode We can track this on the paint node and update it only when visibility is dirty. This is a double benefit - we regenerate it a little less frequently, and we remove a reason for the renderers to care about views. Signed-off-by: Derek Foreman --- libweston/compositor.c | 46 +++++++++++++++++++ libweston/libweston-internal.h | 5 ++ libweston/pixman-renderer.c | 51 ++++++++------------- libweston/renderer-gl/gl-renderer.c | 51 +++++---------------- libweston/renderer-vulkan/vulkan-renderer.c | 46 +++++-------------- 5 files changed, 94 insertions(+), 105 deletions(-) diff --git a/libweston/compositor.c b/libweston/compositor.c index ab244deca..2a761ccc8 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -258,6 +258,44 @@ paint_node_update_rectangles(struct weston_paint_node *pnode) 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() @@ -291,6 +329,9 @@ paint_node_update_early(struct weston_paint_node *pnode) 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; @@ -506,6 +547,9 @@ 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; @@ -564,6 +608,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 91f40ef96..de4b1cf1c 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -713,6 +713,11 @@ struct weston_paint_node { 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..af9e3e334 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); } diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index cfc06a15b..2d50ef8bb 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -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 369385c43..d5db7a1eb 100644 --- a/libweston/renderer-vulkan/vulkan-renderer.c +++ b/libweston/renderer-vulkan/vulkan-renderer.c @@ -1637,7 +1637,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) { @@ -1646,12 +1646,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. @@ -1776,10 +1782,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; @@ -1817,30 +1819,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) @@ -1848,19 +1827,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); } From 7ed55f839061b98c753e373a2e271d5db39a32b9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 17 Mar 2026 11:31:59 -0500 Subject: [PATCH 3/4] compositor,renderers: Store a pointer to the view transform in pnode This pointer is the same for the life of the view, even if the matrix changes. This is a last pedantic step towards preventing renderers from directly accessing a weston_view. Signed-off-by: Derek Foreman --- libweston/compositor.c | 2 ++ libweston/libweston-internal.h | 1 + libweston/renderer-gl/gl-renderer.c | 4 ++-- libweston/renderer-vulkan/vulkan-renderer.c | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libweston/compositor.c b/libweston/compositor.c index 2a761ccc8..c4b23a965 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -553,6 +553,8 @@ weston_paint_node_create(struct weston_surface *surface, 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; diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index de4b1cf1c..08dd5085f 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -687,6 +687,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; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 2d50ef8bb..7eab6ede0 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, diff --git a/libweston/renderer-vulkan/vulkan-renderer.c b/libweston/renderer-vulkan/vulkan-renderer.c index d5db7a1eb..987d730c2 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, From c91d312b32af0df6a78fc2788877d14cea1cf99f Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 17 Mar 2026 11:58:23 -0500 Subject: [PATCH 4/4] pixman-renderer: Use pnode precalculated region for clipped draw Instead of using the surface rectangle and the view scissor, make a union of the blend/opaque regions from the pnode. This is probably measurably more math in cases with freeform window rotations, but it helps us get weston_view out of the renderer. Signed-off-by: Derek Foreman --- libweston/pixman-renderer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index af9e3e334..a550cd87e 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -394,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; @@ -404,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);