From ebdabc203072c855f9e28a679630c8decc6911ff Mon Sep 17 00:00:00 2001 From: Cedric Sodhi Date: Fri, 9 Mar 2018 15:17:15 +0100 Subject: Make X11 fully optional Make X11 Backend (in addition to XWayland) optional and small bug fix on XWayland includes. --- backend/backend.c | 2 ++ backend/meson.build | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'backend') diff --git a/backend/backend.c b/backend/backend.c index c67be617..58ac756e 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -94,6 +94,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { } } +#ifdef WLR_HAS_X11_BACKEND const char *x11_display = getenv("DISPLAY"); if (x11_display) { struct wlr_backend *x11_backend = @@ -101,6 +102,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { wlr_multi_backend_add(backend, x11_backend); return backend; } +#endif // Attempt DRM+libinput struct wlr_session *session = wlr_session_create(display); diff --git a/backend/meson.build b/backend/meson.build index c0ed76f1..a74ea024 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -24,7 +24,6 @@ backend_files = files( 'wayland/output.c', 'wayland/registry.c', 'wayland/wl_seat.c', - 'x11/backend.c', ) backend_deps = [ @@ -50,6 +49,10 @@ if conf_data.get('WLR_HAS_SYSTEMD', false) backend_deps += systemd endif +if conf_data.get('WLR_HAS_X11_BACKEND', false) + backend_files += files('x11/backend.c') +endif + if conf_data.get('WLR_HAS_ELOGIND', false) backend_files += files('session/logind.c') backend_deps += elogind -- cgit v1.2.3 From 51141dd11e9adfb1d26e22166adc2a4c9c10bcfe Mon Sep 17 00:00:00 2001 From: Cedric Sodhi Date: Fri, 23 Mar 2018 10:28:36 +0100 Subject: Minor corrections --- backend/backend.c | 4 +++- meson.build | 2 +- meson_options.txt | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'backend') diff --git a/backend/backend.c b/backend/backend.c index 58ac756e..96e155dc 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -11,7 +11,9 @@ #include #include #include -#include +#ifdef WLR_HAS_X11_BACKEND +# include +#endif #include void wlr_backend_init(struct wlr_backend *backend, diff --git a/meson.build b/meson.build index e7fa9890..e3c9a315 100644 --- a/meson.build +++ b/meson.build @@ -185,7 +185,7 @@ summary = [ ' systemd: @0@'.format(conf_data.get('WLR_HAS_SYSTEMD', false)), ' elogind: @0@'.format(conf_data.get('WLR_HAS_ELOGIND', false)), ' xwayland: @0@'.format(conf_data.get('WLR_HAS_XWAYLAND', false)), - ' x11_backend: @0@'.format(conf_data.get('WLR_HAS_X11BACKEND', false)), + ' x11_backend: @0@'.format(conf_data.get('WLR_HAS_X11_BACKEND', false)), ' xcb-icccm: @0@'.format(conf_data.get('WLR_HAS_XCB_ICCCM', false)), ' xcb-errors: @0@'.format(conf_data.get('WLR_HAS_XCB_ERRORS', false)), '----------------', diff --git a/meson_options.txt b/meson_options.txt index dae22b55..9e8567d0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,4 +3,4 @@ option('enable_systemd', type: 'combo', choices: ['auto', 'true', 'false'], valu option('enable_elogind', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Enable support for logind') option('enable_xcb_errors', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Use xcb-errors util library') option('enable_xwayland', type: 'boolean', value: true, description: 'Enable support X11 applications') -option('enable_x11_backend', type: 'boolean', value: false, description: 'Enable X11 backend') +option('enable_x11_backend', type: 'boolean', value: true, description: 'Enable X11 backend') -- cgit v1.2.3 From c63d94483b1e52817ca01ca82a867a78ebd39fa6 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 24 Mar 2018 18:30:28 -0400 Subject: Redesign wlr_texture - Textures are now immutable (apart from those created from raw pixels), no more invalid textures - Move all wl_drm stuff in wlr_renderer - Most of wlr_texture fields are now private - Remove some duplicated DMA-BUF code in the DRM backend - Add more assertions - Stride is now always given as bytes rather than pixels - Drop wl_shm functions Fun fact: this patch has been written 10,000 meters up in the air. --- backend/drm/drm.c | 23 +- backend/drm/renderer.c | 48 ++-- backend/wayland/output.c | 2 - examples/multi-pointer.c | 2 +- examples/output-layout.c | 6 +- examples/pointer.c | 4 +- examples/rotation.c | 6 +- examples/touch.c | 13 +- include/backend/drm/drm.h | 1 - include/render/gles2.h | 40 ++- include/wlr/render/egl.h | 16 +- include/wlr/render/interface.h | 41 ++-- include/wlr/render/wlr_renderer.h | 15 +- include/wlr/render/wlr_texture.h | 63 ++--- include/wlr/types/wlr_linux_dmabuf.h | 13 +- render/egl.c | 18 -- render/gles2/renderer.c | 124 ++++++---- render/gles2/texture.c | 464 ++++++++++++++--------------------- render/wlr_renderer.c | 43 +++- render/wlr_texture.c | 63 +++-- types/wlr_linux_dmabuf.c | 5 - types/wlr_output.c | 14 +- types/wlr_surface.c | 114 +++++---- types/wlr_xcursor_manager.c | 2 +- 24 files changed, 535 insertions(+), 605 deletions(-) (limited to 'backend') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 524e80bb..94bfbc96 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -181,9 +181,6 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) { if (plane->cursor_bo) { gbm_bo_destroy(plane->cursor_bo); } - if (plane->wlr_tex) { - wlr_texture_destroy(plane->wlr_tex); - } } free(drm->crtcs); @@ -586,12 +583,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_output_transform_invert(output->transform); wlr_matrix_projection(plane->matrix, plane->surf.width, plane->surf.height, transform); - - plane->wlr_tex = - wlr_render_texture_create(plane->surf.renderer->wlr_rend); - if (!plane->wlr_tex) { - return false; - } } struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; @@ -637,13 +628,18 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_drm_surface_make_current(&plane->surf, NULL); - wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, - stride, width, height, buf); - 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, plane->wlr_tex, plane->matrix, 0, 0, 1.0f); + wlr_render_texture(rend, texture, plane->matrix, 0, 0, 1.0f); wlr_renderer_end(rend); wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, @@ -651,6 +647,7 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_drm_surface_swap_buffers(&plane->surf, NULL); + wlr_texture_destroy(texture); gbm_bo_unmap(plane->cursor_bo, bo_data); } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index b2998b5f..2b50bb79 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -178,47 +178,33 @@ static void free_eglimage(struct gbm_bo *bo, void *data) { static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) { struct tex *tex = gbm_bo_get_user_data(bo); - if (tex) { + if (tex != NULL) { return tex->tex; } - // TODO: use wlr_texture_upload_dmabuf instead - - tex = malloc(sizeof(*tex)); - if (!tex) { - wlr_log_errno(L_ERROR, "Allocation failed"); + tex = calloc(1, sizeof(struct tex)); + if (tex == NULL) { return NULL; } - tex->egl = &renderer->egl; - - int dmabuf_fd = gbm_bo_get_fd(bo); - uint32_t width = gbm_bo_get_width(bo); - uint32_t height = gbm_bo_get_height(bo); - - EGLint attribs[] = { - EGL_WIDTH, width, - EGL_HEIGHT, height, - EGL_LINUX_DRM_FOURCC_EXT, gbm_bo_get_format(bo), - EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf_fd, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, gbm_bo_get_offset(bo, 0), - EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride_for_plane(bo, 0), - EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, - EGL_NONE, + struct wlr_dmabuf_buffer_attribs attribs = { + .n_planes = 1, + .width = gbm_bo_get_width(bo), + .height = gbm_bo_get_height(bo), + .format = gbm_bo_get_format(bo), }; - - tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT, - EGL_LINUX_DMA_BUF_EXT, NULL, attribs); - if (!tex->img) { - wlr_log(L_ERROR, "Failed to create EGL image"); - abort(); + attribs.offset[0] = 0; + attribs.stride[0] = gbm_bo_get_stride_for_plane(bo, 0); + attribs.modifier[0] = 0; + attribs.fd[0] = gbm_bo_get_fd(bo); + + tex->tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs); + if (tex->tex == NULL) { + free(tex); + return NULL; } - tex->tex = wlr_render_texture_create(renderer->wlr_rend); - wlr_texture_upload_eglimage(tex->tex, tex->img, width, height); - gbm_bo_set_user_data(bo, tex, free_eglimage); - return tex->tex; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index d528c888..c1fa638a 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -99,8 +99,6 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output, return true; } - stride *= 4; // stride is given in pixels, we need it in bytes - if (!backend->shm || !backend->pointer) { wlr_log(L_INFO, "cannot set cursor, no shm or pointer"); return false; diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 43ccdb66..1f869f50 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -149,7 +149,7 @@ static void handle_input_add(struct compositor_state *state, sample->compositor); struct wlr_xcursor_image *image = sample->xcursor->images[0]; - wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, image->width, image->height, image->hotspot_x, image->hotspot_y, 0); wl_list_insert(&sample->cursors, &cursor->link); diff --git a/examples/output-layout.c b/examples/output-layout.c index 45d896b0..c1392a30 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -197,9 +197,9 @@ int main(int argc, char *argv[]) { compositor_init(&compositor); state.renderer = wlr_gles2_renderer_create(compositor.backend); - state.cat_texture = wlr_render_texture_create(state.renderer); - wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888, - cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); if (!wlr_backend_start(compositor.backend)) { wlr_log(L_ERROR, "Failed to start backend"); diff --git a/examples/pointer.c b/examples/pointer.c index e8a0e892..9794e6e5 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -112,7 +112,7 @@ static void handle_output_add(struct output_state *ostate) { sample->compositor); struct wlr_xcursor_image *image = sample->xcursor->images[0]; - wlr_cursor_set_image(sample->cursor, image->buffer, image->width, + wlr_cursor_set_image(sample->cursor, image->buffer, image->width * 4, image->width, image->height, image->hotspot_x, image->hotspot_y, 0); wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y); @@ -324,7 +324,7 @@ int main(int argc, char *argv[]) { } struct wlr_xcursor_image *image = state.xcursor->images[0]; - wlr_cursor_set_image(state.cursor, image->buffer, image->width, + wlr_cursor_set_image(state.cursor, image->buffer, image->width * 4, image->width, image->height, image->hotspot_x, image->hotspot_y, 0); compositor_init(&compositor); diff --git a/examples/rotation.c b/examples/rotation.c index cbff09a1..dfafeeca 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -142,13 +142,13 @@ int main(int argc, char *argv[]) { wlr_log(L_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); } - state.cat_texture = wlr_render_texture_create(state.renderer); + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); if (!state.cat_texture) { wlr_log(L_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); } - wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888, - cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); if (!wlr_backend_start(compositor.backend)) { wlr_log(L_ERROR, "Failed to start backend"); diff --git a/examples/touch.c b/examples/touch.c index f9c496cf..7639165c 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -45,10 +45,13 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); + int tex_width, tex_height; + wlr_texture_get_size(sample->cat_texture, &tex_width, &tex_height); + struct touch_point *p; wl_list_for_each(p, &sample->touch_points, link) { - int x = (int)(p->x * width) - sample->cat_texture->width / 2; - int y = (int)(p->y * height) - sample->cat_texture->height / 2; + int x = (int)(p->x * width) - tex_width / 2; + int y = (int)(p->y * height) - tex_height / 2; wlr_render_texture(sample->renderer, sample->cat_texture, wlr_output->transform_matrix, x, y, 1.0f); } @@ -110,13 +113,13 @@ int main(int argc, char *argv[]) { wlr_log(L_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); } - state.cat_texture = wlr_render_texture_create(state.renderer); + state.cat_texture = wlr_texture_from_pixels(state.renderer, + WL_SHM_FORMAT_ARGB8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, + cat_tex.pixel_data); if (!state.cat_texture) { wlr_log(L_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); } - wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ARGB8888, - cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); if (!wlr_backend_start(compositor.backend)) { wlr_log(L_ERROR, "Failed to start backend"); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 26189340..cb10ad20 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -27,7 +27,6 @@ struct wlr_drm_plane { // Only used by cursor float matrix[9]; - struct wlr_texture *wlr_tex; struct gbm_bo *cursor_bo; bool cursor_enabled; int32_t cursor_hotspot_x, cursor_hotspot_y; diff --git a/include/render/gles2.h b/include/render/gles2.h index 43a8d648..09295415 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -38,21 +38,49 @@ struct wlr_gles2_renderer { } shaders; }; +enum wlr_gles2_texture_type { + WLR_GLES2_TEXTURE_GLTEX, + WLR_GLES2_TEXTURE_WL_DRM_GL, + WLR_GLES2_TEXTURE_WL_DRM_EXT, + WLR_GLES2_TEXTURE_DMABUF, +}; + struct wlr_gles2_texture { struct wlr_texture wlr_texture; - struct wlr_egl *egl; - GLuint tex_id; - const struct gles2_pixel_format *pixel_format; + struct wlr_gles2_renderer *renderer; + enum wlr_gles2_texture_type type; + int width, height; + bool has_alpha; + bool inverted_y; + + // Not set if WLR_GLES2_TEXTURE_GLTEX EGLImageKHR image; - GLenum target; + GLuint image_tex; + + union { + GLuint gl_tex; + struct wl_resource *wl_drm; + }; }; const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); const enum wl_shm_format *gles2_formats(size_t *len); -struct wlr_texture *gles2_texture_create(); -struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); +struct wlr_gles2_renderer *gles2_get_renderer( + struct wlr_renderer *wlr_renderer); +struct wlr_gles2_renderer *gles2_get_renderer_in_context( + struct wlr_renderer *wlr_renderer); + +struct wlr_gles2_texture *gles2_get_texture_in_context( + struct wlr_texture *wlr_texture); +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, + const void *data); +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, + struct wl_resource *data); +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, + struct wlr_dmabuf_buffer_attribs *attribs); void gles2_push_marker(const char *file, const char *func); void gles2_pop_marker(void); diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index aa429e8e..c214f127 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -46,37 +46,25 @@ void wlr_egl_finish(struct wlr_egl *egl); */ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display); -/** - * Refer to the eglQueryWaylandBufferWL extension function. - */ -bool wlr_egl_query_buffer(struct wlr_egl *egl, struct wl_resource *buf, - EGLint attrib, EGLint *value); - /** * Returns a surface for the given native window * The window must match the remote display the wlr_egl was created with. */ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window); -/** - * Creates an egl image from the given client buffer and attributes. - */ -EGLImageKHR wlr_egl_create_image(struct wlr_egl *egl, - EGLenum target, EGLClientBuffer buffer, const EGLint *attribs); - /** * Creates an egl image from the given dmabuf attributes. Check usability * of the dmabuf with wlr_egl_check_import_dmabuf once first. */ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_buffer_attribs *attributes); + struct wlr_dmabuf_buffer_attribs *attributes); /** * Try to import the given dmabuf. On success return true false otherwise. * If this succeeds the dmabuf can be used for rendering on a texture */ bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_buffer *dmabuf); + struct wlr_dmabuf_buffer *dmabuf); /** * Get the available dmabuf formats diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 7f25c0ff..212e4f7a 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -23,7 +23,6 @@ struct wlr_renderer_impl { void (*end)(struct wlr_renderer *renderer); void (*clear)(struct wlr_renderer *renderer, const float color[static 4]); void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); - struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer); bool (*render_texture_with_matrix)(struct wlr_renderer *renderer, struct wlr_texture *texture, const float matrix[static 9], float alpha); @@ -33,45 +32,39 @@ struct wlr_renderer_impl { const float color[static 4], const float matrix[static 9]); const enum wl_shm_format *(*formats)( struct wlr_renderer *renderer, size_t *len); - bool (*buffer_is_drm)(struct wlr_renderer *renderer, - struct wl_resource *buffer); + bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer, + struct wl_resource *resource); + void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer, + struct wl_resource *buffer, int *width, int *height); bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data); bool (*format_supported)(struct wlr_renderer *renderer, enum wl_shm_format fmt); + struct wlr_texture *(*texture_from_pixels)(struct wlr_renderer *renderer, + enum wl_shm_format fmt, uint32_t stride, uint32_t width, + uint32_t height, const void *data); + struct wlr_texture *(*texture_from_wl_drm)(struct wlr_renderer *renderer, + struct wl_resource *data); + struct wlr_texture *(*texture_from_dmabuf)(struct wlr_renderer *renderer, + struct wlr_dmabuf_buffer_attribs *attribs); void (*destroy)(struct wlr_renderer *renderer); }; void wlr_renderer_init(struct wlr_renderer *renderer, - const struct wlr_renderer_impl *impl); + const struct wlr_renderer_impl *impl); struct wlr_texture_impl { - bool (*upload_pixels)(struct wlr_texture *texture, - enum wl_shm_format format, int stride, int width, int height, - const unsigned char *pixels); - bool (*update_pixels)(struct wlr_texture *texture, - enum wl_shm_format format, int stride, int x, int y, - int width, int height, const unsigned char *pixels); - bool (*upload_shm)(struct wlr_texture *texture, uint32_t format, - struct wl_shm_buffer *shm); - bool (*update_shm)(struct wlr_texture *texture, uint32_t format, - int x, int y, int width, int height, struct wl_shm_buffer *shm); - bool (*upload_drm)(struct wlr_texture *texture, - struct wl_resource *drm_buf); - bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image, - uint32_t width, uint32_t height); - bool (*upload_dmabuf)(struct wlr_texture *texture, - struct wl_resource *dmabuf_resource); - void (*get_buffer_size)(struct wlr_texture *texture, - struct wl_resource *resource, int *width, int *height); + void (*get_size)(struct wlr_texture *texture, int *width, int *height); + bool (*write_pixels)(struct wlr_texture *texture, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, + uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, + uint32_t dst_y, const void *data); void (*destroy)(struct wlr_texture *texture); }; void wlr_texture_init(struct wlr_texture *texture, const struct wlr_texture_impl *impl); -void wlr_texture_get_buffer_size(struct wlr_texture *texture, - struct wl_resource *resource, int *width, int *height); #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 6f0d2ecc..decd14f5 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -1,8 +1,6 @@ #ifndef WLR_RENDER_WLR_RENDERER_H #define WLR_RENDER_WLR_RENDERER_H -#include -#include #include #include #include @@ -21,10 +19,6 @@ void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); * box. */ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); -/** - * Requests a texture handle from this renderer. - */ -struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); /** * Renders the requested texture. */ @@ -51,10 +45,15 @@ void wlr_render_colored_ellipse(struct wlr_renderer *r, const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r, size_t *len); /** - * Returns true if this wl_buffer is a DRM buffer. + * Returns true if this wl_buffer is a wl_drm buffer. */ -bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, +bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer, struct wl_resource *buffer); +/** + * Gets the width and height of a wl_drm buffer. + */ +void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer, + struct wl_resource *buffer, int *width, int *height); /** * Reads out of pixels of the currently bound surface into data. `stride` is in * bytes. diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 095097e6..ab361298 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -5,62 +5,49 @@ #include #include #include +#include +struct wlr_renderer; struct wlr_texture_impl; struct wlr_texture { const struct wlr_texture_impl *impl; - - bool valid; - uint32_t format; - int width, height; - bool inverted_y; - struct wl_signal destroy_signal; - struct wl_resource *resource; }; /** - * Copies pixels to this texture. The buffer is not accessed after this function - * returns. + * Create a new texture from raw pixel data. `stride` is in bytes. The returned + * texture is mutable. */ -bool wlr_texture_upload_pixels(struct wlr_texture *tex, - enum wl_shm_format format, int stride, int width, int height, - const unsigned char *pixels); +struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, + const void *data); + /** - * Copies pixels to this texture. The buffer is not accessed after this function - * returns. Under some circumstances, this function may re-upload the entire - * buffer - therefore, the entire buffer must be valid. + * Create a new texture from a wayland DRM resource. The returned texture is + * immutable. */ -bool wlr_texture_update_pixels(struct wlr_texture *surf, - enum wl_shm_format format, int stride, int x, int y, - int width, int height, const unsigned char *pixels); +struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer, + struct wl_resource *data); + /** - * Copies pixels from a wl_shm_buffer into this texture. The buffer is not - * accessed after this function returns. + * Create a new texture from a DMA-BUF. The returned texture is immutable. */ -bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format, - struct wl_shm_buffer *shm); +struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, + struct wlr_dmabuf_buffer_attribs *attribs); + /** - * Attaches the contents from the given wl_drm wl_buffer resource onto the - * texture. The wl_resource is not used after this call. - * Will fail (return false) if the given resource is no drm buffer. + * Get the texture width and height. */ -bool wlr_texture_upload_drm(struct wlr_texture *tex, - struct wl_resource *drm_buffer); - -bool wlr_texture_upload_eglimage(struct wlr_texture *tex, - EGLImageKHR image, uint32_t width, uint32_t height); +void wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height); -bool wlr_texture_upload_dmabuf(struct wlr_texture *tex, - struct wl_resource *dmabuf_resource); /** - * Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The - * buffer is not accessed after this function returns. Under some circumstances, - * this function may re-upload the entire buffer - therefore, the entire buffer - * must be valid. + * Update a texture with raw pixels. The texture must be mutable. */ -bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, - int x, int y, int width, int height, struct wl_shm_buffer *shm); +bool wlr_texture_write_pixels(struct wlr_texture *texture, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, + uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, + const void *data); + /** * Destroys this wlr_texture. */ diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h index 9d71e598..c06d8a87 100644 --- a/include/wlr/types/wlr_linux_dmabuf.h +++ b/include/wlr/types/wlr_linux_dmabuf.h @@ -11,6 +11,12 @@ #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) #endif +enum { + WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT = 1, + WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_INTERLACED = 2, + WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_BOTTOM_FIRST = 4, +}; + struct wlr_dmabuf_buffer_attribs { /* set via params_add */ int n_planes; @@ -22,7 +28,7 @@ struct wlr_dmabuf_buffer_attribs { int32_t width; int32_t height; uint32_t format; - uint32_t flags; /* enum zlinux_buffer_params_flags */ + uint32_t flags; }; struct wlr_dmabuf_buffer { @@ -52,11 +58,6 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( struct wl_resource *params_resource); -/** - * Returns true if the given dmabuf has y-axis inverted, false otherwise - */ -bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf); - /* the protocol interface */ struct wlr_linux_dmabuf { struct wl_global *wl_global; diff --git a/render/egl.c b/render/egl.c index e582b6d3..49b41eee 100644 --- a/render/egl.c +++ b/render/egl.c @@ -223,24 +223,6 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) return false; } -bool wlr_egl_query_buffer(struct wlr_egl *egl, struct wl_resource *buf, - int attrib, int *value) { - if (!eglQueryWaylandBufferWL) { - return false; - } - return eglQueryWaylandBufferWL(egl->display, buf, attrib, value); -} - -EGLImage wlr_egl_create_image(struct wlr_egl *egl, EGLenum target, - EGLClientBuffer buffer, const EGLint *attribs) { - if (!eglCreateImageKHR) { - return NULL; - } - - return eglCreateImageKHR(egl->display, egl->context, target, - buffer, attribs); -} - bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { if (!eglDestroyImageKHR) { return false; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 9403c0ed..dcda45e9 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -12,23 +12,27 @@ #include #include #include -#include "render/gles2.h" #include "glapi.h" +#include "render/gles2.h" static const struct wlr_renderer_impl renderer_impl; -static struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *gles2_get_renderer( struct wlr_renderer *wlr_renderer) { assert(wlr_renderer->impl == &renderer_impl); - struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)wlr_renderer; + return (struct wlr_gles2_renderer *)wlr_renderer; +} + +struct wlr_gles2_renderer *gles2_get_renderer_in_context( + struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); assert(eglGetCurrentContext() == renderer->egl->context); return renderer; } static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, uint32_t height) { - gles2_get_renderer(wlr_renderer); + gles2_get_renderer_in_context(wlr_renderer); GLES2_DEBUG_PUSH; @@ -45,13 +49,13 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, } static void gles2_end(struct wlr_renderer *wlr_renderer) { - gles2_get_renderer(wlr_renderer); + gles2_get_renderer_in_context(wlr_renderer); // no-op } static void gles2_clear(struct wlr_renderer *wlr_renderer, const float color[static 4]) { - gles2_get_renderer(wlr_renderer); + gles2_get_renderer_in_context(wlr_renderer); GLES2_DEBUG_PUSH; glClearColor(color[0], color[1], color[2], color[3]); @@ -61,7 +65,7 @@ static void gles2_clear(struct wlr_renderer *wlr_renderer, static void gles2_scissor(struct wlr_renderer *wlr_renderer, struct wlr_box *box) { - gles2_get_renderer(wlr_renderer); + gles2_get_renderer_in_context(wlr_renderer); GLES2_DEBUG_PUSH; if (box != NULL) { @@ -73,14 +77,6 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, GLES2_DEBUG_POP; } -static struct wlr_texture *gles2_renderer_texture_create( - struct wlr_renderer *wlr_renderer) { - assert(wlr_renderer->impl == &renderer_impl); - struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)wlr_renderer; - return gles2_texture_create(renderer->egl); -} - static void draw_quad() { GLfloat verts[] = { 1, 0, // top right @@ -107,21 +103,28 @@ static void draw_quad() { glDisableVertexAttribArray(1); } -static bool gles2_render_texture_with_matrix( - struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, - const float matrix[static 9], float alpha) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - if (!wlr_texture->valid) { - wlr_log(L_ERROR, "attempt to render invalid texture"); - return false; - } - - GLuint prog = renderer->shaders.tex_rgba; - if (texture->target == GL_TEXTURE_EXTERNAL_OES) { +static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, + struct wlr_texture *wlr_texture, const float matrix[static 9], + float alpha) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + struct wlr_gles2_texture *texture = + gles2_get_texture_in_context(wlr_texture); + + GLuint prog; + GLenum target; + switch (texture->type) { + case WLR_GLES2_TEXTURE_GLTEX: + case WLR_GLES2_TEXTURE_WL_DRM_GL: + prog = texture->has_alpha ? renderer->shaders.tex_rgba : + renderer->shaders.tex_rgbx; + target = GL_TEXTURE_2D; + break; + case WLR_GLES2_TEXTURE_WL_DRM_EXT: + case WLR_GLES2_TEXTURE_DMABUF: prog = renderer->shaders.tex_ext; - } else if (!texture->pixel_format->has_alpha) { - prog = renderer->shaders.tex_rgbx; + target = GL_TEXTURE_EXTERNAL_OES; + break; } // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set @@ -130,15 +133,23 @@ static bool gles2_render_texture_with_matrix( wlr_matrix_transpose(transposition, matrix); GLES2_DEBUG_PUSH; - glBindTexture(texture->target, texture->tex_id); - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + GLuint tex_id = texture->type == WLR_GLES2_TEXTURE_GLTEX ? + texture->gl_tex : texture->image_tex; + glActiveTexture(GL_TEXTURE0); + glBindTexture(target, tex_id); + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glUseProgram(prog); glUniformMatrix3fv(0, 1, GL_FALSE, transposition); - glUniform1i(1, wlr_texture->inverted_y); + glUniform1i(1, texture->inverted_y); glUniform1f(3, alpha); + draw_quad(); + GLES2_DEBUG_POP; return true; } @@ -146,7 +157,8 @@ static bool gles2_render_texture_with_matrix( static void gles2_render_quad(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE @@ -163,7 +175,8 @@ static void gles2_render_quad(struct wlr_renderer *wlr_renderer, static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE @@ -183,20 +196,38 @@ static const enum wl_shm_format *gles2_renderer_formats( return gles2_formats(len); } -static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, - struct wl_resource *buffer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); +static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, + struct wl_resource *resource) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + + if (!eglQueryWaylandBufferWL) { + return false; + } + + EGLint fmt; + return eglQueryWaylandBufferWL(renderer->egl->display, resource, + EGL_TEXTURE_FORMAT, &fmt); +} + +static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer, + struct wl_resource *buffer, int *width, int *height) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + + if (!eglQueryWaylandBufferWL) { + return; + } - EGLint format; - return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, - &format); + eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_WIDTH, width); + eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_HEIGHT, height); } static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data) { - gles2_get_renderer(wlr_renderer); + gles2_get_renderer_in_context(wlr_renderer); const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); if (fmt == NULL) { @@ -254,14 +285,17 @@ static const struct wlr_renderer_impl renderer_impl = { .end = gles2_end, .clear = gles2_clear, .scissor = gles2_scissor, - .texture_create = gles2_renderer_texture_create, .render_texture_with_matrix = gles2_render_texture_with_matrix, .render_quad = gles2_render_quad, .render_ellipse = gles2_render_ellipse, .formats = gles2_renderer_formats, - .buffer_is_drm = gles2_buffer_is_drm, + .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, + .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .read_pixels = gles2_read_pixels, .format_supported = gles2_format_supported, + .texture_from_pixels = gles2_texture_from_pixels, + .texture_from_wl_drm = gles2_texture_from_wl_drm, + .texture_from_dmabuf = gles2_texture_from_dmabuf, }; void gles2_push_marker(const char *file, const char *func) { diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 46193c78..82effd71 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -10,366 +10,262 @@ #include #include #include +#include "glapi.h" #include "render/gles2.h" #include "util/signal.h" -static struct gles2_pixel_format external_pixel_format = { - .wl_format = 0, - .depth = 0, - .bpp = 0, - .gl_format = 0, - .gl_type = 0, -}; - -static void gles2_texture_ensure(struct wlr_gles2_texture *texture, - GLenum target) { - if (texture->tex_id) { - return; - } - texture->target = target; - glGenTextures(1, &texture->tex_id); - glBindTexture(target, texture->tex_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - static const struct wlr_texture_impl texture_impl; -struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) { +static struct wlr_gles2_texture *gles2_get_texture( + struct wlr_texture *wlr_texture) { assert(wlr_texture->impl == &texture_impl); return (struct wlr_gles2_texture *)wlr_texture; } -static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture, - enum wl_shm_format format, int stride, int width, int height, - const unsigned char *pixels) { +struct wlr_gles2_texture *gles2_get_texture_in_context( + struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - - const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); - if (!fmt || !fmt->gl_format) { - wlr_log(L_ERROR, "No supported pixel format for this texture"); - return false; - } - texture->wlr_texture.width = width; - texture->wlr_texture.height = height; - texture->wlr_texture.format = format; - texture->pixel_format = fmt; - - GLES2_DEBUG_PUSH; - gles2_texture_ensure(texture, GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); - glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, - fmt->gl_format, fmt->gl_type, pixels); - GLES2_DEBUG_POP; - - texture->wlr_texture.valid = true; - return true; + assert(eglGetCurrentContext() == texture->renderer->egl->context); + return texture; } -static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture, - enum wl_shm_format format, int stride, int x, int y, - int width, int height, const unsigned char *pixels) { +static void gles2_texture_get_size(struct wlr_texture *wlr_texture, int *width, + int *height) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - - // TODO: Test if the unpack subimage extension is supported and adjust the - // upload strategy if not - if (!texture->wlr_texture.valid - || texture->wlr_texture.format != format - /* || unpack not supported */) { - return gles2_texture_upload_pixels(&texture->wlr_texture, format, - stride, width, height, pixels); - } - const struct gles2_pixel_format *fmt = texture->pixel_format; - GLES2_DEBUG_PUSH; - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); - glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); - glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format, - fmt->gl_type, pixels); - glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); - glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); - GLES2_DEBUG_POP; - return true; + *width = texture->width; + *height = texture->height; } -static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture, - uint32_t format, struct wl_shm_buffer *buffer) { - struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); +static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, + uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, + uint32_t dst_y, const void *data) { + struct wlr_gles2_texture *texture = + gles2_get_texture_in_context(wlr_texture); + + if (texture->type != WLR_GLES2_TEXTURE_GLTEX) { + wlr_log(L_ERROR, "Cannot write pixels to immutable texture"); + return false; + } - const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); - if (!fmt || !fmt->gl_format) { - wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture", - format); + const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); + if (fmt == NULL) { + wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt); return false; } - wl_shm_buffer_begin_access(buffer); - uint8_t *pixels = wl_shm_buffer_get_data(buffer); - int width = wl_shm_buffer_get_width(buffer); - int height = wl_shm_buffer_get_height(buffer); - int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8); - texture->wlr_texture.width = width; - texture->wlr_texture.height = height; - texture->wlr_texture.format = format; - texture->pixel_format = fmt; + // TODO: what if the unpack subimage extension isn't supported? GLES2_DEBUG_PUSH; - gles2_texture_ensure(texture, GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); - glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); - glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); - glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, - fmt->gl_format, fmt->gl_type, pixels); - GLES2_DEBUG_POP; - texture->wlr_texture.valid = true; - wl_shm_buffer_end_access(buffer); - return true; -} + glBindTexture(GL_TEXTURE_2D, texture->gl_tex); -static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture, - uint32_t format, int x, int y, int width, int height, - struct wl_shm_buffer *buffer) { - struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8)); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y); - // TODO: Test if the unpack subimage extension is supported and adjust the - // upload strategy if not - assert(texture); - if (!texture->wlr_texture.valid - || texture->wlr_texture.format != format - /* || unpack not supported */) { - return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer); - } - const struct gles2_pixel_format *fmt = texture->pixel_format; - wl_shm_buffer_begin_access(buffer); - uint8_t *pixels = wl_shm_buffer_get_data(buffer); - int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8); + glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height, + fmt->gl_format, fmt->gl_type, data); - GLES2_DEBUG_PUSH; - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); - glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); - glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, - fmt->gl_format, fmt->gl_type, pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); - GLES2_DEBUG_POP; - - wl_shm_buffer_end_access(buffer); + GLES2_DEBUG_POP; return true; } -static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture, - struct wl_resource *buf) { - struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); - if (!glEGLImageTargetTexture2DOES) { - return false; +static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { + if (wlr_texture == NULL) { + return; } - EGLint format; - if (!wlr_egl_query_buffer(tex->egl, buf, EGL_TEXTURE_FORMAT, &format)) { - wlr_log(L_INFO, "upload_drm called with no drm buffer"); - return false; - } + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH, - (EGLint*)&tex->wlr_texture.width); - wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT, - (EGLint*)&tex->wlr_texture.height); + wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL); - EGLint inverted_y; - if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, - &inverted_y)) { - tex->wlr_texture.inverted_y = !!inverted_y; + GLES2_DEBUG_PUSH; + + if (texture->image_tex) { + glDeleteTextures(1, &texture->image_tex); + } + if (texture->image) { + assert(eglDestroyImageKHR); + eglDestroyImageKHR(texture->renderer->egl->display, texture->image); } - GLenum target; - const struct gles2_pixel_format *pf; - switch (format) { - case EGL_TEXTURE_RGB: - case EGL_TEXTURE_RGBA: - target = GL_TEXTURE_2D; - pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); - break; - case EGL_TEXTURE_EXTERNAL_WL: - target = GL_TEXTURE_EXTERNAL_OES; - pf = &external_pixel_format; - break; - default: - wlr_log(L_ERROR, "invalid/unsupported egl buffer format"); - return false; + if (texture->type == WLR_GLES2_TEXTURE_GLTEX) { + glDeleteTextures(1, &texture->gl_tex); } - GLES2_DEBUG_PUSH; - gles2_texture_ensure(tex, target); - glBindTexture(GL_TEXTURE_2D, tex->tex_id); GLES2_DEBUG_POP; - EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; + free(texture); +} - if (tex->image) { - wlr_egl_destroy_image(tex->egl, tex->image); +static const struct wlr_texture_impl texture_impl = { + .get_size = gles2_texture_get_size, + .write_pixels = gles2_texture_write_pixels, + .destroy = gles2_texture_destroy, +}; + +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, + uint32_t height, const void *data) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + + const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); + if (fmt == NULL) { + wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt); + return NULL; } - tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL, - (EGLClientBuffer*) buf, attribs); - if (!tex->image) { - wlr_log(L_ERROR, "failed to create EGL image"); - return false; + struct wlr_gles2_texture *texture = + calloc(1, sizeof(struct wlr_gles2_texture)); + if (texture == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + return NULL; } + wlr_texture_init(&texture->wlr_texture, &texture_impl); + texture->renderer = renderer; + texture->width = width; + texture->height = height; + texture->type = WLR_GLES2_TEXTURE_GLTEX; + texture->has_alpha = fmt->has_alpha; GLES2_DEBUG_PUSH; - glActiveTexture(GL_TEXTURE0); - glBindTexture(target, tex->tex_id); - glEGLImageTargetTexture2DOES(target, tex->image); - GLES2_DEBUG_POP; - tex->wlr_texture.valid = true; - tex->pixel_format = pf; - - return true; -} -static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture, - EGLImageKHR image, uint32_t width, uint32_t height) { - struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); + glGenTextures(1, &texture->gl_tex); + glBindTexture(GL_TEXTURE_2D, texture->gl_tex); - tex->image = image; - tex->pixel_format = &external_pixel_format; - tex->wlr_texture.valid = true; - tex->wlr_texture.width = width; - tex->wlr_texture.height = height; + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8)); + glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + fmt->gl_format, fmt->gl_type, data); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); - GLES2_DEBUG_PUSH; - gles2_texture_ensure(tex, GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image); GLES2_DEBUG_POP; - - return true; + return (struct wlr_texture *)texture; } -static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, - struct wl_resource *dmabuf_resource) { - struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource); +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, + struct wl_resource *data) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - if (!tex->egl->egl_exts.dmabuf_import) { - wlr_log(L_ERROR, "Want dmabuf but extension not present"); - return false; + if (!eglQueryWaylandBufferWL || !eglCreateImageKHR || + !glEGLImageTargetTexture2DOES) { + return NULL; } - tex->wlr_texture.width = dmabuf->attributes.width; - tex->wlr_texture.height = dmabuf->attributes.height; + EGLint fmt; + if (!eglQueryWaylandBufferWL(renderer->egl->display, data, + EGL_TEXTURE_FORMAT, &fmt)) { + return NULL; + } - if (tex->image) { - wlr_egl_destroy_image(tex->egl, tex->image); + EGLint width, height; + eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_WIDTH, &width); + eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_HEIGHT, &height); + + EGLint inverted_y; + if (!eglQueryWaylandBufferWL(renderer->egl->display, data, + EGL_WAYLAND_Y_INVERTED_WL, &inverted_y)) { + inverted_y = 0; } - if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { - wlr_texture->inverted_y = true; + struct wlr_gles2_texture *texture = + calloc(1, sizeof(struct wlr_gles2_texture)); + if (texture == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + return NULL; } + wlr_texture_init(&texture->wlr_texture, &texture_impl); + texture->renderer = renderer; + texture->width = width; + texture->height = height; + texture->wl_drm = data; + texture->inverted_y = !!inverted_y; GLenum target; - const struct gles2_pixel_format *pf; - if (dmabuf->attributes.n_planes > 1) { - target = GL_TEXTURE_EXTERNAL_OES; - pf = &external_pixel_format; - } else { + switch (fmt) { + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: target = GL_TEXTURE_2D; - pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); + texture->type = WLR_GLES2_TEXTURE_WL_DRM_GL; + texture->has_alpha = fmt == EGL_TEXTURE_RGBA; + break; + case EGL_TEXTURE_EXTERNAL_WL: + target = GL_TEXTURE_EXTERNAL_OES; + texture->type = WLR_GLES2_TEXTURE_WL_DRM_EXT; + texture->has_alpha = true; + break; + default: + wlr_log(L_ERROR, "Invalid or unsupported EGL buffer format"); + free(texture); + return NULL; } - GLES2_DEBUG_PUSH; - gles2_texture_ensure(tex, target); - glBindTexture(target, tex->tex_id); - tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); - glActiveTexture(GL_TEXTURE0); - glEGLImageTargetTexture2DOES(target, tex->image); - GLES2_DEBUG_POP; - tex->pixel_format = pf; - tex->wlr_texture.valid = true; - return true; -} -static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct - wl_resource *resource, int *width, int *height) { - if (!wlr_dmabuf_resource_is_buffer(resource)) { - return false; + EGLint attribs[] = { + EGL_WAYLAND_PLANE_WL, 0, + EGL_NONE, + }; + texture->image = eglCreateImageKHR(renderer->egl->display, + renderer->egl->context, EGL_WAYLAND_BUFFER_WL, data, attribs); + if (texture->image == NULL) { + free(texture); + return NULL; } - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); - *width = dmabuf->attributes.width; - *height = dmabuf->attributes.height; - return true; -} - -static void gles2_texture_get_buffer_size(struct wlr_texture *texture, - struct wl_resource *resource, int *width, int *height) { - struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource); - if (!buffer) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture; - if (!glEGLImageTargetTexture2DOES) { - return; - } - if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH, - (EGLint*)width)) { - if (!gles2_texture_get_dmabuf_size(texture, resource, width, - height)) { - wlr_log(L_ERROR, "could not get size of the buffer"); - return; - } - } - wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height); + GLES2_DEBUG_PUSH; - return; - } + glGenTextures(1, &texture->image_tex); + glBindTexture(target, texture->image_tex); + glEGLImageTargetTexture2DOES(target, texture->image); - *width = wl_shm_buffer_get_width(buffer); - *height = wl_shm_buffer_get_height(buffer); + GLES2_DEBUG_POP; + return (struct wlr_texture *)texture; } -static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { - struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, + struct wlr_dmabuf_buffer_attribs *attribs) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, - &texture->wlr_texture); - if (texture->tex_id) { - GLES2_DEBUG_PUSH; - glDeleteTextures(1, &texture->tex_id); - GLES2_DEBUG_POP; + if (!glEGLImageTargetTexture2DOES) { + return NULL; } - if (texture->image) { - wlr_egl_destroy_image(texture->egl, texture->image); + if (!renderer->egl->egl_exts.dmabuf_import) { + wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension " + "unavailable"); + return NULL; } - free(texture); -} - -static const struct wlr_texture_impl texture_impl = { - .upload_pixels = gles2_texture_upload_pixels, - .update_pixels = gles2_texture_update_pixels, - .upload_shm = gles2_texture_upload_shm, - .update_shm = gles2_texture_update_shm, - .upload_drm = gles2_texture_upload_drm, - .upload_dmabuf = gles2_texture_upload_dmabuf, - .upload_eglimage = gles2_texture_upload_eglimage, - .get_buffer_size = gles2_texture_get_buffer_size, - .destroy = gles2_texture_destroy, -}; - -struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) { - struct wlr_gles2_texture *texture; - if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) { + struct wlr_gles2_texture *texture = + calloc(1, sizeof(struct wlr_gles2_texture)); + if (texture == NULL) { + wlr_log(L_ERROR, "Allocation failed"); return NULL; } wlr_texture_init(&texture->wlr_texture, &texture_impl); - texture->egl = egl; - return &texture->wlr_texture; + texture->renderer = renderer; + texture->width = attribs->width; + texture->height = attribs->height; + texture->type = WLR_GLES2_TEXTURE_DMABUF; + texture->has_alpha = true; + texture->inverted_y = + (attribs->flags & WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT) != 0; + + texture->image = wlr_egl_create_image_from_dmabuf(renderer->egl, attribs); + if (texture->image == NULL) { + free(texture); + return NULL; + } + + GLES2_DEBUG_PUSH; + + glGenTextures(1, &texture->image_tex); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->image_tex); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, texture->image); + + GLES2_DEBUG_POP; + return (struct wlr_texture *)texture; } diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 622aa1dd..d5a4d19f 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,15 @@ void wlr_renderer_init(struct wlr_renderer *renderer, const struct wlr_renderer_impl *impl) { + assert(impl->begin); + assert(impl->clear); + assert(impl->scissor); + assert(impl->render_texture_with_matrix); + assert(impl->render_quad); + assert(impl->render_ellipse); + assert(impl->formats); + assert(impl->format_supported); + assert(impl->texture_from_pixels); renderer->impl = impl; } @@ -22,7 +32,9 @@ void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { } void wlr_renderer_end(struct wlr_renderer *r) { - r->impl->end(r); + if (r->impl->end) { + r->impl->end(r); + } } void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) { @@ -33,16 +45,15 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) { r->impl->scissor(r, box); } -struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { - return r->impl->texture_create(r); -} - bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, const float projection[static 9], int x, int y, float alpha) { + int width, height; + wlr_texture_get_size(texture, &width, &height); + float mat[9]; wlr_matrix_identity(mat); wlr_matrix_translate(mat, x, y); - wlr_matrix_scale(mat, texture->width, texture->height); + wlr_matrix_scale(mat, width, height); wlr_matrix_multiply(mat, projection, mat); return wlr_render_texture_with_matrix(r, texture, mat, alpha); @@ -69,15 +80,29 @@ const enum wl_shm_format *wlr_renderer_get_formats( return r->impl->formats(r, len); } -bool wlr_renderer_buffer_is_drm(struct wlr_renderer *r, - struct wl_resource *buffer) { - return r->impl->buffer_is_drm(r, buffer); +bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *r, + struct wl_resource *resource) { + if (!r->impl->resource_is_wl_drm_buffer) { + return false; + } + return r->impl->resource_is_wl_drm_buffer(r, resource); +} + +void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *r, + struct wl_resource *buffer, int *width, int *height) { + if (!r->impl->wl_drm_buffer_get_size) { + return; + } + return r->impl->wl_drm_buffer_get_size(r, buffer, width, height); } bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data) { + if (!r->impl->read_pixels) { + return false; + } return r->impl->read_pixels(r, fmt, stride, width, height, src_x, src_y, dst_x, dst_y, data); } diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 33c91822..9aecfd98 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,8 +6,9 @@ void wlr_texture_init(struct wlr_texture *texture, const struct wlr_texture_impl *impl) { + assert(impl->get_size); + assert(impl->write_pixels); texture->impl = impl; - wl_signal_init(&texture->destroy_signal); } void wlr_texture_destroy(struct wlr_texture *texture) { @@ -17,45 +19,38 @@ void wlr_texture_destroy(struct wlr_texture *texture) { } } -bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format, - int stride, int width, int height, const unsigned char *pixels) { - return texture->impl->upload_pixels(texture, format, stride, - width, height, pixels); +struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, + uint32_t height, const void *data) { + return renderer->impl->texture_from_pixels(renderer, wl_fmt, stride, width, + height, data); } -bool wlr_texture_update_pixels(struct wlr_texture *texture, - enum wl_shm_format format, int stride, int x, int y, - int width, int height, const unsigned char *pixels) { - return texture->impl->update_pixels(texture, format, stride, x, y, - width, height, pixels); -} - -bool wlr_texture_upload_shm(struct wlr_texture *texture, uint32_t format, - struct wl_shm_buffer *shm) { - return texture->impl->upload_shm(texture, format, shm); -} - -bool wlr_texture_update_shm(struct wlr_texture *texture, uint32_t format, - int x, int y, int width, int height, struct wl_shm_buffer *shm) { - return texture->impl->update_shm(texture, format, x, y, width, height, shm); -} - -bool wlr_texture_upload_drm(struct wlr_texture *texture, - struct wl_resource *drm_buffer) { - return texture->impl->upload_drm(texture, drm_buffer); +struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer, + struct wl_resource *data) { + if (!renderer->impl->texture_from_wl_drm) { + return NULL; + } + return renderer->impl->texture_from_wl_drm(renderer, data); } -bool wlr_texture_upload_eglimage(struct wlr_texture *texture, - EGLImageKHR image, uint32_t width, uint32_t height) { - return texture->impl->upload_eglimage(texture, image, width, height); +struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, + struct wlr_dmabuf_buffer_attribs *attribs) { + if (!renderer->impl->texture_from_dmabuf) { + return NULL; + } + return renderer->impl->texture_from_dmabuf(renderer, attribs); } -bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, - struct wl_resource *dmabuf_resource) { - return texture->impl->upload_dmabuf(texture, dmabuf_resource); +void wlr_texture_get_size(struct wlr_texture *texture, int *width, + int *height) { + return texture->impl->get_size(texture, width, height); } -void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource - *resource, int *width, int *height) { - texture->impl->get_buffer_size(texture, resource, width, height); +bool wlr_texture_write_pixels(struct wlr_texture *texture, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, + uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, + uint32_t dst_y, const void *data) { + return texture->impl->write_pixels(texture, wl_fmt, stride, width, height, + src_x, src_y, dst_x, dst_y, data); } diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index a61d0ea5..d2a8bea9 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -19,11 +19,6 @@ static const struct wl_buffer_interface wl_buffer_impl = { wl_buffer_destroy, }; -bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf) { - return dmabuf->attributes.flags - & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; -} - bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface, &wl_buffer_impl)) { diff --git a/types/wlr_output.c b/types/wlr_output.c index e30c3b78..f95a7ea0 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -731,15 +731,11 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, return true; } - if (cursor->texture == NULL) { - cursor->texture = wlr_render_texture_create(renderer); - if (cursor->texture == NULL) { - return false; - } - } + wlr_texture_destroy(cursor->texture); - return wlr_texture_upload_pixels(cursor->texture, WL_SHM_FORMAT_ARGB8888, + cursor->texture = wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, pixels); + return cursor->texture != NULL; } static void output_cursor_commit(struct wlr_output_cursor *cursor) { @@ -901,9 +897,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { } cursor->output->hardware_cursor = NULL; } - if (cursor->texture != NULL) { - wlr_texture_destroy(cursor->texture); - } + wlr_texture_destroy(cursor->texture); wl_list_remove(&cursor->link); free(cursor); } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index e700853a..3be7bdfc 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -155,8 +155,24 @@ static bool wlr_surface_update_size(struct wlr_surface *surface, int scale = state->scale; enum wl_output_transform transform = state->transform; - wlr_texture_get_buffer_size(surface->texture, state->buffer, - &state->buffer_width, &state->buffer_height); + struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer); + if (buf != NULL) { + state->buffer_width = wl_shm_buffer_get_width(buf); + state->buffer_height = wl_shm_buffer_get_height(buf); + } else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, + state->buffer)) { + wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer, + &state->buffer_width, &state->buffer_height); + } else if (wlr_dmabuf_resource_is_buffer(state->buffer)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(state->buffer); + state->buffer_width = dmabuf->attributes.width; + state->buffer_height = dmabuf->attributes.height; + } else { + wlr_log(L_ERROR, "Unknown buffer handle attached"); + state->buffer_width = 0; + state->buffer_height = 0; + } int width = state->buffer_width / scale; int height = state->buffer_height / scale; @@ -316,51 +332,65 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { static void wlr_surface_apply_damage(struct wlr_surface *surface, bool reupload_buffer) { - if (!surface->current->buffer) { + struct wl_resource *resource = surface->current->buffer; + if (resource == NULL) { return; } - struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current->buffer); - if (!buffer) { - if (wlr_renderer_buffer_is_drm(surface->renderer, - surface->current->buffer)) { - wlr_texture_upload_drm(surface->texture, surface->current->buffer); - goto release; - } else if (wlr_dmabuf_resource_is_buffer(surface->current->buffer)) { - wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer); - goto release; - } else { - wlr_log(L_INFO, "Unknown buffer handle attached"); - return; - } - } - uint32_t format = wl_shm_buffer_get_format(buffer); - if (reupload_buffer) { - wlr_texture_upload_shm(surface->texture, format, buffer); - } else { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->buffer_damage); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - surface->current->buffer_width, surface->current->buffer_height); - - int n; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); - for (int i = 0; i < n; ++i) { - pixman_box32_t rect = rects[i]; - if (!wlr_texture_update_shm(surface->texture, format, - rect.x1, rect.y1, - rect.x2 - rect.x1, - rect.y2 - rect.y1, - buffer)) { - break; + struct wl_shm_buffer *buf = wl_shm_buffer_get(resource); + if (buf != NULL) { + wl_shm_buffer_begin_access(buf); + + enum wl_shm_format fmt = wl_shm_buffer_get_format(buf); + int32_t stride = wl_shm_buffer_get_stride(buf); + int32_t width = wl_shm_buffer_get_width(buf); + int32_t height = wl_shm_buffer_get_height(buf); + void *data = wl_shm_buffer_get_data(buf); + + if (surface->texture == NULL || reupload_buffer) { + wlr_texture_destroy(surface->texture); + surface->texture = wlr_texture_from_pixels(surface->renderer, fmt, + stride, width, height, data); + } else { + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, &surface->current->buffer_damage); + pixman_region32_intersect_rect(&damage, &damage, 0, 0, + surface->current->buffer_width, + surface->current->buffer_height); + + int n; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); + for (int i = 0; i < n; ++i) { + pixman_box32_t *r = &rects[i]; + if (!wlr_texture_write_pixels(surface->texture, fmt, stride, + r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, + r->x1, r->y1, data)) { + break; + } } + + pixman_region32_fini(&damage); } - pixman_region32_fini(&damage); + wl_shm_buffer_end_access(buf); + } else if (!surface->texture || reupload_buffer) { + wlr_texture_destroy(surface->texture); + + if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) { + surface->texture = + wlr_texture_from_wl_drm(surface->renderer, resource); + } else if (wlr_dmabuf_resource_is_buffer(resource)) { + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); + surface->texture = + wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes); + } else { + surface->texture = NULL; + wlr_log(L_ERROR, "Unknown buffer handle attached"); + } } -release: wlr_surface_state_release_buffer(surface->current); } @@ -375,7 +405,8 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { wlr_surface_move_state(surface, surface->pending, surface->current); if (null_buffer_commit) { - surface->texture->valid = false; + wlr_texture_destroy(surface->texture); + surface->texture = NULL; } bool reupload_buffer = oldw != surface->current->buffer_width || @@ -611,7 +642,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, } wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, res); surface->renderer = renderer; - surface->texture = wlr_render_texture_create(renderer); surface->resource = res; surface->current = wlr_surface_state_create(); @@ -628,7 +658,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, } bool wlr_surface_has_buffer(struct wlr_surface *surface) { - return surface->texture && surface->texture->valid; + return surface->texture != NULL; } int wlr_surface_set_role(struct wlr_surface *surface, const char *role, diff --git a/types/wlr_xcursor_manager.c b/types/wlr_xcursor_manager.c index d81b639d..7333a7a1 100644 --- a/types/wlr_xcursor_manager.c +++ b/types/wlr_xcursor_manager.c @@ -77,7 +77,7 @@ void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, } struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(cursor, image->buffer, image->width, + wlr_cursor_set_image(cursor, image->buffer, image->width * 4, image->width, image->height, image->hotspot_x, image->hotspot_y, theme->scale); } -- cgit v1.2.3 From c7f8b28d8d48a9857659ad73935a3b513e588d4c Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Mon, 26 Mar 2018 10:48:30 +0200 Subject: Fix use-after-free in x11 backend during shutdown The xcb_connection_t instance that is used here comes from XGetXCBConnection(), is created by XOpenDisplay(), and is owned by the returned Display*. Calling xcb_disconnect() directly on it leads to various use-after-frees during shutdown, as reported by valgrind. The first one of the about 30 errors is: Invalid read of size 4 at 0x71F2051: xcb_take_socket (in /usr/lib64/libxcb.so.1.1.0) by 0x78551DD: ??? (in /usr/lib64/libX11.so.6.3.0) by 0x7855A14: _XFlush (in /usr/lib64/libX11.so.6.3.0) by 0x7858504: _XGetRequest (in /usr/lib64/libX11.so.6.3.0) by 0x7838966: XFreeGC (in /usr/lib64/libX11.so.6.3.0) by 0x783238B: XCloseDisplay (in /usr/lib64/libX11.so.6.3.0) by 0x4E680C2: wlr_x11_backend_destroy (backend.c:333) by 0x4E57E94: wlr_backend_destroy (backend.c:39) by 0x4E629FB: multi_backend_destroy (backend.c:47) by 0x4E62B5A: handle_display_destroy (backend.c:90) by 0x50B7E9F: ??? (in /usr/lib64/libwayland-server.so.0.1.0) by 0x50B8476: wl_display_destroy (in /usr/lib64/libwayland-server.so.0.1.0) Address 0xc14dda0 is 0 bytes inside a block of size 21,152 free'd at 0x4C2DD18: free (vg_replace_malloc.c:530) by 0x4E680A5: wlr_x11_backend_destroy (backend.c:330) by 0x4E57E94: wlr_backend_destroy (backend.c:39) by 0x4E629FB: multi_backend_destroy (backend.c:47) by 0x4E62B5A: handle_display_destroy (backend.c:90) by 0x50B7E9F: ??? (in /usr/lib64/libwayland-server.so.0.1.0) by 0x50B8476: wl_display_destroy (in /usr/lib64/libwayland-server.so.0.1.0) by 0x40C54E: main (main.c:84) Block was alloc'd at at 0x4C2EA1E: calloc (vg_replace_malloc.c:711) by 0x71F0C60: xcb_connect_to_fd (in /usr/lib64/libxcb.so.1.1.0) by 0x71F4BD4: xcb_connect_to_display_with_auth_info (in /usr/lib64/libxcb.so.1.1.0) by 0x7854AA1: _XConnectXCB (in /usr/lib64/libX11.so.6.3.0) by 0x7845481: XOpenDisplay (in /usr/lib64/libX11.so.6.3.0) by 0x4E681B6: wlr_x11_backend_create (backend.c:376) by 0x4E580EE: wlr_backend_autocreate (backend.c:99) by 0x40C27D: main (main.c:35) Normally, one would expect this to crash during XCloseDisplay() when xcb_disconnect() is called again and frees the same data again (glibc would detect a double free). However, XCloseDisplay() tries to clean up some internal caches first for which it has to send requests to the X11 server (e.g. the XFreeGC() above). This fails since the file descriptor was already closed, which causes an IO error. Xlib's _XDefaultIOError() handles this by printing an error message and calling exit(1). Thus, the only symptom of this problem was compositors exiting mid-shutdown and printing an error message: XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0" after 6 requests (6 known processed) with 0 events remaining. Fixes: https://github.com/swaywm/wlroots/issues/745 Signed-off-by: Uli Schlachter --- backend/x11/backend.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'backend') diff --git a/backend/x11/backend.c b/backend/x11/backend.c index dd2c0a6e..36d72d9e 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -326,9 +326,6 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) { wl_event_source_remove(x11->frame_timer); wlr_egl_finish(&x11->egl); - if (x11->xcb_conn) { - xcb_disconnect(x11->xcb_conn); - } if (x11->xlib_conn) { XCloseDisplay(x11->xlib_conn); } @@ -428,7 +425,6 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, error_event: wl_event_source_remove(x11->event_source); error_x11: - xcb_disconnect(x11->xcb_conn); XCloseDisplay(x11->xlib_conn); free(x11); return NULL; -- cgit v1.2.3 From 3bda7e2ef8db955bb56e9dbf700974de06a2836b Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 26 Mar 2018 12:00:08 -0400 Subject: Use DRM_FORMAT_MOD_LINEAR instead of a hardcoded constant --- backend/drm/renderer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'backend') diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 2b50bb79..c1531ce3 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -14,6 +14,10 @@ #include "backend/drm/drm.h" #include "glapi.h" +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR 0 +#endif + bool wlr_drm_renderer_init(struct wlr_drm_backend *drm, struct wlr_drm_renderer *renderer) { renderer->gbm = gbm_create_device(drm->fd); @@ -195,7 +199,7 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, }; attribs.offset[0] = 0; attribs.stride[0] = gbm_bo_get_stride_for_plane(bo, 0); - attribs.modifier[0] = 0; + attribs.modifier[0] = DRM_FORMAT_MOD_LINEAR; attribs.fd[0] = gbm_bo_get_fd(bo); tex->tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs); -- cgit v1.2.3 From 706f77e3c735e49b4a051d545f40043a53e1ea2c Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 26 Mar 2018 23:15:21 -0400 Subject: Address review feedback --- backend/backend.c | 2 +- rootston/input.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'backend') diff --git a/backend/backend.c b/backend/backend.c index 96e155dc..02b0b9af 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -12,7 +12,7 @@ #include #include #ifdef WLR_HAS_X11_BACKEND -# include +#include #endif #include diff --git a/rootston/input.c b/rootston/input.c index 27ad1f6b..962be9fa 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -6,7 +6,7 @@ #include #include #ifdef WLR_HAS_XWAYLAND -# include +#include #endif #include "rootston/config.h" #include "rootston/input.h" -- cgit v1.2.3 From a0b52a0dff1e69f85e0095c58e3bda0b588caf45 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 27 Mar 2018 09:19:44 +0200 Subject: Fix x11 backend Need to include wlr/config.h before using the various WLR_HAS_xxx defines --- backend/backend.c | 5 ++++- include/xwayland/xwm.h | 1 + rootston/input.c | 1 + rootston/output.c | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) (limited to 'backend') diff --git a/backend/backend.c b/backend/backend.c index 02b0b9af..52344dac 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -11,10 +11,13 @@ #include #include #include +#include +#include + +/* WLR_HAS_X11_BACKEND needs to be after wlr/config.h */ #ifdef WLR_HAS_X11_BACKEND #include #endif -#include void wlr_backend_init(struct wlr_backend *backend, const struct wlr_backend_impl *impl) { diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 4b15cc84..9e21ea3a 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -2,6 +2,7 @@ #define XWAYLAND_XWM_H #include +#include #include #include diff --git a/rootston/input.c b/rootston/input.c index 962be9fa..3e1b06fb 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/rootston/output.c b/rootston/output.c index 8d6444d6..52ece54d 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3