window: Allow hinting of a preference for RGB565 when creating a window
authorTomeu Vizoso <tomeu@tomeuvizoso.net>
Tue, 6 Aug 2013 18:05:54 +0000 (20:05 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 6 Aug 2013 23:49:27 +0000 (16:49 -0700)
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
clients/window.c
clients/window.h

index ad324ba..9bd0ade 100644 (file)
@@ -995,6 +995,8 @@ background_create(struct desktop *desktop)
        background->widget = window_add_widget(background->window, background);
        window_set_user_data(background->window, background);
        widget_set_redraw_handler(background->widget, background_draw);
+       window_set_preferred_format(background->window,
+                                   WINDOW_PREFERRED_FORMAT_RGB565);
 
        s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
        weston_config_section_get_string(s, "background-image",
index d9f7d5a..b9045f3 100644 (file)
@@ -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;
 
+       enum preferred_format preferred_format;
+
        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->preferred_format == WINDOW_PREFERRED_FORMAT_RGB565)
+               flags |= SURFACE_HINT_RGB565;
+
        if (window->resize_edges & WINDOW_RESIZING_LEFT)
                dx = surface->server_allocation.width -
                        surface->allocation.width;
@@ -4209,6 +4225,7 @@ window_create_internal(struct display *display,
        window->type = type;
        window->fullscreen_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
        window->configure_requests = 0;
+       window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
 
        if (display->argb_device)
 #ifdef HAVE_CAIRO_EGL
@@ -4432,6 +4449,13 @@ window_set_buffer_type(struct window *window, enum window_buffer_type type)
        window->main_surface->buffer_type = type;
 }
 
+void
+window_set_preferred_format(struct window *window,
+                           enum preferred_format format)
+{
+       window->preferred_format = format;
+}
+
 struct widget *
 window_add_subsurface(struct window *window, void *data,
                      enum subsurface_mode default_mode)
@@ -4730,6 +4754,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)
 {
@@ -4754,6 +4791,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,
index 75be165..e045b95 100644 (file)
@@ -139,6 +139,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,
@@ -383,6 +385,15 @@ window_get_title(struct window *window);
 void
 window_set_text_cursor_position(struct window *window, int32_t x, int32_t y);
 
+enum preferred_format {
+       WINDOW_PREFERRED_FORMAT_NONE,
+       WINDOW_PREFERRED_FORMAT_RGB565
+};
+
+void
+window_set_preferred_format(struct window *window,
+                           enum preferred_format format);
+
 int
 widget_set_tooltip(struct widget *parent, char *entry, float x, float y);