clients: Paint desktop-shell color background with single-pixel-buffer

So the buffer has the WESTON_BUFFER_SOLID type, which will make
additional optimizations easier going forward.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
This commit is contained in:
Robert Mader 2025-09-08 13:32:42 +02:00 committed by Daniel Stone
parent 2497377af4
commit 6cc8f48cd8
4 changed files with 169 additions and 72 deletions

View file

@ -53,6 +53,7 @@
#include "window.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "weston-desktop-shell-client-protocol.h"
@ -782,94 +783,139 @@ enum {
BACKGROUND_CENTERED
};
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void
background_draw(struct widget *widget, void *data)
{
struct background *background = data;
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
surface = window_get_surface(background->window);
if (!background->image && background->color) {
struct display *display = window_get_display(background->window);
struct wp_single_pixel_buffer_manager_v1 *sp_manager;
struct wl_surface *wl_surface;
struct wl_buffer *wl_buffer;
uint32_t r8, g8, b8;
uint32_t r32, g32, b32;
cr = widget_cairo_create(background->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
sp_manager = display_get_single_pixel_buffer_manager(display);
assert(sp_manager);
wl_surface = widget_get_wl_surface(background->widget);
assert(wl_surface);
widget_get_allocation(widget, &allocation);
image = NULL;
if (background->image)
image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
r8 = (background->color >> 16) & 0xff;
g8 = (background->color >> 8) & 0xff;
b8 = (background->color >> 0) & 0xff;
image = load_cairo_surface(name);
free(name);
}
r32 = r8 << 24 | r8 << 16 | r8 << 8 | r8;
g32 = g8 << 24 | g8 << 16 | g8 << 8 | g8;
b32 = b8 << 24 | b8 << 16 | b8 << 8 | b8;
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
wl_buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(sp_manager,
r32,
g32,
b32,
0xffffffff);
assert(wl_buffer);
pattern = cairo_pattern_create_for_surface(image);
wl_surface_attach(wl_surface, wl_buffer, 0, 0);
wl_buffer_add_listener(wl_buffer, &buffer_listener, NULL);
widget_surface_flush(widget);
} else {
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
case BACKGROUND_SCALE_FIT:
if (background->type == BACKGROUND_SCALE_CROP)
s = (sx < sy) ? sx : sy;
else
s = (sx > sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
surface = window_get_surface(background->window);
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cr = widget_cairo_create(background->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
widget_get_allocation(widget, &allocation);
image = NULL;
if (background->image)
image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
image = load_cairo_surface(name);
free(name);
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
cairo_destroy(cr);
cairo_surface_destroy(surface);
pattern = cairo_pattern_create_for_surface(image);
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
case BACKGROUND_SCALE_FIT:
if (background->type == BACKGROUND_SCALE_CROP)
s = (sx < sy) ? sx : sy;
else
s = (sx > sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
background->painted = 1;
check_desktop_ready(background->window);
@ -897,6 +943,7 @@ background_configure(void *data,
}
if (!background->image && background->color) {
widget_set_use_cairo(background->widget, 0);
widget_set_viewport_destination(background->widget, width, height);
width = 1;
height = 1;

View file

@ -14,6 +14,8 @@ srcs_toytoolkit = [
relative_pointer_unstable_v1_protocol_c,
pointer_constraints_unstable_v1_client_protocol_h,
pointer_constraints_unstable_v1_protocol_c,
single_pixel_buffer_v1_client_protocol_h,
single_pixel_buffer_v1_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
ivi_application_client_protocol_h,

View file

@ -55,6 +55,7 @@
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h"
#include "color-management-v1-client-protocol.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "text-cursor-position-client-protocol.h"
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
@ -93,6 +94,7 @@ struct display {
struct zwp_tablet_manager_v2 *tablet_manager;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager;
uint32_t serial;
uint32_t color_manager_features;
@ -1447,6 +1449,35 @@ surface_flush(struct surface *surface)
surface->cairo_surface = NULL;
}
void
widget_surface_flush(struct widget *widget)
{
struct surface *surface = widget->surface;
if (surface->opaque_region) {
wl_surface_set_opaque_region(surface->surface,
surface->opaque_region);
wl_region_destroy(surface->opaque_region);
surface->opaque_region = NULL;
}
if (surface->input_region) {
wl_surface_set_input_region(surface->surface,
surface->input_region);
wl_region_destroy(surface->input_region);
surface->input_region = NULL;
}
if (surface->viewport) {
wp_viewport_set_destination(surface->viewport,
widget->viewport_dest_width,
widget->viewport_dest_height);
}
wl_surface_damage(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(surface->surface);
}
int
window_has_focus(struct window *window)
{
@ -6807,6 +6838,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
&wp_color_manager_v1_interface, 1);
wp_color_manager_v1_add_listener(d->color_manager,
&cm_listener, d);
} else if (strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) {
d->single_pixel_buffer_manager =
wl_registry_bind(registry, id,
&wp_single_pixel_buffer_manager_v1_interface,
1);
}
if (d->global_handler)
@ -7095,6 +7131,12 @@ display_get_compositor(struct display *display)
return display->compositor;
}
struct wp_single_pixel_buffer_manager_v1 *
display_get_single_pixel_buffer_manager(struct display *display)
{
return display->single_pixel_buffer_manager;
}
uint32_t
display_get_serial(struct display *display)
{

View file

@ -76,6 +76,9 @@ display_has_subcompositor(struct display *display);
struct wl_compositor *
display_get_compositor(struct display *display);
struct wp_single_pixel_buffer_manager_v1 *
display_get_single_pixel_buffer_manager(struct display *display);
struct output *
display_get_output(struct display *display);
@ -610,6 +613,9 @@ widget_cairo_create(struct widget *widget);
struct wl_surface *
widget_get_wl_surface(struct widget *widget);
void
widget_surface_flush(struct widget *widget);
uint32_t
widget_get_last_time(struct widget *widget);