From 0b52aa9d137b03017313e028accc92dc5d536440 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 30 Dec 2023 11:25:16 +0100 Subject: Initial rebase without effects --- types/scene/wlr_scene.c | 1299 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 944 insertions(+), 355 deletions(-) (limited to 'types/scene/wlr_scene.c') diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 4a32a6b..fab40a5 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -4,18 +4,21 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include +#include + #include "render/fx_renderer/fx_renderer.h" #include "types/fx/shadow_data.h" #include "types/wlr_buffer.h" +#include "types/wlr_output.h" #include "types/wlr_scene.h" #include "util/array.h" #include "util/env.h" @@ -23,14 +26,13 @@ #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 -static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { +struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); struct wlr_scene_tree *tree = wl_container_of(node, tree, node); return tree; } -static struct wlr_scene_rect *scene_rect_from_node( - struct wlr_scene_node *node) { +struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); struct wlr_scene_rect *rect = wl_container_of(node, rect, node); return rect; @@ -46,7 +48,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node( struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { struct wlr_scene_tree *tree; if (node->type == WLR_SCENE_NODE_TREE) { - tree = scene_tree_from_node(node); + tree = wlr_scene_tree_from_node(node); } else { tree = node->parent; } @@ -54,15 +56,17 @@ struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { while (tree->node.parent != NULL) { tree = tree->node.parent; } - return (struct wlr_scene *)tree; + struct wlr_scene *scene = wl_container_of(tree, scene, tree); + return scene; } static void scene_node_init(struct wlr_scene_node *node, enum wlr_scene_node_type type, struct wlr_scene_tree *parent) { - memset(node, 0, sizeof(*node)); - node->type = type; - node->parent = parent; - node->enabled = true; + *node = (struct wlr_scene_node){ + .type = type, + .parent = parent, + .enabled = true, + }; wl_list_init(&node->link); @@ -114,7 +118,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_buffer_unlock(scene_buffer->buffer); pixman_region32_fini(&scene_buffer->opaque_region); } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); if (scene_tree == &scene->tree) { assert(!node->parent); @@ -124,6 +128,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } wl_list_remove(&scene->presentation_destroy.link); + wl_list_remove(&scene->linux_dmabuf_v1_destroy.link); } else { assert(node->parent); } @@ -142,13 +147,13 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { static void scene_tree_init(struct wlr_scene_tree *tree, struct wlr_scene_tree *parent) { - memset(tree, 0, sizeof(*tree)); + *tree = (struct wlr_scene_tree){0}; scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); wl_list_init(&tree->children); } struct wlr_scene *wlr_scene_create(void) { - struct wlr_scene *scene = calloc(1, sizeof(struct wlr_scene)); + struct wlr_scene *scene = calloc(1, sizeof(*scene)); if (scene == NULL) { return NULL; } @@ -157,6 +162,7 @@ struct wlr_scene *wlr_scene_create(void) { wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); + wl_list_init(&scene->linux_dmabuf_v1_destroy.link); const char *debug_damage_options[] = { "none", @@ -175,7 +181,7 @@ struct wlr_scene *wlr_scene_create(void) { struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) { assert(parent); - struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree)); + struct wlr_scene_tree *tree = calloc(1, sizeof(*tree)); if (tree == NULL) { return NULL; } @@ -197,7 +203,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box switch (node->type) { case WLR_SCENE_NODE_TREE:; - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each_reverse(child, &scene_tree->children, link) { if (_scene_nodes_in_box(child, box, iterator, user_data, lx + child->x, ly + child->y)) { @@ -230,8 +236,11 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, pixman_region32_t *opaque) { + int width, height; + scene_node_get_size(node, &width, &height); + if (node->type == WLR_SCENE_NODE_RECT) { - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node); if (scene_rect->color[3] != 1) { return; } @@ -242,20 +251,22 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, return; } - // Buffer is translucent - if (scene_buffer->opacity != 1 || scene_buffer->corner_radius > 0) { + if (scene_buffer->opacity != 1) { + return; + } + + if (scene_buffer->corner_radius > 0) { return; } if (!buffer_is_opaque(scene_buffer->buffer)) { pixman_region32_copy(opaque, &scene_buffer->opaque_region); + pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height); pixman_region32_translate(opaque, x, y); return; } } - int width, height; - scene_node_get_size(node, &width, &height); pixman_region32_fini(opaque); pixman_region32_init_rect(opaque, x, y, width, height); } @@ -287,6 +298,28 @@ static void scale_output_damage(pixman_region32_t *damage, float scale) { } } +struct render_data { + enum wl_output_transform transform; + float scale; + struct wlr_box logical; + int trans_width, trans_height; + + struct wlr_scene_output *output; + + struct wlr_render_pass *render_pass; + pixman_region32_t damage; +}; + +static void transform_output_damage(pixman_region32_t *damage, const struct render_data *data) { + enum wl_output_transform transform = wlr_output_transform_invert(data->transform); + wlr_region_transform(damage, damage, transform, data->trans_width, data->trans_height); +} + +static void transform_output_box(struct wlr_box *box, const struct render_data *data) { + enum wl_output_transform transform = wlr_output_transform_invert(data->transform); + wlr_box_transform(box, box, transform, data->trans_width, data->trans_height); +} + static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) { if (!pixman_region32_not_empty(damage)) { return; @@ -308,7 +341,8 @@ static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *dam } static void update_node_update_outputs(struct wlr_scene_node *node, - struct wl_list *outputs, struct wlr_scene_output *ignore) { + struct wl_list *outputs, struct wlr_scene_output *ignore, + struct wlr_scene_output *force) { if (node->type != WLR_SCENE_NODE_BUFFER) { return; } @@ -316,8 +350,10 @@ static void update_node_update_outputs(struct wlr_scene_node *node, struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); uint32_t largest_overlap = 0; + struct wlr_scene_output *old_primary_output = scene_buffer->primary_output; scene_buffer->primary_output = NULL; + size_t count = 0; uint64_t active_outputs = 0; // let's update the outputs in two steps: @@ -356,11 +392,17 @@ static void update_node_update_outputs(struct wlr_scene_node *node, } active_outputs |= 1ull << scene_output->index; + count++; } pixman_region32_fini(&intersection); } + if (old_primary_output != scene_buffer->primary_output) { + scene_buffer->prev_feedback_options = + (struct wlr_linux_dmabuf_feedback_v1_init_options){0}; + } + uint64_t old_active = scene_buffer->active_outputs; scene_buffer->active_outputs = active_outputs; @@ -379,6 +421,31 @@ static void update_node_update_outputs(struct wlr_scene_node *node, // if there are active outputs on this node, we should always have a primary // output assert(!scene_buffer->active_outputs || scene_buffer->primary_output); + + // Skip output update event if nothing was updated + if (old_active == active_outputs && + (!force || ((1ull << force->index) & ~active_outputs)) && + old_primary_output == scene_buffer->primary_output) { + return; + } + + struct wlr_scene_output *outputs_array[64]; + struct wlr_scene_outputs_update_event event = { + .active = outputs_array, + .size = count, + }; + + size_t i = 0; + wl_list_for_each(scene_output, outputs, link) { + if (~active_outputs & (1ull << scene_output->index)) { + continue; + } + + assert(i < count); + outputs_array[i++] = scene_output; + } + + wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event); } static bool scene_node_update_iterator(struct wlr_scene_node *node, @@ -410,7 +477,7 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, } } - update_node_update_outputs(node, data->outputs, NULL); + update_node_update_outputs(node, data->outputs, NULL, NULL); return false; } @@ -422,7 +489,7 @@ static void scene_node_visibility(struct wlr_scene_node *node, } if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { scene_node_visibility(child, visible); @@ -440,7 +507,7 @@ static void scene_node_bounds(struct wlr_scene_node *node, } if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { scene_node_bounds(child, x + child->x, y + child->y, visible); @@ -517,8 +584,7 @@ static void scene_node_update(struct wlr_scene_node *node, struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, int width, int height, const float color[static 4]) { - struct wlr_scene_rect *scene_rect = - calloc(1, sizeof(struct wlr_scene_rect)); + struct wlr_scene_rect *scene_rect = calloc(1, sizeof(*scene_rect)); if (scene_rect == NULL) { return NULL; } @@ -566,12 +632,12 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, scene_buffer->buffer = wlr_buffer_lock(buffer); } + wl_signal_init(&scene_buffer->events.outputs_update); wl_signal_init(&scene_buffer->events.output_enter); wl_signal_init(&scene_buffer->events.output_leave); - wl_signal_init(&scene_buffer->events.output_present); + wl_signal_init(&scene_buffer->events.output_sample); wl_signal_init(&scene_buffer->events.frame_done); pixman_region32_init(&scene_buffer->opaque_region); - scene_buffer->opacity = 1; scene_buffer->corner_radius = 0; scene_buffer->shadow_data = shadow_data_get_default(); @@ -582,14 +648,13 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, } void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, - struct wlr_buffer *buffer, pixman_region32_t *damage) { + struct wlr_buffer *buffer, const pixman_region32_t *damage) { // specifying a region for a NULL buffer doesn't make sense. We need to know // about the buffer to scale the buffer local coordinates down to scene // coordinates. assert(buffer || !damage); bool update = false; - wlr_buffer_unlock(scene_buffer->buffer); wlr_texture_destroy(scene_buffer->texture); scene_buffer->texture = NULL; @@ -603,8 +668,10 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff (scene_buffer->buffer->width != buffer->width || scene_buffer->buffer->height != buffer->height)); + wlr_buffer_unlock(scene_buffer->buffer); scene_buffer->buffer = wlr_buffer_lock(buffer); } else { + wlr_buffer_unlock(scene_buffer->buffer); update = true; scene_buffer->buffer = NULL; } @@ -694,8 +761,8 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff pixman_region32_fini(&cull_region); pixman_region32_translate(&output_damage, - (lx - scene_output->x) * output_scale, - (ly - scene_output->y) * output_scale); + (int)round((lx - scene_output->x) * output_scale), + (int)round((ly - scene_output->y) * output_scale)); if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { wlr_output_schedule_frame(scene_output->output); } @@ -712,27 +779,35 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, } void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer, - pixman_region32_t *region) { + const pixman_region32_t *region) { if (pixman_region32_equal(&scene_buffer->opaque_region, region)) { return; } pixman_region32_copy(&scene_buffer->opaque_region, region); - scene_node_update(&scene_buffer->node, NULL); + + int x, y; + if (!wlr_scene_node_coords(&scene_buffer->node, &x, &y)) { + return; + } + + pixman_region32_t update_region; + pixman_region32_init(&update_region); + scene_node_bounds(&scene_buffer->node, x, y, &update_region); + scene_update_region(scene_node_get_root(&scene_buffer->node), &update_region); + pixman_region32_fini(&update_region); } void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, const struct wlr_fbox *box) { - struct wlr_fbox *cur = &scene_buffer->src_box; - if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) || - (box != NULL && wlr_fbox_equal(cur, box))) { + if (wlr_fbox_equal(&scene_buffer->src_box, box)) { return; } if (box != NULL) { - memcpy(cur, box, sizeof(*box)); + scene_buffer->src_box = *box; } else { - memset(cur, 0, sizeof(*cur)); + scene_buffer->src_box = (struct wlr_fbox){0}; } scene_node_update(&scene_buffer->node, NULL); @@ -776,6 +851,16 @@ void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer, scene_node_update(&scene_buffer->node, NULL); } +void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer, + enum wlr_scale_filter_mode filter_mode) { + if (scene_buffer->filter_mode == filter_mode) { + return; + } + + scene_buffer->filter_mode = filter_mode; + scene_node_update(&scene_buffer->node, NULL); +} + void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer, int radii) { if (scene_buffer->corner_radius == radii) { @@ -826,7 +911,7 @@ static void scene_node_get_size(struct wlr_scene_node *node, case WLR_SCENE_NODE_TREE: return; case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node); *width = scene_rect->width; *height = scene_rect->height; break; @@ -995,7 +1080,7 @@ static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); user_iterator(scene_buffer, lx, ly, user_data); } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); @@ -1025,7 +1110,7 @@ static bool scene_node_at_iterator(struct wlr_scene_node *node, struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->point_accepts_input && - !scene_buffer->point_accepts_input(scene_buffer, rx, ry)) { + !scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) { return false; } } @@ -1063,208 +1148,300 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, return NULL; } -static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - int ow, oh; - wlr_output_transformed_resolution(output, &ow, &oh); - - enum wl_output_transform transform = - wlr_output_transform_invert(output->transform); - wlr_box_transform(&box, &box, transform, ow, oh); - - fx_renderer_scissor(&box); -} - -static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *output, - pixman_region32_t *damage, const float color[static 4], - const struct wlr_box *box, const float matrix[static 9]) { - assert(fx_renderer); - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output, &rects[i]); - fx_render_rect(fx_renderer, box, color, matrix); - } -} - -static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *output, - pixman_region32_t *damage, struct wlr_texture *texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, - const float matrix[static 9], float opacity, int corner_radius) { - assert(fx_renderer); - - struct wlr_fbox default_src_box = {0}; - if (wlr_fbox_empty(src_box)) { - default_src_box.width = texture->width; - default_src_box.height = texture->height; - src_box = &default_src_box; - } - - // ensure the box is updated as per the output orientation - struct wlr_box transformed_box; - int width, height; - wlr_output_transformed_resolution(output, &width, &height); - wlr_box_transform(&transformed_box, dst_box, - wlr_output_transform_invert(output->transform), width, height); - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output, &rects[i]); - - fx_render_subtexture_with_matrix(fx_renderer, texture, src_box, - &transformed_box, matrix, opacity, corner_radius); - } -} - -static void render_box_shadow(struct fx_renderer *fx_renderer, - struct wlr_output *output, pixman_region32_t *surface_damage, - const struct wlr_box *surface_box, int corner_radius, - struct shadow_data *shadow_data) { - // don't damage area behind window since we dont render it anyway - pixman_region32_t inner_region; - pixman_region32_init(&inner_region); - pixman_region32_union_rect(&inner_region, &inner_region, - surface_box->x + corner_radius * 0.5, - surface_box->y + corner_radius * 0.5, - surface_box->width - corner_radius, - surface_box->height - corner_radius); - pixman_region32_intersect(&inner_region, &inner_region, surface_damage); - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_subtract(&damage, surface_damage, &inner_region); - if (!pixman_region32_not_empty(&damage)) { - goto damage_finish; - } - - struct wlr_box shadow_box = { - .x = surface_box->x - shadow_data->blur_sigma, - .y = surface_box->y - shadow_data->blur_sigma, - .width = surface_box->width + 2 * shadow_data->blur_sigma, - .height = surface_box->height + 2 * shadow_data->blur_sigma, - }; - float matrix[9]; - wlr_matrix_project_box(matrix, &shadow_box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - output->transform_matrix); - - // ensure the box is updated as per the output orientation - struct wlr_box transformed_box; - int width, height; - wlr_output_transformed_resolution(output, &width, &height); - wlr_box_transform(&transformed_box, &shadow_box, - wlr_output_transform_invert(output->transform), width, height); - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output, &rects[i]); - fx_render_box_shadow(fx_renderer, &transformed_box, surface_box, matrix, - corner_radius, shadow_data); - } - -damage_finish: - pixman_region32_fini(&damage); - pixman_region32_fini(&inner_region); -} - -static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_node *node, - struct wlr_scene_output *scene_output, pixman_region32_t *damage) { +// static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { +// struct wlr_box box = { +// .x = rect->x1, +// .y = rect->y1, +// .width = rect->x2 - rect->x1, +// .height = rect->y2 - rect->y1, +// }; +// +// int ow, oh; +// wlr_output_transformed_resolution(output, &ow, &oh); +// +// enum wl_output_transform transform = +// wlr_output_transform_invert(output->transform); +// wlr_box_transform(&box, &box, transform, ow, oh); +// +// fx_renderer_scissor(&box); +// } +// +// static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *output, +// pixman_region32_t *damage, const float color[static 4], +// const struct wlr_box *box, const float matrix[static 9]) { +// assert(fx_renderer); +// +// int nrects; +// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); +// for (int i = 0; i < nrects; ++i) { +// scissor_output(output, &rects[i]); +// fx_render_rect(fx_renderer, box, color, matrix); +// } +// } +// +// static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *output, +// pixman_region32_t *damage, struct wlr_texture *texture, +// const struct wlr_fbox *src_box, const struct wlr_box *dst_box, +// const float matrix[static 9], float opacity, int corner_radius) { +// assert(fx_renderer); +// +// struct wlr_fbox default_src_box = {0}; +// if (wlr_fbox_empty(src_box)) { +// default_src_box.width = texture->width; +// default_src_box.height = texture->height; +// src_box = &default_src_box; +// } +// +// // ensure the box is updated as per the output orientation +// struct wlr_box transformed_box; +// int width, height; +// wlr_output_transformed_resolution(output, &width, &height); +// wlr_box_transform(&transformed_box, dst_box, +// wlr_output_transform_invert(output->transform), width, height); +// +// int nrects; +// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); +// for (int i = 0; i < nrects; ++i) { +// scissor_output(output, &rects[i]); +// +// fx_render_subtexture_with_matrix(fx_renderer, texture, src_box, +// &transformed_box, matrix, opacity, corner_radius); +// } +// } +// +// static void render_box_shadow(struct fx_renderer *fx_renderer, +// struct wlr_output *output, pixman_region32_t *surface_damage, +// const struct wlr_box *surface_box, int corner_radius, +// struct shadow_data *shadow_data) { +// // don't damage area behind window since we dont render it anyway +// pixman_region32_t inner_region; +// pixman_region32_init(&inner_region); +// pixman_region32_union_rect(&inner_region, &inner_region, +// surface_box->x + corner_radius * 0.5, +// surface_box->y + corner_radius * 0.5, +// surface_box->width - corner_radius, +// surface_box->height - corner_radius); +// pixman_region32_intersect(&inner_region, &inner_region, surface_damage); +// +// pixman_region32_t damage; +// pixman_region32_init(&damage); +// pixman_region32_subtract(&damage, surface_damage, &inner_region); +// if (!pixman_region32_not_empty(&damage)) { +// goto damage_finish; +// } +// +// struct wlr_box shadow_box = { +// .x = surface_box->x - shadow_data->blur_sigma, +// .y = surface_box->y - shadow_data->blur_sigma, +// .width = surface_box->width + 2 * shadow_data->blur_sigma, +// .height = surface_box->height + 2 * shadow_data->blur_sigma, +// }; +// float matrix[9]; +// wlr_matrix_project_box(matrix, &shadow_box, WL_OUTPUT_TRANSFORM_NORMAL, 0, +// output->transform_matrix); +// +// // ensure the box is updated as per the output orientation +// struct wlr_box transformed_box; +// int width, height; +// wlr_output_transformed_resolution(output, &width, &height); +// wlr_box_transform(&transformed_box, &shadow_box, +// wlr_output_transform_invert(output->transform), width, height); +// +// int nrects; +// pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); +// for (int i = 0; i < nrects; ++i) { +// scissor_output(output, &rects[i]); +// fx_render_box_shadow(fx_renderer, &transformed_box, surface_box, matrix, +// corner_radius, shadow_data); +// } +// +// damage_finish: +// pixman_region32_fini(&damage); +// pixman_region32_fini(&inner_region); +// } +// +// static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_node *node, +// struct wlr_scene_output *scene_output, pixman_region32_t *damage) { +// int x, y; +// wlr_scene_node_coords(node, &x, &y); +// x -= scene_output->x; +// y -= scene_output->y; +// +// struct wlr_output *output = scene_output->output; +// +// pixman_region32_t render_region; +// pixman_region32_init(&render_region); +// pixman_region32_copy(&render_region, &node->visible); +// pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); +// scale_output_damage(&render_region, output->scale); +// pixman_region32_intersect(&render_region, &render_region, damage); +// if (!pixman_region32_not_empty(&render_region)) { +// pixman_region32_fini(&render_region); +// return; +// } +// +// struct wlr_box dst_box = { +// .x = x, +// .y = y, +// }; +// scene_node_get_size(node, &dst_box.width, &dst_box.height); +// scale_box(&dst_box, output->scale); +// +// struct wlr_texture *texture; +// float matrix[9]; +// enum wl_output_transform transform; +// switch (node->type) { +// case WLR_SCENE_NODE_TREE: +// assert(false); +// break; +// case WLR_SCENE_NODE_RECT:; +// struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); +// +// render_rect(fx_renderer, output, &render_region, scene_rect->color, &dst_box, +// output->transform_matrix); +// break; +// case WLR_SCENE_NODE_BUFFER:; +// struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); +// assert(scene_buffer->buffer); +// +// struct wlr_renderer *renderer = output->renderer; +// texture = scene_buffer_get_texture(scene_buffer, renderer); +// +// transform = wlr_output_transform_invert(scene_buffer->transform); +// wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, +// output->transform_matrix); +// +// // Some surfaces (mostly GTK 4) decorate their windows with shadows +// // which extends the node size past the actual window size. This gets +// // the actual surface geometry, mostly ignoring CSD decorations +// // but only if we need to. +// if (scene_buffer->corner_radius != 0 || +// scene_buffer_has_shadow(&scene_buffer->shadow_data)) { +// struct wlr_scene_surface *scene_surface = NULL; +// if ((scene_surface = wlr_scene_surface_from_buffer(scene_buffer)) && +// wlr_surface_is_xdg_surface(scene_surface->surface)) { +// struct wlr_xdg_surface *xdg_surface = +// wlr_xdg_surface_from_wlr_surface(scene_surface->surface); +// +// struct wlr_box geometry; +// wlr_xdg_surface_get_geometry(xdg_surface, &geometry); +// dst_box.width = fmin(dst_box.width, geometry.width); +// dst_box.height = fmin(dst_box.height, geometry.height); +// dst_box.x = fmax(dst_box.x, geometry.x + x); +// dst_box.y = fmax(dst_box.y, geometry.y + y); +// } +// } +// +// // Shadow +// if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { +// // TODO: Compensate for SSD borders here +// render_box_shadow(fx_renderer, output, &render_region, &dst_box, +// scene_buffer->corner_radius, &scene_buffer->shadow_data); +// } +// +// // Clip the damage to the dst_box before rendering the texture +// pixman_region32_intersect_rect(&render_region, &render_region, +// dst_box.x, dst_box.y, dst_box.width, dst_box.height); +// +// render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box, +// &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius); +// +// wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); +// break; +// } +// +// pixman_region32_fini(&render_region); +// } + +struct render_list_entry { + struct wlr_scene_node *node; + bool sent_dmabuf_feedback; int x, y; - wlr_scene_node_coords(node, &x, &y); - x -= scene_output->x; - y -= scene_output->y; +}; - struct wlr_output *output = scene_output->output; +static void scene_entry_render(struct render_list_entry *entry, const struct render_data *data) { + struct wlr_scene_node *node = entry->node; pixman_region32_t render_region; pixman_region32_init(&render_region); pixman_region32_copy(&render_region, &node->visible); - pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); - scale_output_damage(&render_region, output->scale); - pixman_region32_intersect(&render_region, &render_region, damage); + pixman_region32_translate(&render_region, -data->logical.x, -data->logical.y); + scale_output_damage(&render_region, data->scale); + pixman_region32_intersect(&render_region, &render_region, &data->damage); if (!pixman_region32_not_empty(&render_region)) { pixman_region32_fini(&render_region); return; } struct wlr_box dst_box = { - .x = x, - .y = y, + .x = entry->x - data->logical.x, + .y = entry->y - data->logical.y, }; scene_node_get_size(node, &dst_box.width, &dst_box.height); - scale_box(&dst_box, output->scale); + scale_box(&dst_box, data->scale); + + pixman_region32_t opaque; + pixman_region32_init(&opaque); + scene_node_opaque_region(node, dst_box.x, dst_box.y, &opaque); + scale_output_damage(&opaque, data->scale); + pixman_region32_subtract(&opaque, &render_region, &opaque); + + transform_output_box(&dst_box, data); + transform_output_damage(&render_region, data); - struct wlr_texture *texture; - float matrix[9]; - enum wl_output_transform transform; switch (node->type) { case WLR_SCENE_NODE_TREE: assert(false); break; case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - - render_rect(fx_renderer, output, &render_region, scene_rect->color, &dst_box, - output->transform_matrix); + struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node); + + wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){ + .box = dst_box, + .color = { + .r = scene_rect->color[0], + .g = scene_rect->color[1], + .b = scene_rect->color[2], + .a = scene_rect->color[3], + }, + .clip = &render_region, + }); break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); assert(scene_buffer->buffer); - struct wlr_renderer *renderer = output->renderer; - texture = scene_buffer_get_texture(scene_buffer, renderer); - - transform = wlr_output_transform_invert(scene_buffer->transform); - wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, - output->transform_matrix); - - // Some surfaces (mostly GTK 4) decorate their windows with shadows - // which extends the node size past the actual window size. This gets - // the actual surface geometry, mostly ignoring CSD decorations - // but only if we need to. - if (scene_buffer->corner_radius != 0 || - scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - struct wlr_scene_surface *scene_surface = NULL; - if ((scene_surface = wlr_scene_surface_from_buffer(scene_buffer)) && - wlr_surface_is_xdg_surface(scene_surface->surface)) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(scene_surface->surface); - - struct wlr_box geometry; - wlr_xdg_surface_get_geometry(xdg_surface, &geometry); - dst_box.width = fmin(dst_box.width, geometry.width); - dst_box.height = fmin(dst_box.height, geometry.height); - dst_box.x = fmax(dst_box.x, geometry.x + x); - dst_box.y = fmax(dst_box.y, geometry.y + y); - } - } - - // Shadow - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - // TODO: Compensate for SSD borders here - render_box_shadow(fx_renderer, output, &render_region, &dst_box, - scene_buffer->corner_radius, &scene_buffer->shadow_data); + struct wlr_texture *texture = scene_buffer_get_texture(scene_buffer, + data->output->output->renderer); + if (texture == NULL) { + break; } - // Clip the damage to the dst_box before rendering the texture - pixman_region32_intersect_rect(&render_region, &render_region, - dst_box.x, dst_box.y, dst_box.width, dst_box.height); - - render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box, - &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius); - - wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); + enum wl_output_transform transform = + wlr_output_transform_invert(scene_buffer->transform); + transform = wlr_output_transform_compose(transform, data->transform); + + wlr_render_pass_add_texture(data->render_pass, &(struct wlr_render_texture_options) { + .texture = texture, + .src_box = scene_buffer->src_box, + .dst_box = dst_box, + .transform = transform, + .clip = &render_region, + .alpha = &scene_buffer->opacity, + .filter_mode = scene_buffer->filter_mode, + .blend_mode = pixman_region32_not_empty(&opaque) ? + WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE, + }); + + struct wlr_scene_output_sample_event sample_event = { + .output = data->output, + .direct_scanout = false, + }; + wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event); break; } + pixman_region32_fini(&opaque); pixman_region32_fini(&render_region); } @@ -1285,6 +1462,23 @@ void wlr_scene_set_presentation(struct wlr_scene *scene, wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy); } +static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene *scene = + wl_container_of(listener, scene, linux_dmabuf_v1_destroy); + wl_list_remove(&scene->linux_dmabuf_v1_destroy.link); + wl_list_init(&scene->linux_dmabuf_v1_destroy.link); + scene->linux_dmabuf_v1 = NULL; +} + +void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene, + struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1) { + assert(scene->linux_dmabuf_v1 == NULL); + scene->linux_dmabuf_v1 = linux_dmabuf_v1; + scene->linux_dmabuf_v1_destroy.notify = scene_handle_linux_dmabuf_v1_destroy; + wl_signal_add(&linux_dmabuf_v1->events.destroy, &scene->linux_dmabuf_v1_destroy); +} + static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); @@ -1296,50 +1490,47 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; - static void scene_node_output_update(struct wlr_scene_node *node, - struct wl_list *outputs, struct wlr_scene_output *ignore) { + struct wl_list *outputs, struct wlr_scene_output *ignore, + struct wlr_scene_output *force) { if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { - scene_node_output_update(child, outputs, ignore); + scene_node_output_update(child, outputs, ignore, force); } return; } - update_node_update_outputs(node, outputs, ignore); + update_node_update_outputs(node, outputs, ignore, force); } -static void scene_output_update_geometry(struct wlr_scene_output *scene_output) { - int width, height; - wlr_output_transformed_resolution(scene_output->output, &width, &height); - wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height); +static void scene_output_update_geometry(struct wlr_scene_output *scene_output, + bool force_update) { + wlr_damage_ring_add_whole(&scene_output->damage_ring); wlr_output_schedule_frame(scene_output->output); scene_node_output_update(&scene_output->scene->tree.node, - &scene_output->scene->outputs, NULL); + &scene_output->scene->outputs, NULL, force_update ? scene_output : NULL); } static void scene_output_handle_commit(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_commit); struct wlr_output_event_commit *event = data; + const struct wlr_output_state *state = event->state; - if (event->committed & (WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_TRANSFORM | - WLR_OUTPUT_STATE_SCALE | + bool force_update = state->committed & ( + WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SCALE | + WLR_OUTPUT_STATE_SUBPIXEL); + + if (force_update || state->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED)) { - scene_output_update_geometry(scene_output); + scene_output_update_geometry(scene_output, force_update); } } -static void scene_output_handle_mode(struct wl_listener *listener, void *data) { - struct wlr_scene_output *scene_output = wl_container_of(listener, - scene_output, output_mode); - scene_output_update_geometry(scene_output); -} - static void scene_output_handle_damage(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_damage); @@ -1395,16 +1586,13 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output_commit.notify = scene_output_handle_commit; wl_signal_add(&output->events.commit, &scene_output->output_commit); - scene_output->output_mode.notify = scene_output_handle_mode; - wl_signal_add(&output->events.mode, &scene_output->output_mode); - scene_output->output_damage.notify = scene_output_handle_damage; wl_signal_add(&output->events.damage, &scene_output->output_damage); scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); - scene_output_update_geometry(scene_output); + scene_output_update_geometry(scene_output, false); return scene_output; } @@ -1423,18 +1611,21 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_signal_emit_mutable(&scene_output->events.destroy, NULL); scene_node_output_update(&scene_output->scene->tree.node, - &scene_output->scene->outputs, scene_output); + &scene_output->scene->outputs, scene_output, NULL); struct highlight_region *damage, *tmp_damage; wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) { highlight_region_destroy(damage); } + struct fx_renderer *fx_renderer = + fx_renderer_addon_find(&scene_output->output->addons, scene_output->scene); + wlr_addon_finish(&fx_renderer->addon); + wlr_addon_finish(&scene_output->addon); wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); wl_list_remove(&scene_output->output_commit.link); - wl_list_remove(&scene_output->output_mode.link); wl_list_remove(&scene_output->output_damage.link); wl_list_remove(&scene_output->output_needs_frame.link); @@ -1463,14 +1654,14 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; - scene_output_update_geometry(scene_output); + scene_output_update_geometry(scene_output, false); } static bool scene_node_invisible(struct wlr_scene_node *node) { if (node->type == WLR_SCENE_NODE_TREE) { return true; } else if (node->type == WLR_SCENE_NODE_RECT) { - struct wlr_scene_rect *rect = scene_rect_from_node(node); + struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node); return rect->color[3] == 0.f; } else if (node->type == WLR_SCENE_NODE_BUFFER) { @@ -1500,7 +1691,7 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node, // If we see a black rect, we can ignore rendering everything under the rect // and even the rect itself. if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) { - struct wlr_scene_rect *rect = scene_rect_from_node(node); + struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node); float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f }; if (memcmp(rect->color, black, sizeof(float) * 4) == 0) { @@ -1520,16 +1711,66 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node, pixman_region32_fini(&intersection); - struct wlr_scene_node **entry = wl_array_add(data->render_list, - sizeof(struct wlr_scene_node *)); - if (entry) { - *entry = node; + struct render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry)); + if (!entry) { + return false; } + + *entry = (struct render_list_entry){ + .node = node, + .x = lx, + .y = ly, + }; + return false; } -static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, - struct wlr_scene_output *scene_output, struct wlr_box *box) { +static void output_state_apply_damage(const struct render_data *data, + struct wlr_output_state *state) { + pixman_region32_t frame_damage; + pixman_region32_init(&frame_damage); + pixman_region32_copy(&frame_damage, &data->output->damage_ring.current); + transform_output_damage(&frame_damage, data); + wlr_output_state_set_damage(state, &frame_damage); + pixman_region32_fini(&frame_damage); +} + +static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene, + struct wlr_scene_buffer *scene_buffer, + const struct wlr_linux_dmabuf_feedback_v1_init_options *options) { + if (!scene->linux_dmabuf_v1) { + return; + } + + struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(scene_buffer); + if (!surface) { + return; + } + + // compare to the previous options so that we don't send + // duplicate feedback events. + if (memcmp(options, &scene_buffer->prev_feedback_options, sizeof(*options)) == 0) { + return; + } + + scene_buffer->prev_feedback_options = *options; + + struct wlr_linux_dmabuf_feedback_v1 feedback = {0}; + if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, options)) { + return; + } + + wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1, + surface->surface, &feedback); + + wlr_linux_dmabuf_feedback_v1_finish(&feedback); +} + +static bool scene_entry_try_direct_scanout(struct render_list_entry *entry, + struct wlr_output_state *state, const struct render_data *data) { + struct wlr_scene_output *scene_output = data->output; + struct wlr_scene_node *node = entry->node; + if (!scene_output->scene->direct_scanout) { return false; } @@ -1545,8 +1786,18 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, return false; } + if (state->committed & (WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_ENABLED | + WLR_OUTPUT_STATE_RENDER_FORMAT)) { + // Legacy DRM will explode if we try to modeset with a direct scanout buffer + return false; + } + + if (!wlr_output_is_direct_scanout_allowed(scene_output->output)) { + return false; + } + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - struct wlr_output *output = scene_output->output; struct wlr_fbox default_box = {0}; if (buffer->transform & WL_OUTPUT_TRANSFORM_90) { @@ -1562,75 +1813,396 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, return false; } - if (buffer->transform != output->transform) { + if (buffer->transform != data->transform) { return false; } - struct wlr_box node_box; - wlr_scene_node_coords(node, &node_box.x, &node_box.y); + struct wlr_box node_box = { .x = entry->x, .y = entry->y }; scene_node_get_size(node, &node_box.width, &node_box.height); - if (!wlr_box_equal(box, &node_box)) { + if (!wlr_box_equal(&data->logical, &node_box)) { + return false; + } + + if (buffer->primary_output == scene_output) { + struct wlr_linux_dmabuf_feedback_v1_init_options options = { + .main_renderer = scene_output->output->renderer, + .scanout_primary_output = scene_output->output, + }; + + scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options); + entry->sent_dmabuf_feedback = true; + } + + struct wlr_output_state pending; + wlr_output_state_init(&pending); + if (!wlr_output_state_copy(&pending, state)) { return false; } - wlr_output_attach_buffer(output, buffer->buffer); - if (!wlr_output_test(output)) { - wlr_output_rollback(output); + wlr_output_state_set_buffer(&pending, buffer->buffer); + output_state_apply_damage(data, &pending); + + if (!wlr_output_test_state(scene_output->output, &pending)) { + wlr_output_state_finish(&pending); return false; } - return wlr_output_commit(output); + wlr_output_state_copy(state, &pending); + wlr_output_state_finish(&pending); + + struct wlr_scene_output_sample_event sample_event = { + .output = scene_output, + .direct_scanout = true, + }; + wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event); + return true; } -bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { +// bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { +// struct wlr_output *output = scene_output->output; +// enum wlr_scene_debug_damage_option debug_damage = +// scene_output->scene->debug_damage_option; +// +// // Find the fx_renderer addon +// struct fx_renderer *renderer = +// fx_renderer_addon_find(&output->addons, scene_output->scene); +// assert(renderer != NULL); +// +// struct render_list_constructor_data list_con = { +// .box = { .x = scene_output->x, .y = scene_output->y }, +// .render_list = &scene_output->render_list, +// .calculate_visibility = scene_output->scene->calculate_visibility, +// }; +// wlr_output_effective_resolution(output, +// &list_con.box.width, &list_con.box.height); +// +// list_con.render_list->size = 0; +// scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, +// construct_render_list_iterator, &list_con); +// array_realloc(list_con.render_list, list_con.render_list->size); +// +// int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *); +// struct wlr_scene_node **list_data = list_con.render_list->data; +// +// // if there is only one thing to render let's see if that thing can be +// // directly scanned out +// bool scanout = false; +// if (list_len == 1) { +// struct wlr_scene_node *node = list_data[0]; +// scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); +// } +// +// if (scene_output->prev_scanout != scanout) { +// scene_output->prev_scanout = scanout; +// wlr_log(WLR_DEBUG, "Direct scan-out %s", +// scanout ? "enabled" : "disabled"); +// // When exiting direct scan-out, damage everything +// wlr_damage_ring_add_whole(&scene_output->damage_ring); +// } +// +// if (scanout) { +// struct wlr_scene_node *node = list_data[0]; +// +// assert(node->type == WLR_SCENE_NODE_BUFFER); +// struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); +// wl_signal_emit_mutable(&buffer->events.output_present, scene_output); +// return true; +// } +// +// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { +// wlr_damage_ring_add_whole(&scene_output->damage_ring); +// } +// +// struct timespec now; +// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { +// struct wl_list *regions = &scene_output->damage_highlight_regions; +// clock_gettime(CLOCK_MONOTONIC, &now); +// +// // add the current frame's damage if there is damage +// if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { +// struct highlight_region *current_damage = +// calloc(1, sizeof(*current_damage)); +// if (current_damage) { +// pixman_region32_init(¤t_damage->region); +// pixman_region32_copy(¤t_damage->region, +// &scene_output->damage_ring.current); +// current_damage->when = now; +// wl_list_insert(regions, ¤t_damage->link); +// } +// } +// +// pixman_region32_t acc_damage; +// pixman_region32_init(&acc_damage); +// struct highlight_region *damage, *tmp_damage; +// wl_list_for_each_safe(damage, tmp_damage, regions, link) { +// // remove overlaping damage regions +// pixman_region32_subtract(&damage->region, &damage->region, &acc_damage); +// pixman_region32_union(&acc_damage, &acc_damage, &damage->region); +// +// // if this damage is too old or has nothing in it, get rid of it +// struct timespec time_diff; +// timespec_sub(&time_diff, &now, &damage->when); +// if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME || +// !pixman_region32_not_empty(&damage->region)) { +// highlight_region_destroy(damage); +// } +// } +// +// wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage); +// pixman_region32_fini(&acc_damage); +// } +// +// int buffer_age; +// if (!wlr_output_attach_render(output, &buffer_age)) { +// return false; +// } +// +// pixman_region32_t damage; +// pixman_region32_init(&damage); +// wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, +// buffer_age, &damage); +// if (!output->needs_frame && !pixman_region32_not_empty( +// &scene_output->damage_ring.current)) { +// pixman_region32_fini(&damage); +// wlr_output_rollback(output); +// return true; +// } +// +// fx_renderer_begin(renderer, output->width, output->height); +// +// pixman_region32_t background; +// pixman_region32_init(&background); +// pixman_region32_copy(&background, &damage); +// +// // Cull areas of the background that are occluded by opaque regions of +// // scene nodes above. Those scene nodes will just render atop having us +// // never see the background. +// if (scene_output->scene->calculate_visibility) { +// float output_scale = scene_output->output->scale; +// +// for (int i = list_len - 1; i >= 0; i--) { +// struct wlr_scene_node *node = list_data[i]; +// int x, y; +// wlr_scene_node_coords(node, &x, &y); +// +// // We must only cull opaque regions that are visible by the node. +// // The node's visibility will have the knowledge of a black rect +// // that may have been omitted from the render list via the black +// // rect optimization. In order to ensure we don't cull background +// // rendering in that black rect region, consider the node's visibility. +// pixman_region32_t opaque; +// pixman_region32_init(&opaque); +// scene_node_opaque_region(node, x, y, &opaque); +// pixman_region32_intersect(&opaque, &opaque, &node->visible); +// +// pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y); +// wlr_region_scale(&opaque, &opaque, output_scale); +// pixman_region32_subtract(&background, &background, &opaque); +// pixman_region32_fini(&opaque); +// } +// +// if (floor(output_scale) != output_scale) { +// wlr_region_expand(&background, &background, 1); +// +// // reintersect with the damage because we never want to render +// // outside of the damage region +// pixman_region32_intersect(&background, &background, &damage); +// } +// } +// +// int nrects; +// pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects); +// for (int i = 0; i < nrects; ++i) { +// scissor_output(output, &rects[i]); +// fx_renderer_clear((float[4]){ 0.0, 0.0, 0.0, 1.0 }); +// } +// pixman_region32_fini(&background); +// +// for (int i = list_len - 1; i >= 0; i--) { +// struct wlr_scene_node *node = list_data[i]; +// scene_node_render(renderer, node, scene_output, &damage); +// } +// +// fx_renderer_scissor(NULL); +// +// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { +// struct highlight_region *damage; +// wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { +// struct timespec time_diff; +// timespec_sub(&time_diff, &now, &damage->when); +// int64_t time_diff_ms = timespec_to_msec(&time_diff); +// float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; +// +// int nrects; +// pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects); +// for (int i = 0; i < nrects; ++i) { +// struct wlr_box box = { +// .x = rects[i].x1, +// .y = rects[i].y1, +// .width = rects[i].x2 - rects[i].x1, +// .height = rects[i].y2 - rects[i].y1, +// }; +// +// float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 }; +// fx_render_rect(renderer, &box, color, output->transform_matrix); +// } +// } +// } +// +// // Draw the software cursors +// wlr_renderer_begin(output->renderer, output->width, output->height); +// wlr_output_render_software_cursors(output, &damage); +// wlr_renderer_end(output->renderer); +// +// pixman_region32_fini(&damage); +// +// int tr_width, tr_height; +// wlr_output_transformed_resolution(output, &tr_width, &tr_height); +// +// enum wl_output_transform transform = +// wlr_output_transform_invert(output->transform); +// +// pixman_region32_t frame_damage; +// pixman_region32_init(&frame_damage); +// wlr_region_transform(&frame_damage, +// &scene_output->damage_ring.current, +// transform, tr_width, tr_height); +// wlr_output_set_damage(output, &frame_damage); +// pixman_region32_fini(&frame_damage); +// +// bool success = wlr_output_commit(output); +// +// if (success) { +// wlr_damage_ring_rotate(&scene_output->damage_ring); +// } +// +// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && +// !wl_list_empty(&scene_output->damage_highlight_regions)) { +// wlr_output_schedule_frame(scene_output->output); +// } +// +// return success; +// } + +bool wlr_scene_output_commit(struct wlr_scene_output *scene_output, + const struct wlr_scene_output_state_options *options) { + if (!scene_output->output->needs_frame && !pixman_region32_not_empty( + &scene_output->damage_ring.current)) { + return true; + } + + bool ok = false; + struct wlr_output_state state; + wlr_output_state_init(&state); + if (!wlr_scene_output_build_state(scene_output, &state, options)) { + goto out; + } + + ok = wlr_output_commit_state(scene_output->output, &state); + if (!ok) { + goto out; + } + + wlr_damage_ring_rotate(&scene_output->damage_ring); + +out: + wlr_output_state_finish(&state); + return ok; +} + +bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, + struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) { + struct wlr_scene_output_state_options default_options = {0}; + if (!options) { + options = &default_options; + } + struct wlr_scene_timer *timer = options->timer; + struct timespec start_time; + if (timer) { + clock_gettime(CLOCK_MONOTONIC, &start_time); + wlr_scene_timer_finish(timer); + *timer = (struct wlr_scene_timer){0}; + } + + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) { + // if the state is being disabled, do nothing. + return true; + } + struct wlr_output *output = scene_output->output; enum wlr_scene_debug_damage_option debug_damage = scene_output->scene->debug_damage_option; - // Find the fx_renderer addon - struct fx_renderer *renderer = - fx_renderer_addon_find(&output->addons, scene_output->scene); - assert(renderer != NULL); + struct render_data render_data = { + .transform = output->transform, + .scale = output->scale, + .logical = { .x = scene_output->x, .y = scene_output->y }, + .output = scene_output, + }; + + output_pending_resolution(output, state, + &render_data.trans_width, &render_data.trans_height); + + if (state->committed & WLR_OUTPUT_STATE_TRANSFORM) { + if (render_data.transform != state->transform) { + wlr_damage_ring_add_whole(&scene_output->damage_ring); + } + + render_data.transform = state->transform; + } + + if (state->committed & WLR_OUTPUT_STATE_SCALE) { + if (render_data.scale != state->scale) { + wlr_damage_ring_add_whole(&scene_output->damage_ring); + } + + render_data.scale = state->scale; + } + + if (render_data.transform & WL_OUTPUT_TRANSFORM_90) { + int tmp = render_data.trans_width; + render_data.trans_width = render_data.trans_height; + render_data.trans_height = tmp; + } + + render_data.logical.width = render_data.trans_width / render_data.scale; + render_data.logical.height = render_data.trans_height / render_data.scale; struct render_list_constructor_data list_con = { - .box = { .x = scene_output->x, .y = scene_output->y }, + .box = render_data.logical, .render_list = &scene_output->render_list, .calculate_visibility = scene_output->scene->calculate_visibility, }; - wlr_output_effective_resolution(output, - &list_con.box.width, &list_con.box.height); list_con.render_list->size = 0; scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, construct_render_list_iterator, &list_con); array_realloc(list_con.render_list, list_con.render_list->size); - int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *); - struct wlr_scene_node **list_data = list_con.render_list->data; + struct render_list_entry *list_data = list_con.render_list->data; + int list_len = list_con.render_list->size / sizeof(*list_data); - // if there is only one thing to render let's see if that thing can be - // directly scanned out - bool scanout = false; - if (list_len == 1) { - struct wlr_scene_node *node = list_data[0]; - scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); - } + bool scanout = list_len == 1 && + scene_entry_try_direct_scanout(&list_data[0], state, &render_data); if (scene_output->prev_scanout != scanout) { scene_output->prev_scanout = scanout; wlr_log(WLR_DEBUG, "Direct scan-out %s", scanout ? "enabled" : "disabled"); - // When exiting direct scan-out, damage everything - wlr_damage_ring_add_whole(&scene_output->damage_ring); + if (!scanout) { + // When exiting direct scan-out, damage everything + wlr_damage_ring_add_whole(&scene_output->damage_ring); + } } if (scanout) { - struct wlr_scene_node *node = list_data[0]; - - assert(node->type == WLR_SCENE_NODE_BUFFER); - struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - wl_signal_emit_mutable(&buffer->events.output_present, scene_output); + if (timer) { + struct timespec end_time, duration; + clock_gettime(CLOCK_MONOTONIC, &end_time); + timespec_sub(&duration, &end_time, &start_time); + timer->pre_render_duration = timespec_to_nsec(&duration); + } return true; } @@ -1645,8 +2217,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { // add the current frame's damage if there is damage if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { - struct highlight_region *current_damage = - calloc(1, sizeof(*current_damage)); + struct highlight_region *current_damage = calloc(1, sizeof(*current_damage)); if (current_damage) { pixman_region32_init(¤t_damage->region); pixman_region32_copy(¤t_damage->region, @@ -1677,38 +2248,52 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_fini(&acc_damage); } + wlr_damage_ring_set_bounds(&scene_output->damage_ring, + render_data.trans_width, render_data.trans_height); + + if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) { + return false; + } + int buffer_age; - if (!wlr_output_attach_render(output, &buffer_age)) { + struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain, &buffer_age); + if (buffer == NULL) { return false; } - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, - buffer_age, &damage); - if (!output->needs_frame && !pixman_region32_not_empty( - &scene_output->damage_ring.current)) { - pixman_region32_fini(&damage); - wlr_output_rollback(output); - return true; + if (timer) { + timer->render_timer = wlr_render_timer_create(output->renderer); + + struct timespec end_time, duration; + clock_gettime(CLOCK_MONOTONIC, &end_time); + timespec_sub(&duration, &end_time, &start_time); + timer->pre_render_duration = timespec_to_nsec(&duration); } - fx_renderer_begin(renderer, output->width, output->height); + struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer, + &(struct wlr_buffer_pass_options){ + .timer = timer ? timer->render_timer : NULL, + }); + if (render_pass == NULL) { + wlr_buffer_unlock(buffer); + return false; + } + + render_data.render_pass = render_pass; + pixman_region32_init(&render_data.damage); + wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, + buffer_age, &render_data.damage); pixman_region32_t background; pixman_region32_init(&background); - pixman_region32_copy(&background, &damage); + pixman_region32_copy(&background, &render_data.damage); // Cull areas of the background that are occluded by opaque regions of // scene nodes above. Those scene nodes will just render atop having us // never see the background. if (scene_output->scene->calculate_visibility) { - float output_scale = scene_output->output->scale; - for (int i = list_len - 1; i >= 0; i--) { - struct wlr_scene_node *node = list_data[i]; - int x, y; - wlr_scene_node_coords(node, &x, &y); + struct render_list_entry *entry = &list_data[i]; // We must only cull opaque regions that are visible by the node. // The node's visibility will have the knowledge of a black rect @@ -1717,38 +2302,49 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { // rendering in that black rect region, consider the node's visibility. pixman_region32_t opaque; pixman_region32_init(&opaque); - scene_node_opaque_region(node, x, y, &opaque); - pixman_region32_intersect(&opaque, &opaque, &node->visible); + scene_node_opaque_region(entry->node, entry->x, entry->y, &opaque); + pixman_region32_intersect(&opaque, &opaque, &entry->node->visible); pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y); - wlr_region_scale(&opaque, &opaque, output_scale); + wlr_region_scale(&opaque, &opaque, render_data.scale); pixman_region32_subtract(&background, &background, &opaque); pixman_region32_fini(&opaque); } - if (floor(output_scale) != output_scale) { + if (floor(render_data.scale) != render_data.scale) { wlr_region_expand(&background, &background, 1); // reintersect with the damage because we never want to render // outside of the damage region - pixman_region32_intersect(&background, &background, &damage); + pixman_region32_intersect(&background, &background, &render_data.damage); } } - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output, &rects[i]); - fx_renderer_clear((float[4]){ 0.0, 0.0, 0.0, 1.0 }); - } + transform_output_damage(&background, &render_data); + wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){ + .box = { .width = buffer->width, .height = buffer->height }, + .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, + .clip = &background, + }); pixman_region32_fini(&background); for (int i = list_len - 1; i >= 0; i--) { - struct wlr_scene_node *node = list_data[i]; - scene_node_render(renderer, node, scene_output, &damage); - } + struct render_list_entry *entry = &list_data[i]; + scene_entry_render(entry, &render_data); + + if (entry->node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node); - fx_renderer_scissor(NULL); + if (buffer->primary_output == scene_output && !entry->sent_dmabuf_feedback) { + struct wlr_linux_dmabuf_feedback_v1_init_options options = { + .main_renderer = output->renderer, + .scanout_primary_output = NULL, + }; + + scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options); + } + } + } if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { struct highlight_region *damage; @@ -1758,55 +2354,48 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { int64_t time_diff_ms = timespec_to_msec(&time_diff); float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects); - for (int i = 0; i < nrects; ++i) { - struct wlr_box box = { - .x = rects[i].x1, - .y = rects[i].y1, - .width = rects[i].x2 - rects[i].x1, - .height = rects[i].y2 - rects[i].y1, - }; - - float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 }; - fx_render_rect(renderer, &box, color, output->transform_matrix); - } + wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){ + .box = { .width = buffer->width, .height = buffer->height }, + .color = { .r = alpha * 0.5, .g = 0, .b = 0, .a = alpha * 0.5 }, + .clip = &damage->region, + }); } } - // Draw the software cursors - wlr_renderer_begin(output->renderer, output->width, output->height); - wlr_output_render_software_cursors(output, &damage); - wlr_renderer_end(output->renderer); - - pixman_region32_fini(&damage); + wlr_output_add_software_cursors_to_render_pass(output, render_pass, &render_data.damage); - int tr_width, tr_height; - wlr_output_transformed_resolution(output, &tr_width, &tr_height); + pixman_region32_fini(&render_data.damage); - enum wl_output_transform transform = - wlr_output_transform_invert(output->transform); - - pixman_region32_t frame_damage; - pixman_region32_init(&frame_damage); - wlr_region_transform(&frame_damage, - &scene_output->damage_ring.current, - transform, tr_width, tr_height); - wlr_output_set_damage(output, &frame_damage); - pixman_region32_fini(&frame_damage); - - bool success = wlr_output_commit(output); - - if (success) { - wlr_damage_ring_rotate(&scene_output->damage_ring); + if (!wlr_render_pass_submit(render_pass)) { + wlr_buffer_unlock(buffer); + return false; } + wlr_output_state_set_buffer(state, buffer); + wlr_buffer_unlock(buffer); + output_state_apply_damage(&render_data, state); + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && !wl_list_empty(&scene_output->damage_highlight_regions)) { wlr_output_schedule_frame(scene_output->output); } - return success; + return true; +} + +int64_t wlr_scene_timer_get_duration_ns(struct wlr_scene_timer *timer) { + int64_t pre_render = timer->pre_render_duration; + if (!timer->render_timer) { + return pre_render; + } + int64_t render = wlr_render_timer_get_duration_ns(timer->render_timer); + return render != -1 ? pre_render + render : -1; +} + +void wlr_scene_timer_finish(struct wlr_scene_timer *timer) { + if (timer->render_timer) { + wlr_render_timer_destroy(timer->render_timer); + } } static void scene_node_send_frame_done(struct wlr_scene_node *node, @@ -1823,7 +2412,7 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, wlr_scene_buffer_send_frame_done(scene_buffer, now); } } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { scene_node_send_frame_done(child, scene_output, now); @@ -1858,7 +2447,7 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, user_iterator(scene_buffer, lx, ly, user_data); } } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { scene_output_for_each_scene_buffer(output_box, child, lx, ly, -- cgit v1.2.3 From b6a990da71b5b0947650a50dcf1a083acfce868c Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 30 Dec 2023 12:45:04 +0100 Subject: Added fx_texture and fx_framebuffer --- types/scene/wlr_scene.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'types/scene/wlr_scene.c') diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index fab40a5..45b1a18 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1559,7 +1559,7 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, // Init FX Renderer struct wlr_egl *egl = wlr_gles2_renderer_get_egl(output->renderer); - fx_renderer_init_addon(egl, &output->addons, scene); + fx_renderer_init_addon(egl, output, &output->addons, scene); wlr_damage_ring_init(&scene_output->damage_ring); wl_list_init(&scene_output->damage_highlight_regions); @@ -2050,6 +2050,9 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry, // } // } // +// fx_renderer_scissor(NULL); +// fx_renderer_end(renderer); +// // // Draw the software cursors // wlr_renderer_begin(output->renderer, output->width, output->height); // wlr_output_render_software_cursors(output, &damage); -- cgit v1.2.3 From 51c7078b9ec413ebd8316501f01ccf769a090f64 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 31 Dec 2023 00:32:39 +0100 Subject: Converted fx_renderer to impl wlr_renderer Makes the fx_renderer the default renderer for everything, no wlr_gles2 rendering. This includes wlr_render_pass (fx_render_pass in our case) --- types/scene/wlr_scene.c | 511 ++++-------------------------------------------- 1 file changed, 39 insertions(+), 472 deletions(-) (limited to 'types/scene/wlr_scene.c') diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 45b1a18..343a901 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -15,7 +15,7 @@ #include #include -#include "render/fx_renderer/fx_renderer.h" +#include "render/pass.h" #include "types/fx/shadow_data.h" #include "types/wlr_buffer.h" #include "types/wlr_output.h" @@ -306,7 +306,7 @@ struct render_data { struct wlr_scene_output *output; - struct wlr_render_pass *render_pass; + struct fx_gles_render_pass *render_pass; pixman_region32_t damage; }; @@ -1148,211 +1148,6 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, return NULL; } -// static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { -// struct wlr_box box = { -// .x = rect->x1, -// .y = rect->y1, -// .width = rect->x2 - rect->x1, -// .height = rect->y2 - rect->y1, -// }; -// -// int ow, oh; -// wlr_output_transformed_resolution(output, &ow, &oh); -// -// enum wl_output_transform transform = -// wlr_output_transform_invert(output->transform); -// wlr_box_transform(&box, &box, transform, ow, oh); -// -// fx_renderer_scissor(&box); -// } -// -// static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *output, -// pixman_region32_t *damage, const float color[static 4], -// const struct wlr_box *box, const float matrix[static 9]) { -// assert(fx_renderer); -// -// int nrects; -// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); -// for (int i = 0; i < nrects; ++i) { -// scissor_output(output, &rects[i]); -// fx_render_rect(fx_renderer, box, color, matrix); -// } -// } -// -// static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *output, -// pixman_region32_t *damage, struct wlr_texture *texture, -// const struct wlr_fbox *src_box, const struct wlr_box *dst_box, -// const float matrix[static 9], float opacity, int corner_radius) { -// assert(fx_renderer); -// -// struct wlr_fbox default_src_box = {0}; -// if (wlr_fbox_empty(src_box)) { -// default_src_box.width = texture->width; -// default_src_box.height = texture->height; -// src_box = &default_src_box; -// } -// -// // ensure the box is updated as per the output orientation -// struct wlr_box transformed_box; -// int width, height; -// wlr_output_transformed_resolution(output, &width, &height); -// wlr_box_transform(&transformed_box, dst_box, -// wlr_output_transform_invert(output->transform), width, height); -// -// int nrects; -// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); -// for (int i = 0; i < nrects; ++i) { -// scissor_output(output, &rects[i]); -// -// fx_render_subtexture_with_matrix(fx_renderer, texture, src_box, -// &transformed_box, matrix, opacity, corner_radius); -// } -// } -// -// static void render_box_shadow(struct fx_renderer *fx_renderer, -// struct wlr_output *output, pixman_region32_t *surface_damage, -// const struct wlr_box *surface_box, int corner_radius, -// struct shadow_data *shadow_data) { -// // don't damage area behind window since we dont render it anyway -// pixman_region32_t inner_region; -// pixman_region32_init(&inner_region); -// pixman_region32_union_rect(&inner_region, &inner_region, -// surface_box->x + corner_radius * 0.5, -// surface_box->y + corner_radius * 0.5, -// surface_box->width - corner_radius, -// surface_box->height - corner_radius); -// pixman_region32_intersect(&inner_region, &inner_region, surface_damage); -// -// pixman_region32_t damage; -// pixman_region32_init(&damage); -// pixman_region32_subtract(&damage, surface_damage, &inner_region); -// if (!pixman_region32_not_empty(&damage)) { -// goto damage_finish; -// } -// -// struct wlr_box shadow_box = { -// .x = surface_box->x - shadow_data->blur_sigma, -// .y = surface_box->y - shadow_data->blur_sigma, -// .width = surface_box->width + 2 * shadow_data->blur_sigma, -// .height = surface_box->height + 2 * shadow_data->blur_sigma, -// }; -// float matrix[9]; -// wlr_matrix_project_box(matrix, &shadow_box, WL_OUTPUT_TRANSFORM_NORMAL, 0, -// output->transform_matrix); -// -// // ensure the box is updated as per the output orientation -// struct wlr_box transformed_box; -// int width, height; -// wlr_output_transformed_resolution(output, &width, &height); -// wlr_box_transform(&transformed_box, &shadow_box, -// wlr_output_transform_invert(output->transform), width, height); -// -// int nrects; -// pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); -// for (int i = 0; i < nrects; ++i) { -// scissor_output(output, &rects[i]); -// fx_render_box_shadow(fx_renderer, &transformed_box, surface_box, matrix, -// corner_radius, shadow_data); -// } -// -// damage_finish: -// pixman_region32_fini(&damage); -// pixman_region32_fini(&inner_region); -// } -// -// static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_node *node, -// struct wlr_scene_output *scene_output, pixman_region32_t *damage) { -// int x, y; -// wlr_scene_node_coords(node, &x, &y); -// x -= scene_output->x; -// y -= scene_output->y; -// -// struct wlr_output *output = scene_output->output; -// -// pixman_region32_t render_region; -// pixman_region32_init(&render_region); -// pixman_region32_copy(&render_region, &node->visible); -// pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); -// scale_output_damage(&render_region, output->scale); -// pixman_region32_intersect(&render_region, &render_region, damage); -// if (!pixman_region32_not_empty(&render_region)) { -// pixman_region32_fini(&render_region); -// return; -// } -// -// struct wlr_box dst_box = { -// .x = x, -// .y = y, -// }; -// scene_node_get_size(node, &dst_box.width, &dst_box.height); -// scale_box(&dst_box, output->scale); -// -// struct wlr_texture *texture; -// float matrix[9]; -// enum wl_output_transform transform; -// switch (node->type) { -// case WLR_SCENE_NODE_TREE: -// assert(false); -// break; -// case WLR_SCENE_NODE_RECT:; -// struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); -// -// render_rect(fx_renderer, output, &render_region, scene_rect->color, &dst_box, -// output->transform_matrix); -// break; -// case WLR_SCENE_NODE_BUFFER:; -// struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); -// assert(scene_buffer->buffer); -// -// struct wlr_renderer *renderer = output->renderer; -// texture = scene_buffer_get_texture(scene_buffer, renderer); -// -// transform = wlr_output_transform_invert(scene_buffer->transform); -// wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, -// output->transform_matrix); -// -// // Some surfaces (mostly GTK 4) decorate their windows with shadows -// // which extends the node size past the actual window size. This gets -// // the actual surface geometry, mostly ignoring CSD decorations -// // but only if we need to. -// if (scene_buffer->corner_radius != 0 || -// scene_buffer_has_shadow(&scene_buffer->shadow_data)) { -// struct wlr_scene_surface *scene_surface = NULL; -// if ((scene_surface = wlr_scene_surface_from_buffer(scene_buffer)) && -// wlr_surface_is_xdg_surface(scene_surface->surface)) { -// struct wlr_xdg_surface *xdg_surface = -// wlr_xdg_surface_from_wlr_surface(scene_surface->surface); -// -// struct wlr_box geometry; -// wlr_xdg_surface_get_geometry(xdg_surface, &geometry); -// dst_box.width = fmin(dst_box.width, geometry.width); -// dst_box.height = fmin(dst_box.height, geometry.height); -// dst_box.x = fmax(dst_box.x, geometry.x + x); -// dst_box.y = fmax(dst_box.y, geometry.y + y); -// } -// } -// -// // Shadow -// if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { -// // TODO: Compensate for SSD borders here -// render_box_shadow(fx_renderer, output, &render_region, &dst_box, -// scene_buffer->corner_radius, &scene_buffer->shadow_data); -// } -// -// // Clip the damage to the dst_box before rendering the texture -// pixman_region32_intersect_rect(&render_region, &render_region, -// dst_box.x, dst_box.y, dst_box.width, dst_box.height); -// -// render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box, -// &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius); -// -// wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); -// break; -// } -// -// pixman_region32_fini(&render_region); -// } - struct render_list_entry { struct wlr_scene_node *node; bool sent_dmabuf_feedback; @@ -1396,16 +1191,19 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node); - wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){ - .box = dst_box, - .color = { - .r = scene_rect->color[0], - .g = scene_rect->color[1], - .b = scene_rect->color[2], - .a = scene_rect->color[3], + struct fx_render_rect_options rect_options = { + .base = { + .box = dst_box, + .color = { + .r = scene_rect->color[0], + .g = scene_rect->color[1], + .b = scene_rect->color[2], + .a = scene_rect->color[3], + }, + .clip = &render_region, }, - .clip = &render_region, - }); + }; + fx_render_pass_add_rect(data->render_pass, &rect_options); break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); @@ -1421,17 +1219,21 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); - wlr_render_pass_add_texture(data->render_pass, &(struct wlr_render_texture_options) { - .texture = texture, - .src_box = scene_buffer->src_box, - .dst_box = dst_box, - .transform = transform, - .clip = &render_region, - .alpha = &scene_buffer->opacity, - .filter_mode = scene_buffer->filter_mode, - .blend_mode = pixman_region32_not_empty(&opaque) ? - WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE, - }); + struct fx_render_texture_options tex_options = { + .base = (struct wlr_render_texture_options){ + .texture = texture, + .src_box = scene_buffer->src_box, + .dst_box = dst_box, + .transform = transform, + .clip = &render_region, + .alpha = &scene_buffer->opacity, + .filter_mode = scene_buffer->filter_mode, + .blend_mode = pixman_region32_not_empty(&opaque) ? + WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE, + }, + .corner_radius = scene_buffer->corner_radius, + }; + fx_render_pass_add_texture(data->render_pass, &tex_options); struct wlr_scene_output_sample_event sample_event = { .output = data->output, @@ -1557,10 +1359,6 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); - // Init FX Renderer - struct wlr_egl *egl = wlr_gles2_renderer_get_egl(output->renderer); - fx_renderer_init_addon(egl, output, &output->addons, scene); - wlr_damage_ring_init(&scene_output->damage_ring); wl_list_init(&scene_output->damage_highlight_regions); @@ -1618,10 +1416,6 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { highlight_region_destroy(damage); } - struct fx_renderer *fx_renderer = - fx_renderer_addon_find(&scene_output->output->addons, scene_output->scene); - wlr_addon_finish(&fx_renderer->addon); - wlr_addon_finish(&scene_output->addon); wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); @@ -1859,235 +1653,6 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry, return true; } -// bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { -// struct wlr_output *output = scene_output->output; -// enum wlr_scene_debug_damage_option debug_damage = -// scene_output->scene->debug_damage_option; -// -// // Find the fx_renderer addon -// struct fx_renderer *renderer = -// fx_renderer_addon_find(&output->addons, scene_output->scene); -// assert(renderer != NULL); -// -// struct render_list_constructor_data list_con = { -// .box = { .x = scene_output->x, .y = scene_output->y }, -// .render_list = &scene_output->render_list, -// .calculate_visibility = scene_output->scene->calculate_visibility, -// }; -// wlr_output_effective_resolution(output, -// &list_con.box.width, &list_con.box.height); -// -// list_con.render_list->size = 0; -// scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, -// construct_render_list_iterator, &list_con); -// array_realloc(list_con.render_list, list_con.render_list->size); -// -// int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *); -// struct wlr_scene_node **list_data = list_con.render_list->data; -// -// // if there is only one thing to render let's see if that thing can be -// // directly scanned out -// bool scanout = false; -// if (list_len == 1) { -// struct wlr_scene_node *node = list_data[0]; -// scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); -// } -// -// if (scene_output->prev_scanout != scanout) { -// scene_output->prev_scanout = scanout; -// wlr_log(WLR_DEBUG, "Direct scan-out %s", -// scanout ? "enabled" : "disabled"); -// // When exiting direct scan-out, damage everything -// wlr_damage_ring_add_whole(&scene_output->damage_ring); -// } -// -// if (scanout) { -// struct wlr_scene_node *node = list_data[0]; -// -// assert(node->type == WLR_SCENE_NODE_BUFFER); -// struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); -// wl_signal_emit_mutable(&buffer->events.output_present, scene_output); -// return true; -// } -// -// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { -// wlr_damage_ring_add_whole(&scene_output->damage_ring); -// } -// -// struct timespec now; -// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { -// struct wl_list *regions = &scene_output->damage_highlight_regions; -// clock_gettime(CLOCK_MONOTONIC, &now); -// -// // add the current frame's damage if there is damage -// if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { -// struct highlight_region *current_damage = -// calloc(1, sizeof(*current_damage)); -// if (current_damage) { -// pixman_region32_init(¤t_damage->region); -// pixman_region32_copy(¤t_damage->region, -// &scene_output->damage_ring.current); -// current_damage->when = now; -// wl_list_insert(regions, ¤t_damage->link); -// } -// } -// -// pixman_region32_t acc_damage; -// pixman_region32_init(&acc_damage); -// struct highlight_region *damage, *tmp_damage; -// wl_list_for_each_safe(damage, tmp_damage, regions, link) { -// // remove overlaping damage regions -// pixman_region32_subtract(&damage->region, &damage->region, &acc_damage); -// pixman_region32_union(&acc_damage, &acc_damage, &damage->region); -// -// // if this damage is too old or has nothing in it, get rid of it -// struct timespec time_diff; -// timespec_sub(&time_diff, &now, &damage->when); -// if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME || -// !pixman_region32_not_empty(&damage->region)) { -// highlight_region_destroy(damage); -// } -// } -// -// wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage); -// pixman_region32_fini(&acc_damage); -// } -// -// int buffer_age; -// if (!wlr_output_attach_render(output, &buffer_age)) { -// return false; -// } -// -// pixman_region32_t damage; -// pixman_region32_init(&damage); -// wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, -// buffer_age, &damage); -// if (!output->needs_frame && !pixman_region32_not_empty( -// &scene_output->damage_ring.current)) { -// pixman_region32_fini(&damage); -// wlr_output_rollback(output); -// return true; -// } -// -// fx_renderer_begin(renderer, output->width, output->height); -// -// pixman_region32_t background; -// pixman_region32_init(&background); -// pixman_region32_copy(&background, &damage); -// -// // Cull areas of the background that are occluded by opaque regions of -// // scene nodes above. Those scene nodes will just render atop having us -// // never see the background. -// if (scene_output->scene->calculate_visibility) { -// float output_scale = scene_output->output->scale; -// -// for (int i = list_len - 1; i >= 0; i--) { -// struct wlr_scene_node *node = list_data[i]; -// int x, y; -// wlr_scene_node_coords(node, &x, &y); -// -// // We must only cull opaque regions that are visible by the node. -// // The node's visibility will have the knowledge of a black rect -// // that may have been omitted from the render list via the black -// // rect optimization. In order to ensure we don't cull background -// // rendering in that black rect region, consider the node's visibility. -// pixman_region32_t opaque; -// pixman_region32_init(&opaque); -// scene_node_opaque_region(node, x, y, &opaque); -// pixman_region32_intersect(&opaque, &opaque, &node->visible); -// -// pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y); -// wlr_region_scale(&opaque, &opaque, output_scale); -// pixman_region32_subtract(&background, &background, &opaque); -// pixman_region32_fini(&opaque); -// } -// -// if (floor(output_scale) != output_scale) { -// wlr_region_expand(&background, &background, 1); -// -// // reintersect with the damage because we never want to render -// // outside of the damage region -// pixman_region32_intersect(&background, &background, &damage); -// } -// } -// -// int nrects; -// pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects); -// for (int i = 0; i < nrects; ++i) { -// scissor_output(output, &rects[i]); -// fx_renderer_clear((float[4]){ 0.0, 0.0, 0.0, 1.0 }); -// } -// pixman_region32_fini(&background); -// -// for (int i = list_len - 1; i >= 0; i--) { -// struct wlr_scene_node *node = list_data[i]; -// scene_node_render(renderer, node, scene_output, &damage); -// } -// -// fx_renderer_scissor(NULL); -// -// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { -// struct highlight_region *damage; -// wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { -// struct timespec time_diff; -// timespec_sub(&time_diff, &now, &damage->when); -// int64_t time_diff_ms = timespec_to_msec(&time_diff); -// float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; -// -// int nrects; -// pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects); -// for (int i = 0; i < nrects; ++i) { -// struct wlr_box box = { -// .x = rects[i].x1, -// .y = rects[i].y1, -// .width = rects[i].x2 - rects[i].x1, -// .height = rects[i].y2 - rects[i].y1, -// }; -// -// float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 }; -// fx_render_rect(renderer, &box, color, output->transform_matrix); -// } -// } -// } -// -// fx_renderer_scissor(NULL); -// fx_renderer_end(renderer); -// -// // Draw the software cursors -// wlr_renderer_begin(output->renderer, output->width, output->height); -// wlr_output_render_software_cursors(output, &damage); -// wlr_renderer_end(output->renderer); -// -// pixman_region32_fini(&damage); -// -// int tr_width, tr_height; -// wlr_output_transformed_resolution(output, &tr_width, &tr_height); -// -// enum wl_output_transform transform = -// wlr_output_transform_invert(output->transform); -// -// pixman_region32_t frame_damage; -// pixman_region32_init(&frame_damage); -// wlr_region_transform(&frame_damage, -// &scene_output->damage_ring.current, -// transform, tr_width, tr_height); -// wlr_output_set_damage(output, &frame_damage); -// pixman_region32_fini(&frame_damage); -// -// bool success = wlr_output_commit(output); -// -// if (success) { -// wlr_damage_ring_rotate(&scene_output->damage_ring); -// } -// -// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && -// !wl_list_empty(&scene_output->damage_highlight_regions)) { -// wlr_output_schedule_frame(scene_output->output); -// } -// -// return success; -// } - bool wlr_scene_output_commit(struct wlr_scene_output *scene_output, const struct wlr_scene_output_state_options *options) { if (!scene_output->output->needs_frame && !pixman_region32_not_empty( @@ -2273,10 +1838,12 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, timer->pre_render_duration = timespec_to_nsec(&duration); } - struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer, - &(struct wlr_buffer_pass_options){ - .timer = timer ? timer->render_timer : NULL, - }); + struct fx_gles_render_pass *render_pass = + fx_renderer_begin_buffer_pass(output->renderer, buffer, + &(struct wlr_buffer_pass_options){ + .timer = timer ? timer->render_timer : NULL, + } + ); if (render_pass == NULL) { wlr_buffer_unlock(buffer); return false; @@ -2324,7 +1891,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, } transform_output_damage(&background, &render_data); - wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){ + wlr_render_pass_add_rect(&render_pass->base, &(struct wlr_render_rect_options){ .box = { .width = buffer->width, .height = buffer->height }, .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, .clip = &background, @@ -2357,7 +1924,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, int64_t time_diff_ms = timespec_to_msec(&time_diff); float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; - wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){ + wlr_render_pass_add_rect(&render_pass->base, &(struct wlr_render_rect_options){ .box = { .width = buffer->width, .height = buffer->height }, .color = { .r = alpha * 0.5, .g = 0, .b = 0, .a = alpha * 0.5 }, .clip = &damage->region, @@ -2365,11 +1932,11 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, } } - wlr_output_add_software_cursors_to_render_pass(output, render_pass, &render_data.damage); + wlr_output_add_software_cursors_to_render_pass(output, &render_pass->base, &render_data.damage); pixman_region32_fini(&render_data.damage); - if (!wlr_render_pass_submit(render_pass)) { + if (!wlr_render_pass_submit(&render_pass->base)) { wlr_buffer_unlock(buffer); return false; } -- cgit v1.2.3 From c15af4a182314d8384fc6b28e7c3fc58c0352b83 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:19:48 +0100 Subject: Added back shadow effect --- types/scene/wlr_scene.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) (limited to 'types/scene/wlr_scene.c') diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 343a901..d822392 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -471,9 +471,10 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, // Expand the nodes visible region by the shadow size if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - struct shadow_data *data = &buffer->shadow_data; - if (scene_buffer_has_shadow(data)) { - wlr_region_expand(&node->visible, &node->visible, data->blur_sigma); + struct shadow_data *shadow_data = &buffer->shadow_data; + if (scene_buffer_has_shadow(shadow_data)) { + wlr_region_expand(&node->visible, &node->visible, shadow_data->blur_sigma); + wlr_region_expand(data->visible, data->visible, shadow_data->blur_sigma); } } @@ -876,7 +877,10 @@ void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, struct shadow_data *buff_data = &scene_buffer->shadow_data; if (buff_data->enabled == shadow_data.enabled && buff_data->blur_sigma == shadow_data.blur_sigma && - buff_data->color && shadow_data.color) { + buff_data->color.r && shadow_data.color.r && + buff_data->color.g && shadow_data.color.g && + buff_data->color.b && shadow_data.color.b && + buff_data->color.a && shadow_data.color.a) { return; } @@ -1148,6 +1152,38 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, return NULL; } +// Some surfaces (mostly GTK 4) decorate their windows with shadows +// which extends the node size past the actual window size. This gets +// the actual surface geometry, mostly ignoring CSD decorations +// but only if we need to. +static void clip_xdg(struct wlr_scene_buffer *scene_buffer, + pixman_region32_t *clip, struct wlr_box *dst_box, + int x, int y, int scale) { + if (scene_buffer->corner_radius == 0 && + !scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + return; + } + + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_try_from_buffer(scene_buffer); + struct wlr_xdg_surface *xdg_surface = NULL; + if (scene_surface && + (xdg_surface = + wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface))) { + struct wlr_box geometry; + wlr_xdg_surface_get_geometry(xdg_surface, &geometry); + dst_box->width = fmin(dst_box->width, geometry.width); + dst_box->height = fmin(dst_box->height, geometry.height); + dst_box->x = fmax(dst_box->x, geometry.x + x); + dst_box->y = fmax(dst_box->y, geometry.y + y); + scale_box(&geometry, scale); + + pixman_region32_intersect_rect(clip, clip, + geometry.x + x, geometry.y + y, + geometry.width, geometry.height); + } +} + struct render_list_entry { struct wlr_scene_node *node; bool sent_dmabuf_feedback; @@ -1219,6 +1255,29 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); + struct wlr_box xdg_box = dst_box; + // Tries to clip + clip_xdg(scene_buffer, &render_region, &xdg_box, + entry->x, entry->y, data->scale); + // Shadow + if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + // TODO: Compensate for SSD borders here + pixman_region32_t shadow_clip; + pixman_region32_init(&shadow_clip); + // Extend the size of the clip box + wlr_region_expand(&shadow_clip, &render_region, + scene_buffer->shadow_data.blur_sigma); + struct fx_render_rect_options shadow_options = { + .base = { + .box = xdg_box, + .clip = &shadow_clip, + }, + }; + fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, + scene_buffer->corner_radius, &scene_buffer->shadow_data); + pixman_region32_fini(&shadow_clip); + } + struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1231,6 +1290,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .blend_mode = pixman_region32_not_empty(&opaque) ? WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE, }, + .clip_box = &xdg_box, .corner_radius = scene_buffer->corner_radius, }; fx_render_pass_add_texture(data->render_pass, &tex_options); -- cgit v1.2.3 From b392638c8a8d142376fa0f44b3cc0f3a6ebd93f3 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:50:21 +0100 Subject: Fixed scaling issues --- types/scene/wlr_scene.c | 59 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'types/scene/wlr_scene.c') diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index d822392..8ded6a8 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1156,31 +1156,43 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, // which extends the node size past the actual window size. This gets // the actual surface geometry, mostly ignoring CSD decorations // but only if we need to. -static void clip_xdg(struct wlr_scene_buffer *scene_buffer, +static void clip_xdg(struct wlr_scene_node *node, pixman_region32_t *clip, struct wlr_box *dst_box, - int x, int y, int scale) { - if (scene_buffer->corner_radius == 0 && - !scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + int x, int y, float scale) { + struct wlr_scene_buffer *scene_buffer = NULL; + switch (node->type) { + default: + return; + case WLR_SCENE_NODE_BUFFER: + scene_buffer = wlr_scene_buffer_from_node(node); + break; + } + + if (!scene_buffer || (scene_buffer->corner_radius == 0 && + !scene_buffer_has_shadow(&scene_buffer->shadow_data))) { return; } - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_try_from_buffer(scene_buffer); + struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); struct wlr_xdg_surface *xdg_surface = NULL; if (scene_surface && - (xdg_surface = - wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface))) { + (xdg_surface = wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface))) { struct wlr_box geometry; wlr_xdg_surface_get_geometry(xdg_surface, &geometry); - dst_box->width = fmin(dst_box->width, geometry.width); - dst_box->height = fmin(dst_box->height, geometry.height); - dst_box->x = fmax(dst_box->x, geometry.x + x); - dst_box->y = fmax(dst_box->y, geometry.y + y); scale_box(&geometry, scale); + if (dst_box->width > geometry.width) { + dst_box->width = geometry.width; + dst_box->x = geometry.x + x; + } + if (dst_box->height > geometry.height) { + dst_box->height = geometry.height; + dst_box->y = geometry.y + y; + } + pixman_region32_intersect_rect(clip, clip, - geometry.x + x, geometry.y + y, - geometry.width, geometry.height); + dst_box->x, dst_box->y, + dst_box->width, dst_box->height); } } @@ -1217,7 +1229,12 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren scale_output_damage(&opaque, data->scale); pixman_region32_subtract(&opaque, &render_region, &opaque); + struct wlr_box xdg_box = dst_box; + // Tries to clip + clip_xdg(node, &render_region, &xdg_box, dst_box.x, dst_box.y, data->scale); + transform_output_box(&dst_box, data); + transform_output_box(&xdg_box, data); transform_output_damage(&render_region, data); switch (node->type) { @@ -1238,6 +1255,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren }, .clip = &render_region, }, + .scale = data->scale, }; fx_render_pass_add_rect(data->render_pass, &rect_options); break; @@ -1255,10 +1273,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); - struct wlr_box xdg_box = dst_box; - // Tries to clip - clip_xdg(scene_buffer, &render_region, &xdg_box, - entry->x, entry->y, data->scale); // Shadow if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { // TODO: Compensate for SSD borders here @@ -1266,15 +1280,17 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren pixman_region32_init(&shadow_clip); // Extend the size of the clip box wlr_region_expand(&shadow_clip, &render_region, - scene_buffer->shadow_data.blur_sigma); + scene_buffer->shadow_data.blur_sigma * data->scale); struct fx_render_rect_options shadow_options = { .base = { .box = xdg_box, .clip = &shadow_clip, }, + .scale = data->scale, }; fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, - scene_buffer->corner_radius, &scene_buffer->shadow_data); + scene_buffer->corner_radius * data->scale, + &scene_buffer->shadow_data); pixman_region32_fini(&shadow_clip); } @@ -1290,8 +1306,9 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .blend_mode = pixman_region32_not_empty(&opaque) ? WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE, }, + .scale = data->scale, .clip_box = &xdg_box, - .corner_radius = scene_buffer->corner_radius, + .corner_radius = scene_buffer->corner_radius * data->scale, }; fx_render_pass_add_texture(data->render_pass, &tex_options); -- cgit v1.2.3