diff --git a/backend/drm/drm.c b/backend/drm/drm.c index e8ed7316..30be40ea 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -538,7 +538,8 @@ static void drm_connector_transform(struct wlr_output *output, } static bool drm_connector_set_cursor(struct wlr_output *output, - struct wlr_texture *texture, int32_t hotspot_x, int32_t hotspot_y, + struct wlr_texture *texture, int32_t scale, + enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y, bool update_texture) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; @@ -581,15 +582,12 @@ static bool drm_connector_set_cursor(struct wlr_output *output, return false; } - enum wl_output_transform transform = output->transform; wlr_matrix_projection(plane->matrix, plane->surf.width, - plane->surf.height, transform); + plane->surf.height, output->transform); } struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; - enum wl_output_transform transform = - wlr_output_transform_invert(output->transform); - wlr_box_transform(&hotspot, transform, + wlr_box_transform(&hotspot, wlr_output_transform_invert(output->transform), plane->surf.width, plane->surf.height, &hotspot); if (plane->cursor_hotspot_x != hotspot.x || @@ -617,6 +615,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output, if (texture != NULL) { int width, height; wlr_texture_get_size(texture, &width, &height); + width = width * output->scale / scale; + height = height * output->scale / scale; if (width > (int)plane->surf.width || height > (int)plane->surf.height) { wlr_log(L_ERROR, "Cursor too large (max %dx%d)", @@ -639,9 +639,14 @@ static bool drm_connector_set_cursor(struct wlr_output *output, struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; + struct wlr_box cursor_box = { .width = width, .height = height }; + + float matrix[9]; + wlr_matrix_project_box(matrix, &cursor_box, transform, 0, plane->matrix); + wlr_renderer_begin(rend, plane->surf.width, plane->surf.height); wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 }); - wlr_render_texture(rend, texture, plane->matrix, 0, 0, 1.0f); + wlr_render_texture_with_matrix(rend, texture, matrix, 1.0); wlr_renderer_end(rend); wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, diff --git a/backend/wayland/output.c b/backend/wayland/output.c index c498fc4e..109834c9 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -72,16 +72,20 @@ static void output_transform(struct wlr_output *_output, output->wlr_output.transform = transform; } -static bool output_set_cursor(struct wlr_output *_output, - struct wlr_texture *texture, int32_t hotspot_x, int32_t hotspot_y, +static bool output_set_cursor(struct wlr_output *wlr_output, + struct wlr_texture *texture, int32_t scale, + enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y, bool update_texture) { - struct wlr_wl_output *output = - (struct wlr_wl_output *)_output; + struct wlr_wl_output *output = (struct wlr_wl_output *)wlr_output; struct wlr_wl_backend *backend = output->backend; + struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; + wlr_box_transform(&hotspot, wlr_output_transform_invert(wlr_output->transform), + output->cursor.width, output->cursor.height, &hotspot); + // TODO: use output->wlr_output.transform to transform pixels and hotpot - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = hotspot_y; + output->cursor.hotspot_x = hotspot.x; + output->cursor.hotspot_y = hotspot.y; if (!update_texture) { // Update hotspot without changing cursor image @@ -98,6 +102,11 @@ static bool output_set_cursor(struct wlr_output *_output, if (texture != NULL) { int width, height; wlr_texture_get_size(texture, &width, &height); + width = width * wlr_output->scale / scale; + height = height * wlr_output->scale / scale; + + output->cursor.width = width; + output->cursor.height = height; if (output->cursor.egl_window == NULL) { output->cursor.egl_window = @@ -110,12 +119,20 @@ static bool output_set_cursor(struct wlr_output *_output, wlr_egl_make_current(&backend->egl, egl_surface, NULL); + struct wlr_box cursor_box = { + .width = width, + .height = height, + }; + + float projection[9]; + wlr_matrix_projection(projection, width, height, wlr_output->transform); + float matrix[9]; - wlr_matrix_projection(matrix, width, height, WL_OUTPUT_TRANSFORM_NORMAL); + wlr_matrix_project_box(matrix, &cursor_box, transform, 0, projection); wlr_renderer_begin(backend->renderer, width, height); wlr_renderer_clear(backend->renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 }); - wlr_render_texture(backend->renderer, texture, matrix, 0, 0, 1.0); + wlr_render_texture_with_matrix(backend->renderer, texture, matrix, 1.0); wlr_renderer_end(backend->renderer); wlr_egl_swap_buffers(&backend->egl, egl_surface, NULL); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index fec328ba..fda27da9 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -55,6 +55,7 @@ struct wlr_wl_output { struct wl_surface *surface; struct wl_egl_window *egl_window; int32_t hotspot_x, hotspot_y; + int32_t width, height; } cursor; }; diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index d8c54067..7ecc7551 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -14,6 +14,7 @@ struct wlr_output_impl { void (*transform)(struct wlr_output *output, enum wl_output_transform transform); bool (*set_cursor)(struct wlr_output *output, struct wlr_texture *texture, + int32_t scale, enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y, bool update_texture); bool (*move_cursor)(struct wlr_output *output, int x, int y); void (*destroy)(struct wlr_output *output); diff --git a/types/wlr_output.c b/types/wlr_output.c index 0973fbc7..350538a7 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -695,9 +695,13 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { } static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { + int32_t scale = cursor->output->scale; + enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; struct wlr_texture *texture = cursor->texture; if (cursor->surface != NULL) { texture = cursor->surface->texture; + scale = cursor->surface->current->scale; + transform = cursor->surface->current->transform; } struct wlr_output_cursor *hwcur = cursor->output->hardware_cursor; @@ -708,7 +712,7 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { (int)cursor->x, (int)cursor->y); } if (cursor->output->impl->set_cursor(cursor->output, texture, - cursor->hotspot_x, cursor->hotspot_y, true)) { + scale, transform, cursor->hotspot_x, cursor->hotspot_y, true)) { cursor->output->hardware_cursor = cursor; return true; } @@ -810,7 +814,7 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, } else { assert(cursor->output->impl->set_cursor); cursor->output->impl->set_cursor(cursor->output, NULL, - hotspot_x, hotspot_y, false); + 1, WL_OUTPUT_TRANSFORM_NORMAL, hotspot_x, hotspot_y, false); } return; } @@ -835,7 +839,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, if (cursor->output->hardware_cursor == cursor) { assert(cursor->output->impl->set_cursor); - cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, true); + cursor->output->impl->set_cursor(cursor->output, NULL, 1, + WL_OUTPUT_TRANSFORM_NORMAL, 0, 0, true); } } } @@ -897,7 +902,8 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { if (cursor->output->hardware_cursor == cursor) { // If this cursor was the hardware cursor, disable it if (cursor->output->impl->set_cursor) { - cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, true); + cursor->output->impl->set_cursor(cursor->output, NULL, 1, + WL_OUTPUT_TRANSFORM_NORMAL, 0, 0, true); } cursor->output->hardware_cursor = NULL; }