From 225d182765eb69aa7a7647c809c37903ec08519c Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 1 May 2018 21:38:04 +0100 Subject: output: always use hardware cursors if available This changes the `wlr_output_impl.set_cursor` function to take a `wlr_texture` instead of a byte buffer. This simplifies the DRM and Wayland backends since they were creating textures from the byte buffer anyway. With this commit, performance should be improved when moving the cursor since outputs don't need to be re-rendered anymore. --- backend/drm/drm.c | 33 +++++++-------- backend/wayland/backend.c | 10 ++++- backend/wayland/output.c | 101 +++++++++++++++------------------------------- 3 files changed, 57 insertions(+), 87 deletions(-) (limited to 'backend') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index dc512151..70089e06 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -537,8 +537,8 @@ static void drm_connector_transform(struct wlr_output *output, } static bool drm_connector_set_cursor(struct wlr_output *output, - const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height, - int32_t hotspot_x, int32_t hotspot_y, bool update_pixels) { + struct wlr_texture *texture, 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; struct wlr_drm_renderer *renderer = &drm->renderer; @@ -567,11 +567,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output, ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &h); h = ret ? 64 : h; - if (width > w || height > h) { - wlr_log(L_INFO, "Cursor too large (max %dx%d)", (int)w, (int)h); - return false; - } - if (!init_drm_surface(&plane->surf, renderer, w, h, GBM_FORMAT_ARGB8888, 0)) { wlr_log(L_ERROR, "Cannot allocate cursor resources"); @@ -612,14 +607,22 @@ static bool drm_connector_set_cursor(struct wlr_output *output, wlr_output_update_needs_swap(output); } - if (!update_pixels) { + if (!update_texture) { // Don't update cursor image return true; } - plane->cursor_enabled = buf != NULL; + plane->cursor_enabled = false; + if (texture != NULL) { + int width, height; + wlr_texture_get_size(texture, &width, &height); + + if (width > (int)plane->surf.width || height > (int)plane->surf.height) { + wlr_log(L_ERROR, "Cursor too large (max %dx%d)", + (int)plane->surf.width, (int)plane->surf.height); + return false; + } - if (buf != NULL) { uint32_t bo_width = gbm_bo_get_width(plane->cursor_bo); uint32_t bo_height = gbm_bo_get_height(plane->cursor_bo); @@ -635,13 +638,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output, struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; - struct wlr_texture *texture = wlr_texture_from_pixels(rend, - WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); - if (texture == NULL) { - wlr_log(L_ERROR, "Unable to create texture"); - return false; - } - 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); @@ -652,8 +648,9 @@ static bool drm_connector_set_cursor(struct wlr_output *output, swap_drm_surface_buffers(&plane->surf, NULL); - wlr_texture_destroy(texture); gbm_bo_unmap(plane->cursor_bo, bo_data); + + plane->cursor_enabled = true; } if (!drm->session->active) { diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 15d8feab..dc50cf23 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -164,8 +164,16 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, goto error_registry; } + static EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_ALPHA_SIZE, 1, + EGL_NONE, + }; if (!wlr_egl_init(&backend->egl, EGL_PLATFORM_WAYLAND_EXT, - backend->remote_display, NULL, WL_SHM_FORMAT_ARGB8888)) { + backend->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888)) { wlr_log(L_ERROR, "Could not initialize EGL"); goto error_egl; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 209b060f..c498fc4e 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "backend/wayland.h" #include "util/signal.h" @@ -72,8 +73,8 @@ static void output_transform(struct wlr_output *_output, } static bool output_set_cursor(struct wlr_output *_output, - const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height, - int32_t hotspot_x, int32_t hotspot_y, bool update_pixels) { + struct wlr_texture *texture, int32_t hotspot_x, int32_t hotspot_y, + bool update_texture) { struct wlr_wl_output *output = (struct wlr_wl_output *)_output; struct wlr_wl_backend *backend = output->backend; @@ -82,76 +83,47 @@ static bool output_set_cursor(struct wlr_output *_output, output->cursor.hotspot_x = hotspot_x; output->cursor.hotspot_y = hotspot_y; - if (!update_pixels) { + if (!update_texture) { // Update hotspot without changing cursor image update_wl_output_cursor(output); return true; } - if (!buf) { - // Hide cursor - if (output->cursor.surface) { - wl_surface_destroy(output->cursor.surface); - munmap(output->cursor.data, output->cursor.buf_size); - output->cursor.surface = NULL; - output->cursor.buf_size = 0; - } - update_wl_output_cursor(output); - return true; - } - if (!backend->shm || !backend->pointer) { - wlr_log(L_INFO, "cannot set cursor: no wl_shm or wl_pointer"); - return false; - } - - if (!output->cursor.surface) { + if (output->cursor.surface == NULL) { output->cursor.surface = - wl_compositor_create_surface(output->backend->compositor); + wl_compositor_create_surface(backend->compositor); } + struct wl_surface *surface = output->cursor.surface; - uint32_t size = stride * height; - if (output->cursor.buf_size != size) { - if (output->cursor.buffer) { - wl_buffer_destroy(output->cursor.buffer); - } + if (texture != NULL) { + int width, height; + wlr_texture_get_size(texture, &width, &height); - if (size > output->cursor.buf_size) { - if (output->cursor.pool) { - wl_shm_pool_destroy(output->cursor.pool); - output->cursor.pool = NULL; - munmap(output->cursor.data, output->cursor.buf_size); - } + if (output->cursor.egl_window == NULL) { + output->cursor.egl_window = + wl_egl_window_create(surface, width, height); } + wl_egl_window_resize(output->cursor.egl_window, width, height, 0, 0); - if (!output->cursor.pool) { - int fd = os_create_anonymous_file(size); - if (fd < 0) { - wlr_log_errno(L_INFO, - "creating anonymous file for cursor buffer failed"); - return false; - } - - output->cursor.data = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (output->cursor.data == MAP_FAILED) { - close(fd); - wlr_log_errno(L_INFO, "mmap failed"); - return false; - } - - output->cursor.pool = wl_shm_create_pool(backend->shm, fd, size); - close(fd); - } + EGLSurface egl_surface = + wlr_egl_create_surface(&backend->egl, output->cursor.egl_window); - output->cursor.buffer = wl_shm_pool_create_buffer(output->cursor.pool, - 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - output->cursor.buf_size = size; - } + wlr_egl_make_current(&backend->egl, egl_surface, NULL); - memcpy(output->cursor.data, buf, size); - wl_surface_attach(output->cursor.surface, output->cursor.buffer, 0, 0); - wl_surface_damage(output->cursor.surface, 0, 0, width, height); - wl_surface_commit(output->cursor.surface); + float matrix[9]; + wlr_matrix_projection(matrix, width, height, WL_OUTPUT_TRANSFORM_NORMAL); + + 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_renderer_end(backend->renderer); + + wlr_egl_swap_buffers(&backend->egl, egl_surface, NULL); + wlr_egl_destroy_surface(&backend->egl, egl_surface); + } else { + wl_surface_attach(surface, NULL, 0, 0); + wl_surface_commit(surface); + } update_wl_output_cursor(output); return true; @@ -166,16 +138,9 @@ static void output_destroy(struct wlr_output *wlr_output) { wl_list_remove(&output->link); - if (output->cursor.buf_size != 0) { - assert(output->cursor.data); - assert(output->cursor.buffer); - assert(output->cursor.pool); - - wl_buffer_destroy(output->cursor.buffer); - munmap(output->cursor.data, output->cursor.buf_size); - wl_shm_pool_destroy(output->cursor.pool); + if (output->cursor.egl_window != NULL) { + wl_egl_window_destroy(output->cursor.egl_window); } - if (output->cursor.surface) { wl_surface_destroy(output->cursor.surface); } -- cgit v1.2.3