types/wlr_xcursor_manager: Add caching textures

This commit is contained in:
Scott Anderson 2019-09-17 22:29:28 +12:00
parent 2fcb2b95fc
commit c5bd304795
5 changed files with 98 additions and 37 deletions

View file

@ -59,9 +59,6 @@ struct sample_output {
struct wlr_output *output; struct wlr_output *output;
struct wl_listener frame; struct wl_listener frame;
struct wl_listener destroy; struct wl_listener destroy;
struct wlr_texture *texture;
int32_t hotspot_x, hotspot_y;
}; };
struct sample_keyboard { 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); struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
assert(renderer); 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; bool render_software = true;
if (!sample_output->texture) { if (!tex) {
goto render_output; 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); wlr_output_layout_output_coords(state->layout, wlr_output, &x, &y);
int w, h; 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; int buf_w = w, buf_h = h;
if (!wlr_output_cursor_try_set_size(wlr_output, &buf_w, &buf_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. * hardware cursor, and to know it's really ours.
*/ */
wlr_renderer_clear(renderer, (float[]){ 0.2, 0.2, 0.2, 0.2 }); 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_renderer_end(renderer);
wlr_output_cursor_move(wlr_output, x, y, 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_enable(wlr_output, true);
wlr_output_cursor_commit(wlr_output); wlr_output_cursor_commit(wlr_output);
@ -147,15 +150,15 @@ render_output:
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(renderer, state->clear_color); wlr_renderer_clear(renderer, state->clear_color);
if (!render_software || !sample_output->texture) { if (!render_software || !tex) {
goto end; goto end;
} }
x = state->cursor->x - sample_output->hotspot_x; x = state->cursor->x - cursor->hotspot_x;
y = state->cursor->y - sample_output->hotspot_y; y = state->cursor->y - cursor->hotspot_y;
wlr_output_layout_output_coords(state->layout, wlr_output, &x, &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); wlr_output->transform_matrix, x, y, 1.0f);
end: end:
@ -305,7 +308,6 @@ void new_output_notify(struct wl_listener *listener, void *data) {
struct wlr_output *output = data; struct wlr_output *output = data;
struct sample_state *sample = wl_container_of(listener, sample, new_output); struct sample_state *sample = wl_container_of(listener, sample, new_output);
struct sample_output *sample_output = calloc(1, sizeof(struct sample_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)) { if (!wl_list_empty(&output->modes)) {
struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); 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_output_layout_add_auto(sample->layout, sample_output->output);
wlr_xcursor_manager_load(sample->xcursor_manager, output->scale); 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) { 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);
state.tablet_tool_axis.notify = handle_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) { if (!state.xcursor_manager) {
wlr_log(WLR_ERROR, "Failed to load left_ptr cursor"); wlr_log(WLR_ERROR, "Failed to load left_ptr cursor");
return 1; return 1;

View file

@ -13,6 +13,8 @@
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/xcursor.h> #include <wlr/xcursor.h>
struct wlr_renderer;
/** /**
* An XCursor theme at a particular scale factor of the base size. * An XCursor theme at a particular scale factor of the base size.
*/ */
@ -32,6 +34,9 @@ struct wlr_xcursor_manager {
char *name; char *name;
uint32_t size; uint32_t size;
struct wl_list scaled_themes; // wlr_xcursor_manager_theme::link 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). * (for use when scale=1).
*/ */
struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, 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); 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 *wlr_xcursor_manager_get_xcursor(
struct wlr_xcursor_manager *manager, const char *name, float scale); 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 #endif

View file

@ -52,6 +52,7 @@ struct wlr_xcursor_image {
uint32_t hotspot_y; /* hot spot y (must be inside image) */ uint32_t hotspot_y; /* hot spot y (must be inside image) */
uint32_t delay; /* animation delay to next frame (ms) */ uint32_t delay; /* animation delay to next frame (ms) */
uint8_t *buffer; uint8_t *buffer;
void *userdata;
}; };
struct wlr_xcursor { struct wlr_xcursor {

View file

@ -2,9 +2,34 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/wlr_texture.h>
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, 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 = struct wlr_xcursor_manager *manager =
calloc(1, sizeof(struct wlr_xcursor_manager)); calloc(1, sizeof(struct wlr_xcursor_manager));
if (manager == NULL) { if (manager == NULL) {
@ -15,6 +40,11 @@ struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name,
} }
manager->size = size; manager->size = size;
wl_list_init(&manager->scaled_themes); 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; return manager;
} }
@ -22,12 +52,20 @@ void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager) {
if (manager == NULL) { if (manager == NULL) {
return; return;
} }
if (manager->renderer) {
manager_free_textures(manager);
}
struct wlr_xcursor_manager_theme *theme, *tmp; struct wlr_xcursor_manager_theme *theme, *tmp;
wl_list_for_each_safe(theme, tmp, &manager->scaled_themes, link) { wl_list_for_each_safe(theme, tmp, &manager->scaled_themes, link) {
wl_list_remove(&theme->link);
wlr_xcursor_theme_destroy(theme->theme); wlr_xcursor_theme_destroy(theme->theme);
wl_list_remove(&theme->link);
free(theme); free(theme);
} }
if (manager->renderer) {
wl_list_remove(&manager->renderer_destroy.link);
}
free(manager->name); free(manager->name);
free(manager); free(manager);
} }
@ -65,3 +103,19 @@ struct wlr_xcursor *wlr_xcursor_manager_get_xcursor(
} }
return NULL; 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;
}

View file

@ -57,7 +57,7 @@ static struct wlr_xcursor *xcursor_create_from_data(
} }
cursor->image_count = 1; cursor->image_count = 1;
cursor->images = malloc(sizeof(*cursor->images)); cursor->images = calloc(1, sizeof(*cursor->images));
if (!cursor->images) { if (!cursor->images) {
goto err_free_cursor; goto err_free_cursor;
} }
@ -137,7 +137,7 @@ static struct wlr_xcursor *xcursor_create_from_xcursor_images(
return NULL; return NULL;
} }
cursor->images = malloc(images->nimage * sizeof(cursor->images[0])); cursor->images = calloc(images->nimage, sizeof(cursor->images[0]));
if (!cursor->images) { if (!cursor->images) {
free(cursor); free(cursor);
return NULL; return NULL;
@ -147,7 +147,7 @@ static struct wlr_xcursor *xcursor_create_from_xcursor_images(
cursor->total_delay = 0; cursor->total_delay = 0;
for (i = 0; i < images->nimage; i++) { for (i = 0; i < images->nimage; i++) {
image = malloc(sizeof(*image)); image = calloc(1, sizeof(*image));
if (image == NULL) { if (image == NULL) {
break; break;
} }