From 9e26808c280cb32f32835231a76b5b105011fd1e Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 21 May 2018 18:50:51 +0100 Subject: output, backend/drm: add wlr_output_export_dmabuf --- include/backend/drm/renderer.h | 2 ++ include/wlr/interfaces/wlr_output.h | 2 ++ include/wlr/types/wlr_output.h | 3 +++ 3 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 510abe43..f26ca3d6 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -52,5 +52,7 @@ struct gbm_bo *get_drm_surface_front(struct wlr_drm_surface *surf); void post_drm_surface(struct wlr_drm_surface *surf); struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, struct gbm_bo *src); +void export_drm_bo(struct gbm_bo *bo, + struct wlr_dmabuf_buffer_attribs *attribs); #endif diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 7ecc7551..d39e4edc 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -23,6 +23,8 @@ struct wlr_output_impl { void (*set_gamma)(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t (*get_gamma_size)(struct wlr_output *output); + bool (*export_dmabuf)(struct wlr_output *output, + struct wlr_dmabuf_buffer_attribs *attribs); }; void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index cef3fc5d..669b96ed 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -6,6 +6,7 @@ #include #include #include +#include struct wlr_output_mode { uint32_t flags; // enum wl_output_mode @@ -162,6 +163,8 @@ void wlr_output_schedule_frame(struct wlr_output *output); void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t wlr_output_get_gamma_size(struct wlr_output *output); +bool wlr_output_export_dmabuf(struct wlr_output *output, + struct wlr_dmabuf_buffer_attribs *attribs); void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_surface *surface); struct wlr_output *wlr_output_from_resource(struct wl_resource *resource); -- cgit v1.2.3 From 36bd4795d4fe2282dfcc59f26863bac2896a4a3f Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 22 May 2018 17:38:05 +0100 Subject: export-dmabuf: add basic and incomplete implementation --- include/wlr/types/wlr_export_dmabuf_v1.h | 33 +++++ protocol/meson.build | 3 +- protocol/wlr-export-dmabuf-unstable-v1.xml | 230 +++++++++++++++++++++++++++++ types/meson.build | 1 + types/wlr_export_dmabuf_v1.c | 185 +++++++++++++++++++++++ 5 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 include/wlr/types/wlr_export_dmabuf_v1.h create mode 100644 protocol/wlr-export-dmabuf-unstable-v1.xml create mode 100644 types/wlr_export_dmabuf_v1.c (limited to 'include') diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h new file mode 100644 index 00000000..78db1e61 --- /dev/null +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -0,0 +1,33 @@ +#ifndef WLR_TYPES_WLR_EXPORT_DMABUF_V1_H +#define WLR_TYPES_WLR_EXPORT_DMABUF_V1_H + +#include + +struct wlr_export_dmabuf_manager_v1; + +struct wlr_export_dmabuf_frame_v1 { + struct wl_resource *resource; + struct wlr_export_dmabuf_manager_v1 *manager; + struct wl_list link; + + struct wlr_output *output; +}; + +struct wlr_export_dmabuf_manager_v1 { + struct wl_global *global; + struct wl_list resources; + struct wl_list frames; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create( + struct wl_display *display); +void wlr_export_dmabuf_manager_v1_destroy( + struct wlr_export_dmabuf_manager_v1 *manager); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 8fa64ca9..a14e9723 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -39,8 +39,9 @@ protocols = [ 'screenshooter.xml', 'server-decoration.xml', 'virtual-keyboard-unstable-v1.xml', - 'wlr-layer-shell-unstable-v1.xml', + 'wlr-export-dmabuf-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', + 'wlr-layer-shell-unstable-v1.xml', ] client_protocols = [ diff --git a/protocol/wlr-export-dmabuf-unstable-v1.xml b/protocol/wlr-export-dmabuf-unstable-v1.xml new file mode 100644 index 00000000..6332b146 --- /dev/null +++ b/protocol/wlr-export-dmabuf-unstable-v1.xml @@ -0,0 +1,230 @@ + + + + + Copyright © 2018 Rostislav Pehlivanov + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + An interface to capture surfaces in an efficient way. + Overall usage: + + 1.) client registers with zwlr_screencontent_manager_v1 + 2.) server sends client info about surfaces via "receive_surface_info" + 3.) client subscribes to capture a surface via the "capture" requests + 4.) server sends client events via the "zwlr_screencontent_frame" interface + 5.) client finishes and informs server via the "frame_destroy" event + 6.) client optionally resubscribes via repeating steps 3.) through 5.) + + + + + This object represents a frame which is ready to have its resources + fetched and used. + + The receive callback shall be called first, followed by either the + "dma_object" callback once per object or the "dma_layer" callback, + once per layer. The "dma_plane" callback shall only be called after + the "dma_layer" callback corresponding to the layer the plane belongs + to has been called. Finally, the "ready" event is called to indicate that + all the data has been made available for readout, as well as the time + at which presentation happened at. + The ownership of the frame is passed to the client, who's responsible for + destroying it via the "destroy" event once finished. + The data the API describes has been based off of what + VASurfaceAttribExternalBuffers contains. + All frames are read-only and may not be written into or altered. + + + + + Special flags that must be respected by the client. + Transient frames indicate short lifetime frames (such as swapchain + images from external clients). Clients are advised to copy them and do + all processing outside of the "ready" event. + + + + + + + Main callback supplying the client with information about the frame, + as well as an object to serve as context for destruction. Always called + first before any other events. + + The "transform" argument describes the orientation needed to be applied + to correctly orient the buffer. For example, a buffer rotated by 90 + degrees will have a value of "3" here, corresponding to the need to + apply a 270 degree transpose to correctly present the buffer. + + + + + + + + + + + + + + + Callback which serves to supply the client with the file descriptors + containing the data for each object. + + + + + + + + Callback which serves to supply the client with information on what's + contained in each file descriptor and how its laid out. + Will be called after the main receive event, once per layer. + + + + + + + + Callback which supplies the client with plane information for each + layer. + + + + + + + + + + Called as soon as the frame is presented, indicating it is available + for reading. + The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, + each component being an unsigned 32-bit value. Whole seconds are in + tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, + and the additional fractional part in tv_nsec as nanoseconds. Hence, + for valid timestamps tv_nsec must be in [0, 999999999]. + The seconds part may have an arbitrary offset at start. + + + + + + + + If the frame is no longer valid after the "frame" event has been called, + this callback will be used to inform the client to scrap the frame. + Source is still valid for as long as the subscription function does not + return NULL. + This may get called if for instance the surface is in the process of + resizing. + + + + + + Unreferences the frame, allowing it to be reused. Must be called as soon + as its no longer used. + + + + + + + This object is a manager which informs clients about capturable windows + and is able to create callbacks from which to begin to receive content + from. The "title" argument in the "surface_info" event shall be used + to provide a user-readable identifier such as a window title or + program name. + + + + + This will be called whenever a surface that's able to be captured + appears. + + + + + + + Called if a surface becomes unavailable to capture, for example if has + been closed. + + + + + + + Request to start capturing from a surface with a given id. + If an ID becomes unavailable, a NULL will be returned. + + + + + + + + Request to start capturing from an entire wl_output. + If an output becomes unavailable, a NULL will be returned. + + + + + + diff --git a/types/meson.build b/types/meson.build index f9f5b469..0842f98c 100644 --- a/types/meson.build +++ b/types/meson.build @@ -22,6 +22,7 @@ lib_wlr_types = static_library( 'wlr_box.c', 'wlr_compositor.c', 'wlr_cursor.c', + 'wlr_export_dmabuf_v1.c', 'wlr_gamma_control.c', 'wlr_idle_inhibit_v1.c', 'wlr_idle.c', diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c new file mode 100644 index 00000000..fa732397 --- /dev/null +++ b/types/wlr_export_dmabuf_v1.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include "wlr-export-dmabuf-unstable-v1-protocol.h" + +#define EXPORT_DMABUF_MANAGER_VERSION 1 + + +static const struct zwlr_export_dmabuf_frame_v1_interface frame_impl; + +static struct wlr_export_dmabuf_frame_v1 *frame_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_export_dmabuf_frame_v1_interface, &frame_impl)); + return wl_resource_get_user_data(resource); +} + +static void frame_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_export_dmabuf_frame_v1_interface frame_impl = { + .destroy = frame_handle_destroy, +}; + +static void frame_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_export_dmabuf_frame_v1 *frame = frame_from_resource(resource); + wl_list_remove(&frame->link); + free(frame); +} + + +static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl; + +static struct wlr_export_dmabuf_manager_v1 *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_export_dmabuf_manager_v1_interface, &manager_impl)); + return wl_resource_get_user_data(resource); +} + +static void manager_handle_capture_client(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + uint32_t client_id, int32_t overlay_cursor) { + // TODO +} + +static void manager_handle_capture_output(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + struct wl_resource *output_resource) { + struct wlr_export_dmabuf_manager_v1 *manager = + manager_from_resource(manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); + + struct wlr_export_dmabuf_frame_v1 *frame = + calloc(1, sizeof(struct wlr_export_dmabuf_frame_v1)); + if (frame == NULL) { + wl_resource_post_no_memory(manager_resource); + return; + } + frame->manager = manager; + frame->output = output; + + uint32_t version = wl_resource_get_version(manager_resource); + frame->resource = wl_resource_create(client, + &zwlr_export_dmabuf_frame_v1_interface, version, id); + if (frame->resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(frame->resource, &frame_impl, frame, + frame_handle_resource_destroy); + + wl_list_insert(&manager->frames, &frame->link); + + struct wlr_dmabuf_buffer_attribs attribs; + if (!wlr_output_export_dmabuf(output, &attribs)) { + zwlr_export_dmabuf_frame_v1_send_abort(frame->resource); + return; + } + + // TODO: multiple layers support + + uint32_t frame_flags = 0; + uint32_t mod_high = attribs.modifier[0] >> 32; + uint32_t mod_low = attribs.modifier[0]; + + zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, + output->width, output->height, output->scale, output->transform, + attribs.flags, frame_flags, mod_high, mod_low, attribs.n_planes, 1); + + zwlr_export_dmabuf_frame_v1_send_dma_layer(frame->resource, 0, + attribs.format, 1); + + for (int i = 0; i < attribs.n_planes; ++i) { + // TODO: what to do if the kernel doesn't support seek on buffer + off_t size = lseek(attribs.fd[i], 0, SEEK_END); + + zwlr_export_dmabuf_frame_v1_send_dma_object(frame->resource, i, + attribs.fd[i], size); + zwlr_export_dmabuf_frame_v1_send_dma_plane(frame->resource, i, 0, i, + attribs.offset[i], attribs.stride[i]); + } + + // TODO: wait for the frame to be ready + // TODO: timestamps + zwlr_export_dmabuf_frame_v1_send_ready(frame->resource, 0, 0, 0); +} + +static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl = { + .capture_client = manager_handle_capture_client, + .capture_output = manager_handle_capture_output, +}; + +static void manager_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void manager_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id) { + struct wlr_export_dmabuf_manager_v1 *manager = data; + + struct wl_resource *resource = wl_resource_create(client, + &zwlr_export_dmabuf_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &manager_impl, manager, + manager_handle_resource_destroy); + + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_export_dmabuf_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wlr_export_dmabuf_manager_v1_destroy(manager); +} + +struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create( + struct wl_display *display) { + struct wlr_export_dmabuf_manager_v1 *manager = + calloc(1, sizeof(struct wlr_export_dmabuf_manager_v1)); + if (manager == NULL) { + return NULL; + } + wl_list_init(&manager->resources); + wl_list_init(&manager->frames); + + manager->global = wl_global_create(display, + &zwlr_export_dmabuf_manager_v1_interface, EXPORT_DMABUF_MANAGER_VERSION, + manager, manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} + +void wlr_export_dmabuf_manager_v1_destroy( + struct wlr_export_dmabuf_manager_v1 *manager) { + if (manager == NULL) { + return; + } + wl_list_remove(&manager->display_destroy.link); + wl_global_destroy(manager->global); + struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) { + wl_resource_destroy(resource); + } + struct wlr_export_dmabuf_frame_v1 *frame, *frame_tmp; + wl_list_for_each_safe(frame, frame_tmp, &manager->frames, link) { + wl_resource_destroy(frame->resource); + } + free(manager); +} -- cgit v1.2.3 From bd430b8620f5dec485e49269d6add8dc3c20a8ab Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 22 May 2018 23:07:15 +0100 Subject: backend/drm: support multi-planar DMA-BUFs when exporting --- backend/drm/drm.c | 3 +-- backend/drm/renderer.c | 33 ++++++++++++++++++++++++++------- include/backend/drm/renderer.h | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 5b6054d3..d54c93f8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -270,8 +270,7 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output, struct wlr_drm_plane *plane = crtc->primary; struct wlr_drm_surface *surf = &plane->surf; - export_drm_bo(surf->back, attribs); - return true; + return export_drm_bo(surf->back, attribs); } static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 2cb47a12..15cf8cce 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -160,17 +160,33 @@ void post_drm_surface(struct wlr_drm_surface *surf) { } } -void export_drm_bo(struct gbm_bo *bo, +bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_buffer_attribs *attribs) { memset(attribs, 0, sizeof(struct wlr_dmabuf_buffer_attribs)); - attribs->n_planes = 1; + + attribs->n_planes = gbm_bo_get_plane_count(bo); + if (attribs->n_planes > WLR_LINUX_DMABUF_MAX_PLANES) { + return false; + } + attribs->width = gbm_bo_get_width(bo); attribs->height = gbm_bo_get_height(bo); attribs->format = gbm_bo_get_format(bo); - attribs->offset[0] = 0; - attribs->stride[0] = gbm_bo_get_stride_for_plane(bo, 0); - attribs->modifier[0] = DRM_FORMAT_MOD_LINEAR; - attribs->fd[0] = gbm_bo_get_fd(bo); + + for (int i = 0; i < attribs->n_planes; ++i) { + attribs->offset[i] = gbm_bo_get_offset(bo, i); + attribs->stride[i] = gbm_bo_get_stride_for_plane(bo, i); + attribs->modifier[i] = gbm_bo_get_modifier(bo); + attribs->fd[i] = gbm_bo_get_fd(bo); + if (attribs->fd[i] < 0) { + for (int j = 0; j < i; ++j) { + close(attribs->fd[j]); + } + return false; + } + } + + return true; } struct tex { @@ -200,7 +216,10 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, } struct wlr_dmabuf_buffer_attribs attribs; - export_drm_bo(bo, &attribs); + if (!export_drm_bo(bo, &attribs)) { + free(tex); + return NULL; + } tex->tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs); if (tex->tex == NULL) { diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index f26ca3d6..00e26976 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -52,7 +52,7 @@ struct gbm_bo *get_drm_surface_front(struct wlr_drm_surface *surf); void post_drm_surface(struct wlr_drm_surface *surf); struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, struct gbm_bo *src); -void export_drm_bo(struct gbm_bo *bo, +bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_buffer_attribs *attribs); #endif -- cgit v1.2.3 From 5ba1a9af5652aa2407738ec6290e7a9a59a86ea6 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 23 May 2018 00:03:26 +0100 Subject: render: add wlr_texture_to_dmabuf --- include/wlr/render/egl.h | 5 +++++ include/wlr/render/interface.h | 2 ++ include/wlr/render/wlr_texture.h | 3 +++ render/egl.c | 46 +++++++++++++++++++++++++++++++++++++--- render/glapi.txt | 2 ++ render/gles2/texture.c | 29 +++++++++++++++++++++++++ render/wlr_texture.c | 8 +++++++ 7 files changed, 92 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 4d837138..17fef7ed 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -20,6 +20,7 @@ struct wlr_egl { bool swap_buffers_with_damage; bool dmabuf_import; bool dmabuf_import_modifiers; + bool dmabuf_export; bool bind_wayland_display; } egl_exts; @@ -85,6 +86,10 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats); int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers); +bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, + int32_t width, int32_t height, uint32_t flags, + struct wlr_dmabuf_buffer_attribs *attribs); + /** * Destroys an EGL image created with the given wlr_egl. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 2267d376..1f075e81 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -62,6 +62,8 @@ struct wlr_texture_impl { 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); + bool (*to_dmabuf)(struct wlr_texture *texture, + struct wlr_dmabuf_buffer_attribs *attribs); void (*destroy)(struct wlr_texture *texture); }; diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 239fc51b..481b2a37 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -48,6 +48,9 @@ bool wlr_texture_write_pixels(struct wlr_texture *texture, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, const void *data); +bool wlr_texture_to_dmabuf(struct wlr_texture *texture, + struct wlr_dmabuf_buffer_attribs *attribs); + /** * Destroys this wlr_texture. */ diff --git a/render/egl.c b/render/egl.c index 579bb5fe..1182a72f 100644 --- a/render/egl.c +++ b/render/egl.c @@ -178,8 +178,12 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->exts_str, "EGL_EXT_image_dma_buf_import_modifiers") && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + egl->egl_exts.dmabuf_export = + check_egl_ext(egl->exts_str, "EGL_MESA_image_dma_buf_export"); + egl->egl_exts.bind_wayland_display = check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display"); + print_dmabuf_formats(egl); return true; @@ -209,7 +213,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { } bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { - if (!egl->egl_exts.bind_wayland_display) { + if (!egl->egl_exts.bind_wayland_display || !eglBindWaylandDisplayWL) { return false; } @@ -414,7 +418,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, } #ifndef DRM_FORMAT_BIG_ENDIAN -# define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#define DRM_FORMAT_BIG_ENDIAN 0x80000000 #endif bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_buffer *dmabuf) { @@ -446,7 +450,7 @@ bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { if (!egl->egl_exts.dmabuf_import || - !egl->egl_exts.dmabuf_import_modifiers) { + !egl->egl_exts.dmabuf_import_modifiers) { wlr_log(L_DEBUG, "dmabuf extension not present"); return -1; } @@ -501,6 +505,42 @@ int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, return num; } +bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, + int32_t width, int32_t height, uint32_t flags, + struct wlr_dmabuf_buffer_attribs *attribs) { + memset(attribs, 0, sizeof(struct wlr_dmabuf_buffer_attribs)); + + if (!egl->egl_exts.dmabuf_export || !eglExportDMABUFImageQueryMESA || + !eglExportDMABUFImageMESA) { + return false; + } + + // Only one set of modifiers is returned for all planes + EGLuint64KHR modifiers; + if (!eglExportDMABUFImageQueryMESA(egl->display, image, + (int *)&attribs->format, &attribs->n_planes, &modifiers)) { + return false; + } + if (attribs->n_planes > WLR_LINUX_DMABUF_MAX_PLANES) { + wlr_log(L_ERROR, "EGL returned %d planes, but only %d are supported", + attribs->n_planes, WLR_LINUX_DMABUF_MAX_PLANES); + return false; + } + for (int i = 0; i < attribs->n_planes; ++i) { + attribs->modifier[i] = modifiers; + } + + if (!eglExportDMABUFImageMESA(egl->display, image, attribs->fd, + (EGLint *)attribs->stride, (EGLint *)attribs->offset)) { + return false; + } + + attribs->width = width; + attribs->height = height; + attribs->flags = flags; + return true; +} + bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface) { if (!surface) { return true; diff --git a/render/glapi.txt b/render/glapi.txt index a8e4aaba..b1166f27 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -10,6 +10,8 @@ eglCreatePlatformWindowSurfaceEXT -eglSwapBuffersWithDamageKHR -eglQueryDmaBufFormatsEXT -eglQueryDmaBufModifiersEXT +-eglExportDMABUFImageQueryMESA +-eglExportDMABUFImageMESA -eglDebugMessageControlKHR -glDebugMessageCallbackKHR -glDebugMessageControlKHR diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 37424802..742f9da0 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -74,6 +74,34 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, return true; } +static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture, + struct wlr_dmabuf_buffer_attribs *attribs) { + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + + if (!texture->image) { + assert(texture->type == WLR_GLES2_TEXTURE_GLTEX); + + if (!eglCreateImageKHR) { + return false; + } + + texture->image = eglCreateImageKHR(texture->egl->display, + texture->egl->context, EGL_GL_TEXTURE_2D_KHR, + (EGLClientBuffer)(uintptr_t)texture->gl_tex, NULL); + if (texture->image == EGL_NO_IMAGE_KHR) { + return false; + } + } + + uint32_t flags = 0; + if (texture->inverted_y) { + flags |= WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT; + } + + return wlr_egl_export_image_to_dmabuf(texture->egl, texture->image, + texture->width, texture->height, flags, attribs); +} + static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { if (wlr_texture == NULL) { return; @@ -102,6 +130,7 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { static const struct wlr_texture_impl texture_impl = { .get_size = gles2_texture_get_size, .write_pixels = gles2_texture_write_pixels, + .to_dmabuf = gles2_texture_to_dmabuf, .destroy = gles2_texture_destroy, }; diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 9aecfd98..f7ce0b44 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -54,3 +54,11 @@ bool wlr_texture_write_pixels(struct wlr_texture *texture, return texture->impl->write_pixels(texture, wl_fmt, stride, width, height, src_x, src_y, dst_x, dst_y, data); } + +bool wlr_texture_to_dmabuf(struct wlr_texture *texture, + struct wlr_dmabuf_buffer_attribs *attribs) { + if (!texture->impl->to_dmabuf) { + return false; + } + return texture->impl->to_dmabuf(texture, attribs); +} -- cgit v1.2.3 From e26f4dff9843c51762852642719aa0eee1449aca Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 23 May 2018 09:02:19 +0100 Subject: export-dmabuf: wait for the frame to be ready, send timestamp --- include/wlr/types/wlr_export_dmabuf_v1.h | 2 ++ include/wlr/types/wlr_output.h | 8 +++++++- types/wlr_export_dmabuf_v1.c | 23 +++++++++++++++++++---- types/wlr_output.c | 7 ++++++- 4 files changed, 34 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index 78db1e61..4cb3393f 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -11,6 +11,8 @@ struct wlr_export_dmabuf_frame_v1 { struct wl_list link; struct wlr_output *output; + + struct wl_listener output_swap_buffers; }; struct wlr_export_dmabuf_manager_v1 { diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 669b96ed..96c98dc3 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -82,7 +82,7 @@ struct wlr_output { struct { struct wl_signal frame; struct wl_signal needs_swap; - struct wl_signal swap_buffers; + struct wl_signal swap_buffers; // wlr_output_event_swap_buffers struct wl_signal enable; struct wl_signal mode; struct wl_signal scale; @@ -108,6 +108,12 @@ struct wlr_output { void *data; }; +struct wlr_output_event_swap_buffers { + struct wlr_output *output; + struct timespec *when; + pixman_region32_t *damage; +}; + struct wlr_surface; void wlr_output_enable(struct wlr_output *output, bool enable); diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index fa732397..2f1c88f2 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -30,9 +30,25 @@ static const struct zwlr_export_dmabuf_frame_v1_interface frame_impl = { static void frame_handle_resource_destroy(struct wl_resource *resource) { struct wlr_export_dmabuf_frame_v1 *frame = frame_from_resource(resource); wl_list_remove(&frame->link); + wl_list_remove(&frame->output_swap_buffers.link); free(frame); } +static void frame_output_handle_swap_buffers(struct wl_listener *listener, + void *data) { + struct wlr_export_dmabuf_frame_v1 *frame = + wl_container_of(listener, frame, output_swap_buffers); + struct wlr_output_event_swap_buffers *event = data; + + wl_list_remove(&frame->output_swap_buffers.link); + wl_list_init(&frame->output_swap_buffers.link); + + uint32_t tv_sec_hi = event->when->tv_sec << 32; + uint32_t tv_sec_lo = event->when->tv_sec & 0xFFFFFFFF; + zwlr_export_dmabuf_frame_v1_send_ready(frame->resource, + tv_sec_hi, tv_sec_lo, event->when->tv_nsec); +} + static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl; @@ -87,7 +103,7 @@ static void manager_handle_capture_output(struct wl_client *client, uint32_t frame_flags = 0; uint32_t mod_high = attribs.modifier[0] >> 32; - uint32_t mod_low = attribs.modifier[0]; + uint32_t mod_low = attribs.modifier[0] & 0xFFFFFFFF; zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, output->width, output->height, output->scale, output->transform, @@ -106,9 +122,8 @@ static void manager_handle_capture_output(struct wl_client *client, attribs.offset[i], attribs.stride[i]); } - // TODO: wait for the frame to be ready - // TODO: timestamps - zwlr_export_dmabuf_frame_v1_send_ready(frame->resource, 0, 0, 0); + frame->output_swap_buffers.notify = frame_output_handle_swap_buffers; + wl_signal_add(&output->events.swap_buffers, &frame->output_swap_buffers); } static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl = { diff --git a/types/wlr_output.c b/types/wlr_output.c index f7001b16..b0321d7f 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -467,7 +467,12 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, output->idle_frame = NULL; } - wlr_signal_emit_safe(&output->events.swap_buffers, damage); + struct wlr_output_event_swap_buffers event = { + .output = output, + .when = when, + .damage = damage, + }; + wlr_signal_emit_safe(&output->events.swap_buffers, &event); int width, height; wlr_output_transformed_resolution(output, &width, &height); -- cgit v1.2.3 From 7901740f940dbaf5f674d533808898157790863a Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 23 May 2018 09:07:40 +0100 Subject: rootston: enable export-dmabuf --- include/rootston/desktop.h | 1 + rootston/desktop.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index bb7d2084..dfe070ca 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -45,6 +45,7 @@ struct roots_desktop { struct wlr_xdg_shell *xdg_shell; struct wlr_gamma_control_manager *gamma_control_manager; struct wlr_screenshooter *screenshooter; + struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1; struct wlr_server_decoration_manager *server_decoration_manager; struct wlr_primary_selection_device_manager *primary_selection_device_manager; struct wlr_idle *idle; diff --git a/rootston/desktop.c b/rootston/desktop.c index a6f9e9a0..2bba06e2 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -7,9 +7,10 @@ #include #include #include +#include #include -#include #include +#include #include #include #include @@ -18,9 +19,9 @@ #include #include #include +#include #include #include -#include #include #include "rootston/layers.h" #include "rootston/seat.h" @@ -845,6 +846,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->gamma_control_manager = wlr_gamma_control_manager_create( server->wl_display); desktop->screenshooter = wlr_screenshooter_create(server->wl_display); + desktop->export_dmabuf_manager_v1 = + wlr_export_dmabuf_manager_v1_create(server->wl_display); desktop->server_decoration_manager = wlr_server_decoration_manager_create(server->wl_display); wlr_server_decoration_manager_set_default_mode( -- cgit v1.2.3 From 00e108f2fcd0c41d361a45149ad6a310a0a4b85d Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 23 May 2018 23:27:15 +0100 Subject: export-dmabuf: correctly finish wlr_linux_dmabuf_attribs --- include/wlr/types/wlr_export_dmabuf_v1.h | 2 ++ include/wlr/types/wlr_linux_dmabuf.h | 6 ++++++ types/wlr_export_dmabuf_v1.c | 27 +++++++++++++++------------ types/wlr_linux_dmabuf.c | 15 ++++++++++----- 4 files changed, 33 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index 4cb3393f..218b1635 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -2,6 +2,7 @@ #define WLR_TYPES_WLR_EXPORT_DMABUF_V1_H #include +#include struct wlr_export_dmabuf_manager_v1; @@ -10,6 +11,7 @@ struct wlr_export_dmabuf_frame_v1 { struct wlr_export_dmabuf_manager_v1 *manager; struct wl_list link; + struct wlr_dmabuf_buffer_attribs attribs; struct wlr_output *output; struct wl_listener output_swap_buffers; diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h index 531e68ab..1677398b 100644 --- a/include/wlr/types/wlr_linux_dmabuf.h +++ b/include/wlr/types/wlr_linux_dmabuf.h @@ -37,6 +37,12 @@ struct wlr_dmabuf_buffer { struct wlr_dmabuf_buffer_attribs attributes; }; +/** + * Closes all file descriptors in the DMA-BUF attributes. + */ +void wlr_dmabuf_buffer_attribs_finish( + struct wlr_dmabuf_buffer_attribs *attribs); + /** * Returns true if the given resource was created via the linux-dmabuf * buffer protocol, false otherwise diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index 4a7382a3..1b284c44 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -5,6 +5,7 @@ #include #include #include "wlr-export-dmabuf-unstable-v1-protocol.h" +#include #define EXPORT_DMABUF_MANAGER_VERSION 1 @@ -31,6 +32,7 @@ static void frame_handle_resource_destroy(struct wl_resource *resource) { struct wlr_export_dmabuf_frame_v1 *frame = frame_from_resource(resource); wl_list_remove(&frame->link); wl_list_remove(&frame->output_swap_buffers.link); + wlr_dmabuf_buffer_attribs_finish(&frame->attribs); free(frame); } @@ -80,6 +82,7 @@ static void manager_handle_capture_output(struct wl_client *client, } frame->manager = manager; frame->output = output; + wl_list_init(&frame->output_swap_buffers.link); uint32_t version = wl_resource_get_version(manager_resource); frame->resource = wl_resource_create(client, @@ -93,9 +96,8 @@ static void manager_handle_capture_output(struct wl_client *client, wl_list_insert(&manager->frames, &frame->link); - struct wlr_dmabuf_buffer_attribs attribs; - if (!wlr_output_export_dmabuf(output, &attribs)) { - wl_list_init(&frame->output_swap_buffers.link); + struct wlr_dmabuf_buffer_attribs *attribs = &frame->attribs; + if (!wlr_output_export_dmabuf(output, attribs)) { // TODO: abort reason zwlr_export_dmabuf_frame_v1_send_abort(frame->resource, 0); return; @@ -104,28 +106,29 @@ static void manager_handle_capture_output(struct wl_client *client, // TODO: multiple layers support uint32_t frame_flags = 0; - uint32_t mod_high = attribs.modifier[0] >> 32; - uint32_t mod_low = attribs.modifier[0] & 0xFFFFFFFF; + uint32_t mod_high = attribs->modifier[0] >> 32; + uint32_t mod_low = attribs->modifier[0] & 0xFFFFFFFF; zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, output->width, output->height, output->scale, output->transform, - attribs.flags, frame_flags, mod_high, mod_low, attribs.n_planes, 1); + attribs->flags, frame_flags, mod_high, mod_low, attribs->n_planes, 1); zwlr_export_dmabuf_frame_v1_send_layer(frame->resource, 0, - attribs.format, 1); + attribs->format, 1); - for (int i = 0; i < attribs.n_planes; ++i) { + for (int i = 0; i < attribs->n_planes; ++i) { // TODO: what to do if the kernel doesn't support seek on buffer - off_t size = lseek(attribs.fd[i], 0, SEEK_END); + off_t size = lseek(attribs->fd[i], 0, SEEK_END); zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i, - attribs.fd[i], size); + attribs->fd[i], size); zwlr_export_dmabuf_frame_v1_send_plane(frame->resource, i, 0, i, - attribs.offset[i], attribs.stride[i]); + attribs->offset[i], attribs->stride[i]); } - frame->output_swap_buffers.notify = frame_output_handle_swap_buffers; + wl_list_remove(&frame->output_swap_buffers.link); wl_signal_add(&output->events.swap_buffers, &frame->output_swap_buffers); + frame->output_swap_buffers.notify = frame_output_handle_swap_buffers; } static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl = { diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 9bcd473f..8f46539f 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -51,12 +51,17 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( return buffer; } -static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) { - for (int i = 0; i < buffer->attributes.n_planes; i++) { - close(buffer->attributes.fd[i]); - buffer->attributes.fd[i] = -1; +void wlr_dmabuf_buffer_attribs_finish( + struct wlr_dmabuf_buffer_attribs *attribs) { + for (int i = 0; i < attribs->n_planes; ++i) { + close(attribs->fd[i]); + attribs->fd[i] = -1; } - buffer->attributes.n_planes = 0; + attribs->n_planes = 0; +} + +static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) { + wlr_dmabuf_buffer_attribs_finish(&buffer->attributes); free(buffer); } -- cgit v1.2.3