From f5e5b3eec3e6c06af24cbf2dd65424dced1109ad Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sun, 15 Sep 2019 20:05:37 +1200 Subject: [PATCH] Add new output cursor API --- include/wlr/interfaces/wlr_output.h | 3 + include/wlr/types/wlr_output.h | 106 ++++++++++++++++++++++++++-- types/wlr_output.c | 45 ++++++++++++ 3 files changed, 147 insertions(+), 7 deletions(-) diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index a9a89c342..c554c4af0 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -25,6 +25,9 @@ struct wlr_output_impl { bool (*move_cursor)(struct wlr_output *output, int x, int y); void (*destroy)(struct wlr_output *output); bool (*attach_render)(struct wlr_output *output, int *buffer_age); + bool (*cursor_try_set_size)(struct wlr_output *output, int *x, int *y); + bool (*cursor_attach_render)(struct wlr_output *output, int *buffer_age); + bool (*cursor_commit)(struct wlr_output *output); bool (*commit)(struct wlr_output *output); bool (*set_gamma)(struct wlr_output *output, size_t size, const uint16_t *r, const uint16_t *g, const uint16_t *b); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5f5fe2e06..65e812734 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -46,6 +46,20 @@ struct wlr_output_state { struct wlr_buffer *buffer; // if WLR_OUTPUT_STATE_BUFFER_SCANOUT }; +enum wlr_output_cursor_field { + WLR_OUTPUT_CURSOR_BUFFER = 1 << 0, + WLR_OUTPUT_CURSOR_ENABLE = 1 << 1, + WLR_OUTPUT_CURSOR_POS = 1 << 2, +}; + +struct wlr_output_cursor { + uint32_t committed; // enum wlr_output_cursor_state_field + + bool enabled; + int x, y; + int hotspot_x, hotspot_y; +}; + struct wlr_output_impl; /** @@ -91,6 +105,7 @@ struct wlr_output { float transform_matrix[9]; struct wlr_output_state pending; + struct wlr_output_cursor cursor_pending; struct { // Request to render a frame @@ -280,13 +295,90 @@ void wlr_output_lock_attach_render(struct wlr_output *output, bool lock); */ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock); -#if 0 -bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, - const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, - int32_t hotspot_x, int32_t hotspot_y); -bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, - double x, double y); -#endif +/** + * Hardware cursors: + * + * Hardware cursors are a feature of GPUs that allow a small framebuffer + * to be displayed over the main framebuffer. This is more efficient than + * drawing onto the main framebuffer using e.g. OpenGL. + * + * Not every backend/output will support hardware cursors, so you must always + * be prepared to fall back to rendering the cursor to the main framebuffer + * yourself. + * + * Hardware cursors are always in output buffer coordinates, and does not take + * scale nor rotation into account. You are responsible for doing this + * yourself. + * + * Hardware cursors are always in the ARGB8888 format. + */ + +/** + * Sets the size of the hardware cursor buffer to the values pointed to by + * x and y. + * + * Some backends have strict requirements for the cursor size and may not be + * able to use the size you requested exactly. The actual value used will be + * left in x and y. If this is not large enough for the cursor you wish to + * draw, you should fall back to using software cursors. + * + * This returns false if the backend does not support hardware cursors or from + * some other internal error. Either way, you should fall back to using + * software cursors. + */ +bool wlr_output_cursor_try_set_size(struct wlr_output *output, int *x, int *y); + +/** + * Attaches the renderer to the cursor buffer. + * + * You must successfully call `wlr_output_cursor_try_set_size` at least once + * before using this. Any rendering done will be applied on + * `wlr_output_cursor_commit`. + */ +bool wlr_output_cursor_attach_render(struct wlr_output *output, int *buffer_age); + +/** + * Enables displaying the hardware cursor. + * + * This does not affect the ability to render to the cursor. It only sets + * whether or not it will be displayed. By default, the cursor is disabled. + * + * This will be applied on `wlr_output_cursor_commit`. + */ +void wlr_output_cursor_enable(struct wlr_output *output, bool enable); + +/** + * Moves the position of the hardware cursor on the main framebuffer. + * + * This is in output buffer coordinates. Negative values and values that would + * place the cursor partially or entirely off the main framebuffer are allowed. + * + * The hotspot is the point on the cursor buffer (from the top left) where the + * cursor actually points. For example, with a cursor representing a hand, the + * hotspot may be over the index finger, rather than the top left corner. + * + * Some backends may not be able to move the cursor freely, but may still be + * able to make use of the hotspot to correctly show the cursor. + * + * This will be applied on `wlr_output_cursor_commit`. + */ +void wlr_output_cursor_move(struct wlr_output *output, int x, int y, + int hotspot_x, int hotspot_y); + +/** + * Apply pending cursor state. + * + * This may or may not be synchronized with the output, and would be applied on + * `wlr_output_commit`, depending on the backend limitations. However, it's + * advised to assume that they are sychronized and do any cursor operations at + * the same time you render to the output. + * + * If you have called `wlr_output_cursor_attach_render`, you must call this + * function before `wlr_output_attach_render`, otherwise you risk losing or + * corrupting rendering state. + */ +bool wlr_output_cursor_commit(struct wlr_output *output); + /** * Returns the transform that, when composed with `tr`, gives diff --git a/types/wlr_output.c b/types/wlr_output.c index ea5f6138a..183646537 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -628,6 +628,51 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) { output->software_cursor_locks); } +bool wlr_output_cursor_try_set_size(struct wlr_output *output, int *x, int *y) { + if (!output->impl->cursor_try_set_size) { + return false; + } + + return output->impl->cursor_try_set_size(output, x, y); +} + +bool wlr_output_cursor_attach_render(struct wlr_output *output, int *buffer_age) { + if (!output->impl->cursor_attach_render) { + return false; + } + + if (!output->impl->cursor_attach_render(output, buffer_age)) { + return false; + } + + output->cursor_pending.committed |= WLR_OUTPUT_CURSOR_BUFFER; + return true; +} + +void wlr_output_cursor_enable(struct wlr_output *output, bool enable) { + output->cursor_pending.enabled = enable; + output->cursor_pending.committed |= WLR_OUTPUT_CURSOR_ENABLE; +} + +void wlr_output_cursor_move(struct wlr_output *output, int x, int y, + int hotspot_x, int hotspot_y) { + output->cursor_pending.x = x; + output->cursor_pending.y = y; + output->cursor_pending.hotspot_x = hotspot_x; + output->cursor_pending.hotspot_y = hotspot_y; + output->cursor_pending.committed |= WLR_OUTPUT_CURSOR_POS; +} + +bool wlr_output_cursor_commit(struct wlr_output *output) { + if (!output->impl->cursor_commit) { + return false; + } + + bool ret = output->impl->cursor_commit(output); + output->cursor_pending.committed = 0; + return ret; +} + #if 0 bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height,