diff options
-rw-r--r-- | include/render/fx_renderer/fx_renderer.h | 6 | ||||
-rw-r--r-- | include/wlr/types/wlr_scene.h | 490 | ||||
-rw-r--r-- | render/fx_renderer/fx_renderer.c | 14 | ||||
-rw-r--r-- | tinywl/tinywl.c | 102 | ||||
-rw-r--r-- | types/scene/wlr_scene.c | 34 |
5 files changed, 624 insertions, 22 deletions
diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 085cd1c..2067c04 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -71,8 +71,10 @@ void fx_renderer_clear(const float color[static 4]); void fx_renderer_scissor(struct wlr_box *box); -bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]); +bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, + struct wlr_texture *wlr_texture, const struct wlr_fbox *src_box, + const struct wlr_box *dst_box, const float matrix[static 9], + float opacity, int corner_radius); void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, const float color[static 4], const float projection[static 9]); diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h new file mode 100644 index 0000000..138e0e2 --- /dev/null +++ b/include/wlr/types/wlr_scene.h @@ -0,0 +1,490 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_SCENE_H +#define WLR_TYPES_WLR_SCENE_H + +/** + * The scene-graph API provides a declarative way to display surfaces. The + * compositor creates a scene, adds surfaces, then renders the scene on + * outputs. + * + * The scene-graph API only supports basic 2D composition operations (like the + * KMS API or the Wayland protocol does). For anything more complicated, + * compositors need to implement custom rendering logic. + */ + +#include <pixman.h> +#include <wayland-server-core.h> +#include <wlr/types/wlr_compositor.h> +#include <wlr/types/wlr_damage_ring.h> + +struct wlr_output; +struct wlr_output_layout; +struct wlr_xdg_surface; +struct wlr_layer_surface_v1; + +struct wlr_scene_node; +struct wlr_scene_buffer; + +typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)( + struct wlr_scene_buffer *buffer, int sx, int sy); + +typedef void (*wlr_scene_buffer_iterator_func_t)( + struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data); + +enum wlr_scene_node_type { + WLR_SCENE_NODE_TREE, + WLR_SCENE_NODE_RECT, + WLR_SCENE_NODE_BUFFER, +}; + +/** A node is an object in the scene. */ +struct wlr_scene_node { + enum wlr_scene_node_type type; + struct wlr_scene_tree *parent; + + struct wl_list link; // wlr_scene_tree.children + + bool enabled; + int x, y; // relative to parent + + struct { + struct wl_signal destroy; + } events; + + void *data; + + struct wlr_addon_set addons; + + // private state + + pixman_region32_t visible; +}; + +enum wlr_scene_debug_damage_option { + WLR_SCENE_DEBUG_DAMAGE_NONE, + WLR_SCENE_DEBUG_DAMAGE_RERENDER, + WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT +}; + +/** A sub-tree in the scene-graph. */ +struct wlr_scene_tree { + struct wlr_scene_node node; + + struct wl_list children; // wlr_scene_node.link +}; + +/** The root scene-graph node. */ +struct wlr_scene { + struct wlr_scene_tree tree; + + struct wl_list outputs; // wlr_scene_output.link + + // May be NULL + struct wlr_presentation *presentation; + + // private state + + struct wl_listener presentation_destroy; + + enum wlr_scene_debug_damage_option debug_damage_option; + bool direct_scanout; + bool calculate_visibility; +}; + +/** A scene-graph node displaying a single surface. */ +struct wlr_scene_surface { + struct wlr_scene_buffer *buffer; + struct wlr_surface *surface; + + // private state + + struct wlr_addon addon; + + struct wl_listener output_enter; + struct wl_listener output_leave; + struct wl_listener output_present; + struct wl_listener frame_done; + struct wl_listener surface_destroy; + struct wl_listener surface_commit; +}; + +/** A scene-graph node displaying a solid-colored rectangle */ +struct wlr_scene_rect { + struct wlr_scene_node node; + int width, height; + float color[4]; +}; + +/** A scene-graph node displaying a buffer */ +struct wlr_scene_buffer { + struct wlr_scene_node node; + + // May be NULL + struct wlr_buffer *buffer; + + struct { + struct wl_signal output_enter; // struct wlr_scene_output + struct wl_signal output_leave; // struct wlr_scene_output + struct wl_signal output_present; // struct wlr_scene_output + struct wl_signal frame_done; // struct timespec + } events; + + // May be NULL + wlr_scene_buffer_point_accepts_input_func_t point_accepts_input; + + /** + * The output that the largest area of this buffer is displayed on. + * This may be NULL if the buffer is not currently displayed on any + * outputs. This is the output that should be used for frame callbacks, + * presentation feedback, etc. + */ + struct wlr_scene_output *primary_output; + + // private state + + float opacity; + int corner_radius; + + uint64_t active_outputs; + struct wlr_texture *texture; + struct wlr_fbox src_box; + int dst_width, dst_height; + enum wl_output_transform transform; + pixman_region32_t opaque_region; +}; + +/** A viewport for an output in the scene-graph */ +struct wlr_scene_output { + struct wlr_output *output; + struct wl_list link; // wlr_scene.outputs + struct wlr_scene *scene; + struct wlr_addon addon; + + struct wlr_damage_ring damage_ring; + + int x, y; + + struct { + struct wl_signal destroy; + } events; + + // private state + + uint8_t index; + bool prev_scanout; + + struct wl_listener output_commit; + struct wl_listener output_mode; + struct wl_listener output_damage; + struct wl_listener output_needs_frame; + + struct wl_list damage_highlight_regions; + + struct wl_array render_list; +}; + +/** A layer shell scene helper */ +struct wlr_scene_layer_surface_v1 { + struct wlr_scene_tree *tree; + struct wlr_layer_surface_v1 *layer_surface; + + // private state + + struct wl_listener tree_destroy; + struct wl_listener layer_surface_destroy; + struct wl_listener layer_surface_map; + struct wl_listener layer_surface_unmap; +}; + +/** + * Immediately destroy the scene-graph node. + */ +void wlr_scene_node_destroy(struct wlr_scene_node *node); +/** + * Enable or disable this node. If a node is disabled, all of its children are + * implicitly disabled as well. + */ +void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled); +/** + * Set the position of the node relative to its parent. + */ +void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y); +/** + * Move the node right above the specified sibling. + * Asserts that node and sibling are distinct and share the same parent. + */ +void wlr_scene_node_place_above(struct wlr_scene_node *node, + struct wlr_scene_node *sibling); +/** + * Move the node right below the specified sibling. + * Asserts that node and sibling are distinct and share the same parent. + */ +void wlr_scene_node_place_below(struct wlr_scene_node *node, + struct wlr_scene_node *sibling); +/** + * Move the node above all of its sibling nodes. + */ +void wlr_scene_node_raise_to_top(struct wlr_scene_node *node); +/** + * Move the node below all of its sibling nodes. + */ +void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node); +/** + * Move the node to another location in the tree. + */ +void wlr_scene_node_reparent(struct wlr_scene_node *node, + struct wlr_scene_tree *new_parent); +/** + * Get the node's layout-local coordinates. + * + * True is returned if the node and all of its ancestors are enabled. + */ +bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx, int *ly); +/** + * Call `iterator` on each buffer in the scene-graph, with the buffer's + * position in layout coordinates. The function is called from root to leaves + * (in rendering order). + */ +void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node, + wlr_scene_buffer_iterator_func_t iterator, void *user_data); +/** + * Find the topmost node in this scene-graph that contains the point at the + * given layout-local coordinates. (For surface nodes, this means accepting + * input events at that point.) Returns the node and coordinates relative to the + * returned node, or NULL if no node is found at that location. + */ +struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, + double lx, double ly, double *nx, double *ny); + +/** + * Create a new scene-graph. + */ +struct wlr_scene *wlr_scene_create(void); +/** + * Handle presentation feedback for all surfaces in the scene, assuming that + * scene outputs and the scene rendering functions are used. + * + * Asserts that a struct wlr_presentation hasn't already been set for the scene. + */ +void wlr_scene_set_presentation(struct wlr_scene *scene, + struct wlr_presentation *presentation); + +/** + * Add a node displaying nothing but its children. + */ +struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent); + +/** + * Add a node displaying a single surface to the scene-graph. + * + * The child sub-surfaces are ignored. + * + * wlr_surface_send_enter() and wlr_surface_send_leave() will be called + * automatically based on the position of the surface and outputs in + * the scene. + */ +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent, + struct wlr_surface *surface); + +struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node); + +/** + * If this buffer is backed by a surface, then the struct wlr_scene_surface is + * returned. If not, NULL will be returned. + */ +struct wlr_scene_surface *wlr_scene_surface_from_buffer( + struct wlr_scene_buffer *scene_buffer); + +/** + * Add a node displaying a solid-colored rectangle to the scene-graph. + */ +struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, + int width, int height, const float color[static 4]); + +/** + * Change the width and height of an existing rectangle node. + */ +void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height); + +/** + * Change the color of an existing rectangle node. + */ +void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]); + +/** + * Add a node displaying a buffer to the scene-graph. + * + * If the buffer is NULL, this node will not be displayed. + */ +struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, + struct wlr_buffer *buffer); + +/** + * Sets the buffer's backing buffer. + * + * If the buffer is NULL, the buffer node will not be displayed. + */ +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer); + +/** + * Sets the buffer's backing buffer with a custom damage region. + * + * The damage region is in buffer-local coordinates. If the region is NULL, + * the whole buffer node will be damaged. + */ +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer, pixman_region32_t *region); + +/** + * Sets the buffer's opaque region. This is an optimization hint used to + * determine if buffers which reside under this one need to be rendered or not. + */ +void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer, + pixman_region32_t *region); + +/** + * Set the source rectangle describing the region of the buffer which will be + * sampled to render this node. This allows cropping the buffer. + * + * If NULL, the whole buffer is sampled. By default, the source box is NULL. + */ +void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, + const struct wlr_fbox *box); + +/** + * Set the destination size describing the region of the scene-graph the buffer + * will be painted onto. This allows scaling the buffer. + * + * If zero, the destination size will be the buffer size. By default, the + * destination size is zero. + */ +void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, + int width, int height); + +/** + * Set a transform which will be applied to the buffer. + */ +void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, + enum wl_output_transform transform); + +/** +* Sets the opacity of this buffer +*/ +void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer, + float opacity); + +/** +* Sets the corner radius of this buffer +*/ +void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer, + int radii); + +/** + * Calls the buffer's frame_done signal. + */ +void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, + struct timespec *now); + +/** + * Add a viewport for the specified output to the scene-graph. + * + * An output can only be added once to the scene-graph. + */ +struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, + struct wlr_output *output); +/** + * Destroy a scene-graph output. + */ +void wlr_scene_output_destroy(struct wlr_scene_output *scene_output); +/** + * Set the output's position in the scene-graph. + */ +void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, + int lx, int ly); +/** + * Render and commit an output. + */ +bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); +/** + * Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by + * wlr_scene_output_commit() for which wlr_scene_surface.primary_output + * matches the given scene_output. + */ +void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, + struct timespec *now); +/** + * Call `iterator` on each buffer in the scene-graph visible on the output, + * with the buffer's position in layout coordinates. The function is called + * from root to leaves (in rendering order). + */ +void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, + wlr_scene_buffer_iterator_func_t iterator, void *user_data); +/** + * Get a scene-graph output from a struct wlr_output. + * + * If the output hasn't been added to the scene-graph, returns NULL. + */ +struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, + struct wlr_output *output); + +/** + * Attach an output layout to a scene. + * + * Adding, removing, or repositioning an output in the output layout + * will respectively add, remove or reposition a corresponding + * scene-graph output. When the output layout is destroyed, scene-graph + * outputs which were created by this helper will be destroyed. + */ +bool wlr_scene_attach_output_layout(struct wlr_scene *scene, + struct wlr_output_layout *output_layout); + +/** + * Add a node displaying a surface and all of its sub-surfaces to the + * scene-graph. + */ +struct wlr_scene_tree *wlr_scene_subsurface_tree_create( + struct wlr_scene_tree *parent, struct wlr_surface *surface); + +/** + * Add a node displaying an xdg_surface and all of its sub-surfaces to the + * scene-graph. + * + * The origin of the returned scene-graph node will match the top-left corner + * of the xdg_surface window geometry. + */ +struct wlr_scene_tree *wlr_scene_xdg_surface_create( + struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface); + +/** + * Add a node displaying a layer_surface_v1 and all of its sub-surfaces to the + * scene-graph. + * + * The origin of the returned scene-graph node will match the top-left corner + * of the layer surface. + */ +struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( + struct wlr_scene_tree *parent, struct wlr_layer_surface_v1 *layer_surface); + +/** + * Configure a layer_surface_v1, position its scene node in accordance to its + * current state, and update the remaining usable area. + * + * full_area represents the entire area that may be used by the layer surface + * if its exclusive_zone is -1, and is usually the output dimensions. + * usable_area represents what remains of full_area that can be used if + * exclusive_zone is >= 0. usable_area is updated if the surface has a positive + * exclusive_zone, so that it can be used for the next layer surface. + */ +void wlr_scene_layer_surface_v1_configure( + struct wlr_scene_layer_surface_v1 *scene_layer_surface, + const struct wlr_box *full_area, struct wlr_box *usable_area); + +#endif diff --git a/render/fx_renderer/fx_renderer.c b/render/fx_renderer/fx_renderer.c index c30108a..014be33 100644 --- a/render/fx_renderer/fx_renderer.c +++ b/render/fx_renderer/fx_renderer.c @@ -282,8 +282,10 @@ void fx_renderer_scissor(struct wlr_box *box) { } } -bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]) { +bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, + struct wlr_texture *wlr_texture, const struct wlr_fbox *src_box, + const struct wlr_box *dst_box, const float matrix[static 9], + float opacity, int corner_radius) { assert(wlr_texture_is_gles2(wlr_texture)); struct wlr_gles2_texture_attribs texture_attrs; @@ -320,12 +322,8 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t // to GL_FALSE wlr_matrix_transpose(gl_matrix, gl_matrix); - // TODO: accept me as params! - float alpha = 1.0; - int corner_radius = 0; - // if there's no opacity or rounded corners we don't need to blend - if (!texture_attrs.has_alpha && alpha == 1.0 && !corner_radius) { + if (!texture_attrs.has_alpha && opacity == 1.0 && !corner_radius) { glDisable(GL_BLEND); } else { glEnable(GL_BLEND); @@ -344,7 +342,7 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t glUniform1i(shader->tex, 0); glUniform2f(shader->size, dst_box->width, dst_box->height); glUniform2f(shader->position, dst_box->x, dst_box->y); - glUniform1f(shader->alpha, alpha); + glUniform1f(shader->alpha, opacity); glUniform1f(shader->radius, corner_radius); const GLfloat x1 = src_box->x / wlr_texture->width; diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 80eb6bd..d4f4e7f 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -7,6 +7,7 @@ #include <time.h> #include <unistd.h> #include <wayland-server-core.h> +#include <wayland-util.h> #include <wlr/backend.h> #include <wlr/render/allocator.h> #include <wlr/render/wlr_renderer.h> @@ -90,6 +91,11 @@ struct tinywl_view { struct wl_listener request_maximize; struct wl_listener request_fullscreen; int x, y; + + struct wlr_addon addon; + + float opacity; + int corner_radius; }; struct tinywl_keyboard { @@ -102,6 +108,44 @@ struct tinywl_keyboard { struct wl_listener destroy; }; +static void tinywl_view_destroy(struct tinywl_view *view) { + wl_list_remove(&view->map.link); + wl_list_remove(&view->unmap.link); + wl_list_remove(&view->destroy.link); + wl_list_remove(&view->request_move.link); + wl_list_remove(&view->request_resize.link); + wl_list_remove(&view->request_maximize.link); + wl_list_remove(&view->request_fullscreen.link); + + free(view); +} + +static void tinywl_view_addon_handle_destroy(struct wlr_addon *addon) { + struct tinywl_view *view = wl_container_of(addon, view, addon); + + tinywl_view_destroy(view); +} +static const struct wlr_addon_interface tinywl_view_addon_impl = { + .name = "tinywl_view", + .destroy = tinywl_view_addon_handle_destroy, +}; + +static void tinywl_view_addon_assign(struct tinywl_view *view, struct wlr_addon_set *addons, + const void * owner) { + wlr_addon_init(&view->addon, addons, owner, &tinywl_view_addon_impl); +} + +static struct tinywl_view *tinywl_view_addon_get(struct wlr_addon_set *addons, + const void * owner) { + struct wlr_addon *addon = + wlr_addon_find(addons, owner, &tinywl_view_addon_impl); + if (addon == NULL) { + return NULL; + } + struct tinywl_view *view = wl_container_of(addon, view, addon); + return view; +} + static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { /* Note: this function only deals with keyboard focus. */ if (view == NULL) { @@ -552,6 +596,45 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(server->seat); } +static void output_configure_scene(struct wlr_scene_node *node, + float opacity, int corner_radius) { + if (!node->enabled) { + return; + } + + struct tinywl_view *view = tinywl_view_addon_get(&node->addons, node); + if (view) { + opacity = view->opacity; + corner_radius = view->corner_radius; + } + + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + + struct wlr_scene_surface * scene_surface + = wlr_scene_surface_from_buffer(buffer); + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(scene_surface->surface); + + if (xdg_surface && + xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + // TODO: Be able to set whole decoration_data instead of calling + // each individually? + wlr_scene_buffer_set_opacity(buffer, opacity); + + if (!wlr_surface_is_subsurface(xdg_surface->surface)) { + wlr_scene_buffer_set_corner_radius(buffer, corner_radius); + } + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *tree = wl_container_of(node, tree, node); + struct wlr_scene_node *node; + wl_list_for_each(node, &tree->children, link) { + output_configure_scene(node, opacity, corner_radius); + } + } +} + static void output_frame(struct wl_listener *listener, void *data) { /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ @@ -561,6 +644,8 @@ static void output_frame(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( scene, output->wlr_output); + output_configure_scene(&scene_output->scene->tree.node, 1, 0); + /* Render the scene if needed and commit the output */ wlr_scene_output_commit(scene_output); @@ -655,15 +740,7 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { /* Called when the surface is destroyed and should never be shown again. */ struct tinywl_view *view = wl_container_of(listener, view, destroy); - wl_list_remove(&view->map.link); - wl_list_remove(&view->unmap.link); - wl_list_remove(&view->destroy.link); - wl_list_remove(&view->request_move.link); - wl_list_remove(&view->request_resize.link); - wl_list_remove(&view->request_maximize.link); - wl_list_remove(&view->request_fullscreen.link); - - free(view); + tinywl_view_destroy(view); } static void begin_interactive(struct tinywl_view *view, @@ -779,6 +856,13 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { view->scene_tree->node.data = view; xdg_surface->data = view->scene_tree; + /* Add the view to the trees addon */ + tinywl_view_addon_assign(view, &view->scene_tree->node.addons, &view->scene_tree->node); + + /* Set the scene_nodes decoration data */ + view->opacity = 1; + view->corner_radius = 20; + /* Listen to the various events it can emit */ view->map.notify = xdg_toplevel_map; wl_signal_add(&xdg_surface->events.map, &view->map); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 265f38e..873f606 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -9,6 +9,7 @@ #include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_presentation_time.h> #include <wlr/types/wlr_scene.h> +#include <wlr/types/wlr_subcompositor.h> #include <wlr/util/log.h> #include <wlr/util/region.h> #include "render/fx_renderer/fx_renderer.h" @@ -239,6 +240,10 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, return; } + if (scene_buffer->opacity != 1 || scene_buffer->corner_radius > 0) { + return; + } + if (!buffer_is_opaque(scene_buffer->buffer)) { pixman_region32_copy(opaque, &scene_buffer->opaque_region); pixman_region32_translate(opaque, x, y); @@ -555,6 +560,9 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, 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_node_update(&scene_buffer->node, NULL); return scene_buffer; @@ -745,6 +753,26 @@ void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, } } +void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer, + float opacity) { + if (scene_buffer->opacity == opacity) { + return; + } + + scene_buffer->opacity = opacity; + 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) { + return; + } + + scene_buffer->corner_radius = radii; + scene_node_update(&scene_buffer->node, NULL); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -1042,7 +1070,7 @@ static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *outp 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]) { + const float matrix[static 9], float opacity, int corner_radius) { assert(fx_renderer); struct wlr_fbox default_src_box = {0}; @@ -1065,7 +1093,7 @@ static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *o scissor_output(output, &rects[i]); fx_render_subtexture_with_matrix(fx_renderer, texture, src_box, - &transformed_box, matrix); + &transformed_box, matrix, opacity, corner_radius); } } @@ -1121,7 +1149,7 @@ static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_ output->transform_matrix); render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box, - &dst_box, matrix); + &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius); wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); break; |