[weston RFC 1/5] window: Allow hinting of a preference for RGB565 when creating a window

Tomeu Vizoso tomeu at tomeuvizoso.net
Fri Jul 5 02:41:11 PDT 2013


And check if the renderer supports the RGB565 format for wl_shm buffers
before creating the cairo surface and requesting the buffer.

It can save quite some memory with big surfaces such as desktop
backgrounds.
---
 clients/desktop-shell.c |  8 ++++----
 clients/keyboard.c      |  2 +-
 clients/tablet-shell.c  |  6 +++---
 clients/window.c        | 49 +++++++++++++++++++++++++++++++++++++++++--------
 clients/window.h        |  4 +++-
 clients/wscreensaver.c  |  2 +-
 6 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 51ce3ec..dc375f8 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -534,7 +534,7 @@ panel_create(struct display *display)
 	memset(panel, 0, sizeof *panel);
 
 	panel->base.configure = panel_configure;
-	panel->window = window_create_custom(display);
+	panel->window = window_create_custom(display, 0);
 	panel->widget = window_add_widget(panel->window, panel);
 	wl_list_init(&panel->launcher_list);
 
@@ -869,7 +869,7 @@ unlock_dialog_create(struct desktop *desktop)
 		return NULL;
 	memset(dialog, 0, sizeof *dialog);
 
-	dialog->window = window_create_custom(display);
+	dialog->window = window_create_custom(display, 0);
 	dialog->widget = frame_create(dialog->window, dialog);
 	window_set_title(dialog->window, "Unlock your desktop");
 
@@ -1013,7 +1013,7 @@ background_create(struct desktop *desktop)
 	memset(background, 0, sizeof *background);
 
 	background->base.configure = background_configure;
-	background->window = window_create_custom(desktop->display);
+	background->window = window_create_custom(desktop->display, 1);
 	background->widget = window_add_widget(background->window, background);
 	window_set_user_data(background->window, background);
 	widget_set_redraw_handler(background->widget, background_draw);
@@ -1042,7 +1042,7 @@ grab_surface_create(struct desktop *desktop)
 {
 	struct wl_surface *s;
 
-	desktop->grab_window = window_create_custom(desktop->display);
+	desktop->grab_window = window_create_custom(desktop->display, 0);
 	window_set_user_data(desktop->grab_window, desktop);
 
 	s = window_get_wl_surface(desktop->grab_window);
diff --git a/clients/keyboard.c b/clients/keyboard.c
index a2fbded..fe308dd 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -840,7 +840,7 @@ keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard
 	memset(keyboard, 0, sizeof *keyboard);
 
 	keyboard->keyboard = virtual_keyboard;
-	keyboard->window = window_create_custom(virtual_keyboard->display);
+	keyboard->window = window_create_custom(virtual_keyboard->display, 0);
 	keyboard->widget = window_add_widget(keyboard->window, keyboard);
 
 	virtual_keyboard->keyboard = keyboard;
diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c
index 3d5e79a..afbd0f8 100644
--- a/clients/tablet-shell.c
+++ b/clients/tablet-shell.c
@@ -233,7 +233,7 @@ homescreen_create(struct tablet *tablet)
 	homescreen = malloc (sizeof *homescreen);
 	memset(homescreen, 0, sizeof *homescreen);
 
-	homescreen->window = window_create_custom(tablet->display);
+	homescreen->window = window_create_custom(tablet->display, 0);
 	homescreen->widget =
 		window_add_widget(homescreen->window, homescreen);
 	window_set_user_data(homescreen->window, homescreen);
@@ -251,7 +251,7 @@ lockscreen_create(struct tablet *tablet)
 	lockscreen = malloc (sizeof *lockscreen);
 	memset(lockscreen, 0, sizeof *lockscreen);
 
-	lockscreen->window = window_create_custom(tablet->display);
+	lockscreen->window = window_create_custom(tablet->display, 0);
 	lockscreen->widget =
 		window_add_widget(lockscreen->window, lockscreen);
 	window_set_user_data(lockscreen->window, lockscreen);
@@ -282,7 +282,7 @@ show_switcher(void *data, struct tablet_shell *tablet_shell)
 {
 	struct tablet *tablet = data;
 
-	tablet->switcher = window_create_custom(tablet->display);
+	tablet->switcher = window_create_custom(tablet->display, 0);
 	window_set_user_data(tablet->switcher, tablet);
 	tablet_shell_set_switcher(tablet->tablet_shell,
 				  window_get_wl_surface(tablet->switcher));
diff --git a/clients/window.c b/clients/window.c
index cff7102..78d74e8 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -128,6 +128,8 @@ struct display {
 	/* A hack to get text extents for tooltips */
 	cairo_surface_t *dummy_surface;
 	void *dummy_surface_data;
+
+	int has_rgb565;
 };
 
 enum {
@@ -237,6 +239,8 @@ struct window {
 	int fullscreen_method;
 	int configure_requests;
 
+	int prefer_rgb565;
+
 	window_key_handler_t key_handler;
 	window_keyboard_focus_handler_t keyboard_focus_handler;
 	window_data_handler_t data_handler;
@@ -794,6 +798,7 @@ display_create_shm_surface_from_pool(struct display *display,
 	struct shm_surface_data *data;
 	uint32_t format;
 	cairo_surface_t *surface;
+	cairo_format_t cairo_format;
 	int stride, length, offset;
 	void *map;
 
@@ -801,8 +806,12 @@ display_create_shm_surface_from_pool(struct display *display,
 	if (data == NULL)
 		return NULL;
 
-	stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
-						rectangle->width);
+	if (flags & SURFACE_HINT_RGB565 && display->has_rgb565)
+		cairo_format = CAIRO_FORMAT_RGB16_565;
+	else
+		cairo_format = CAIRO_FORMAT_ARGB32;
+
+	stride = cairo_format_stride_for_width (cairo_format, rectangle->width);
 	length = stride * rectangle->height;
 	data->pool = NULL;
 	map = shm_pool_allocate(pool, length, &offset);
@@ -813,7 +822,7 @@ display_create_shm_surface_from_pool(struct display *display,
 	}
 
 	surface = cairo_image_surface_create_for_data (map,
-						       CAIRO_FORMAT_ARGB32,
+						       cairo_format,
 						       rectangle->width,
 						       rectangle->height,
 						       stride);
@@ -821,10 +830,14 @@ display_create_shm_surface_from_pool(struct display *display,
 	cairo_surface_set_user_data(surface, &shm_surface_data_key,
 				    data, shm_surface_data_destroy);
 
-	if (flags & SURFACE_OPAQUE)
-		format = WL_SHM_FORMAT_XRGB8888;
-	else
-		format = WL_SHM_FORMAT_ARGB8888;
+	if (flags & SURFACE_HINT_RGB565 && display->has_rgb565)
+		format = WL_SHM_FORMAT_RGB565;
+	else {
+		if (flags & SURFACE_OPAQUE)
+			format = WL_SHM_FORMAT_XRGB8888;
+		else
+			format = WL_SHM_FORMAT_ARGB8888;
+	}
 
 	data->buffer = wl_shm_pool_create_buffer(pool->pool, offset,
 						 rectangle->width,
@@ -1425,6 +1438,9 @@ window_create_main_surface(struct window *window)
 	if (window->resizing)
 		flags |= SURFACE_HINT_RESIZE;
 
+	if (window->prefer_rgb565)
+		flags |= SURFACE_HINT_RGB565;
+
 	if (window->resize_edges & WINDOW_RESIZING_LEFT)
 		dx = surface->server_allocation.width -
 			surface->allocation.width;
@@ -4202,6 +4218,7 @@ window_create_internal(struct display *display,
 	window->type = type;
 	window->fullscreen_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
 	window->configure_requests = 0;
+	window->prefer_rgb565 = 0;
 
 	if (display->argb_device)
 #ifdef HAVE_CAIRO_EGL
@@ -4240,7 +4257,7 @@ window_create(struct display *display)
 }
 
 struct window *
-window_create_custom(struct display *display)
+window_create_custom(struct display *display, int prefer_rgb565)
 {
 	struct window *window;
 
@@ -4248,6 +4265,8 @@ window_create_custom(struct display *display)
 	if (!window)
 		return NULL;
 
+	window->prefer_rgb565 = prefer_rgb565;
+
 	return window;
 }
 
@@ -4737,6 +4756,19 @@ init_workspace_manager(struct display *d, uint32_t id)
 }
 
 static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+	struct display *d = data;
+
+	if (format == WL_SHM_FORMAT_RGB565)
+		d->has_rgb565 = 1;
+}
+
+struct wl_shm_listener shm_listener = {
+	shm_format
+};
+
+static void
 registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
 		       const char *interface, uint32_t version)
 {
@@ -4761,6 +4793,7 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
 					    id, &wl_shell_interface, 1);
 	} else if (strcmp(interface, "wl_shm") == 0) {
 		d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+		wl_shm_add_listener(d->shm, &shm_listener, d);
 	} else if (strcmp(interface, "wl_data_device_manager") == 0) {
 		d->data_device_manager =
 			wl_registry_bind(registry, id,
diff --git a/clients/window.h b/clients/window.h
index a79b020..d495ce4 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -132,6 +132,8 @@ display_release_window_surface(struct display *display,
 
 #define SURFACE_HINT_RESIZE 0x10
 
+#define SURFACE_HINT_RGB565 0x100
+
 cairo_surface_t *
 display_create_surface(struct display *display,
 		       struct wl_surface *surface,
@@ -232,7 +234,7 @@ struct window *
 window_create_transient(struct display *display, struct window *parent,
 			int32_t x, int32_t y, uint32_t flags);
 struct window *
-window_create_custom(struct display *display);
+window_create_custom(struct display *display, int prefer_rgb565);
 
 int
 window_has_focus(struct window *window);
diff --git a/clients/wscreensaver.c b/clients/wscreensaver.c
index 9a2c47a..a0bc827 100644
--- a/clients/wscreensaver.c
+++ b/clients/wscreensaver.c
@@ -184,7 +184,7 @@ create_wscreensaver_instance(struct wscreensaver *screensaver,
 	if (demo_mode)
 		mi->window = window_create(screensaver->display);
 	else
-		mi->window = window_create_custom(screensaver->display);
+		mi->window = window_create_custom(screensaver->display, 0);
 
 	if (!mi->window) {
 		fprintf(stderr, "%s: creating a window failed.\n", progname);
-- 
1.8.3.1



More information about the wayland-devel mailing list