From c5bd304795a077292e4164a868f1de26f66d4cb9 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Tue, 17 Sep 2019 22:29:28 +1200 Subject: [PATCH] types/wlr_xcursor_manager: Add caching textures --- examples/pointer.c | 47 +++++++------------- include/wlr/types/wlr_xcursor_manager.h | 23 +++++++++- include/wlr/xcursor.h | 1 + types/wlr_xcursor_manager.c | 58 ++++++++++++++++++++++++- xcursor/wlr_xcursor.c | 6 +-- 5 files changed, 98 insertions(+), 37 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 9c496512d..42b72ad02 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -59,9 +59,6 @@ struct sample_output { struct wlr_output *output; struct wl_listener frame; struct wl_listener destroy; - - struct wlr_texture *texture; - int32_t hotspot_x, hotspot_y; }; struct sample_keyboard { @@ -97,9 +94,15 @@ void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); assert(renderer); + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( + state->xcursor_manager, "left_ptr", wlr_output->scale); + struct wlr_xcursor_image *cursor = xcursor->images[0]; + struct wlr_texture *tex = wlr_xcursor_manager_get_texture( + state->xcursor_manager, cursor); + bool render_software = true; - if (!sample_output->texture) { + if (!tex) { goto render_output; } @@ -108,7 +111,7 @@ void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_layout_output_coords(state->layout, wlr_output, &x, &y); int w, h; - wlr_texture_get_size(sample_output->texture, &w, &h); + wlr_texture_get_size(tex, &w, &h); int buf_w = w, buf_h = h; if (!wlr_output_cursor_try_set_size(wlr_output, &buf_w, &buf_h)) { @@ -131,11 +134,11 @@ void output_frame_notify(struct wl_listener *listener, void *data) { * hardware cursor, and to know it's really ours. */ wlr_renderer_clear(renderer, (float[]){ 0.2, 0.2, 0.2, 0.2 }); - wlr_render_texture_with_matrix(renderer, sample_output->texture, mat, 1.0f); + wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); wlr_renderer_end(renderer); wlr_output_cursor_move(wlr_output, x, y, - sample_output->hotspot_x, sample_output->hotspot_y); + cursor->hotspot_x, cursor->hotspot_y); wlr_output_cursor_enable(wlr_output, true); wlr_output_cursor_commit(wlr_output); @@ -147,15 +150,15 @@ render_output: wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(renderer, state->clear_color); - if (!render_software || !sample_output->texture) { + if (!render_software || !tex) { goto end; } - x = state->cursor->x - sample_output->hotspot_x; - y = state->cursor->y - sample_output->hotspot_y; + x = state->cursor->x - cursor->hotspot_x; + y = state->cursor->y - cursor->hotspot_y; wlr_output_layout_output_coords(state->layout, wlr_output, &x, &y); - wlr_render_texture(renderer, sample_output->texture, + wlr_render_texture(renderer, tex, wlr_output->transform_matrix, x, y, 1.0f); end: @@ -305,7 +308,6 @@ void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); if (!wl_list_empty(&output->modes)) { struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); @@ -320,24 +322,6 @@ void new_output_notify(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(sample->layout, sample_output->output); wlr_xcursor_manager_load(sample->xcursor_manager, output->scale); - - struct wlr_xcursor *xcursor; - struct wlr_xcursor_image *img; - - xcursor = wlr_xcursor_manager_get_xcursor(sample->xcursor_manager, - "left_ptr", output->scale); - if (!xcursor) { - return; - } - - /* Animation not supported */ - img = xcursor->images[0]; - sample_output->hotspot_x = img->hotspot_x; - sample_output->hotspot_y = img->hotspot_y; - - sample_output->texture = wlr_texture_from_pixels(renderer, - WL_SHM_FORMAT_ARGB8888, img->width * 4, img->width, - img->height, img->buffer); } void keyboard_destroy_notify(struct wl_listener *listener, void *data) { @@ -459,7 +443,8 @@ int main(int argc, char *argv[]) { &state.tablet_tool_axis); state.tablet_tool_axis.notify = handle_tablet_tool_axis; - state.xcursor_manager = wlr_xcursor_manager_create("default", 24); + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr); + state.xcursor_manager = wlr_xcursor_manager_create("default", 24, renderer); if (!state.xcursor_manager) { wlr_log(WLR_ERROR, "Failed to load left_ptr cursor"); return 1; diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h index d70f86836..4dae61d26 100644 --- a/include/wlr/types/wlr_xcursor_manager.h +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -13,6 +13,8 @@ #include #include +struct wlr_renderer; + /** * An XCursor theme at a particular scale factor of the base size. */ @@ -32,6 +34,9 @@ struct wlr_xcursor_manager { char *name; uint32_t size; struct wl_list scaled_themes; // wlr_xcursor_manager_theme::link + + struct wlr_renderer *renderer; + struct wl_listener renderer_destroy; }; /** @@ -39,7 +44,7 @@ struct wlr_xcursor_manager { * (for use when scale=1). */ struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, - uint32_t size); + uint32_t size, struct wlr_renderer *renderer); void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager); @@ -57,4 +62,20 @@ int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( struct wlr_xcursor_manager *manager, const char *name, float scale); +/** + * Retrieves the cached texture of this xcursor image from the + * wlr_xcursor_manager. + * + * The wlr_xcursor_manager must have been created with a wlr_renderer and the + * wlr_xcursor_image must have come from a wlr_xcursor returned from + * wlr_xcursor_manager_get_xcursor. + * + * The returned texture is owned by the xcursor manager. You should not save or + * destroy it. + * The manager makes use of the wlr_xcursor_image.userdata field. You must not + * modify this field yourself. + */ +struct wlr_texture *wlr_xcursor_manager_get_texture( + struct wlr_xcursor_manager *manager, struct wlr_xcursor_image *image); + #endif diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index 39874f39f..eb11fe933 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -52,6 +52,7 @@ struct wlr_xcursor_image { uint32_t hotspot_y; /* hot spot y (must be inside image) */ uint32_t delay; /* animation delay to next frame (ms) */ uint8_t *buffer; + void *userdata; }; struct wlr_xcursor { diff --git a/types/wlr_xcursor_manager.c b/types/wlr_xcursor_manager.c index c8618c019..d150c0c0a 100644 --- a/types/wlr_xcursor_manager.c +++ b/types/wlr_xcursor_manager.c @@ -2,9 +2,34 @@ #include #include #include +#include +#include + +static void manager_free_textures(struct wlr_xcursor_manager *manager) { + struct wlr_xcursor_manager_theme *iter; + wl_list_for_each(iter, &manager->scaled_themes, link) { + struct wlr_xcursor_theme *theme = iter->theme; + for (unsigned i = 0; i < theme->cursor_count; ++i) { + struct wlr_xcursor *xcursor = theme->cursors[i]; + for (unsigned j = 0; j < xcursor->image_count; ++j) { + struct wlr_xcursor_image *img = xcursor->images[j]; + + wlr_texture_destroy(img->userdata); + img->userdata = NULL; + } + } + } +} + +static void handle_renderer_destroy(struct wl_listener *listener, void *data) { + struct wlr_xcursor_manager *manager = + wl_container_of(listener, manager, renderer_destroy); + manager->renderer = NULL; + manager_free_textures(manager); +} struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, - uint32_t size) { + uint32_t size, struct wlr_renderer *renderer) { struct wlr_xcursor_manager *manager = calloc(1, sizeof(struct wlr_xcursor_manager)); if (manager == NULL) { @@ -15,6 +40,11 @@ struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, } manager->size = size; wl_list_init(&manager->scaled_themes); + if (renderer) { + manager->renderer = renderer; + manager->renderer_destroy.notify = handle_renderer_destroy; + wl_signal_add(&renderer->events.destroy, &manager->renderer_destroy); + } return manager; } @@ -22,12 +52,20 @@ void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager) { if (manager == NULL) { return; } + if (manager->renderer) { + manager_free_textures(manager); + } + struct wlr_xcursor_manager_theme *theme, *tmp; wl_list_for_each_safe(theme, tmp, &manager->scaled_themes, link) { - wl_list_remove(&theme->link); wlr_xcursor_theme_destroy(theme->theme); + + wl_list_remove(&theme->link); free(theme); } + if (manager->renderer) { + wl_list_remove(&manager->renderer_destroy.link); + } free(manager->name); free(manager); } @@ -65,3 +103,19 @@ struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( } return NULL; } + +struct wlr_texture *wlr_xcursor_manager_get_texture( + struct wlr_xcursor_manager *manager, + struct wlr_xcursor_image *image) { + if (!manager->renderer) { + return NULL; + } + + if (!image->userdata) { + image->userdata = wlr_texture_from_pixels(manager->renderer, + WL_SHM_FORMAT_ARGB8888, image->width * 4, image->width, + image->height, image->buffer); + } + + return image->userdata; +} diff --git a/xcursor/wlr_xcursor.c b/xcursor/wlr_xcursor.c index 4e1d02ecf..f71f17fa2 100644 --- a/xcursor/wlr_xcursor.c +++ b/xcursor/wlr_xcursor.c @@ -57,7 +57,7 @@ static struct wlr_xcursor *xcursor_create_from_data( } cursor->image_count = 1; - cursor->images = malloc(sizeof(*cursor->images)); + cursor->images = calloc(1, sizeof(*cursor->images)); if (!cursor->images) { goto err_free_cursor; } @@ -137,7 +137,7 @@ static struct wlr_xcursor *xcursor_create_from_xcursor_images( return NULL; } - cursor->images = malloc(images->nimage * sizeof(cursor->images[0])); + cursor->images = calloc(images->nimage, sizeof(cursor->images[0])); if (!cursor->images) { free(cursor); return NULL; @@ -147,7 +147,7 @@ static struct wlr_xcursor *xcursor_create_from_xcursor_images( cursor->total_delay = 0; for (i = 0; i < images->nimage; i++) { - image = malloc(sizeof(*image)); + image = calloc(1, sizeof(*image)); if (image == NULL) { break; }