From 73755ad348657fdf8d9e0f9a48ee13a2ab947e35 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 19 Jun 2018 19:07:29 +0100 Subject: screencopy-v1: add basic implementation --- protocol/meson.build | 4 +- protocol/wlr-screencopy-unstable-v1.xml | 122 ++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 protocol/wlr-screencopy-unstable-v1.xml (limited to 'protocol') diff --git a/protocol/meson.build b/protocol/meson.build index ca0d82b5..5ab82d84 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -42,6 +42,7 @@ protocols = [ 'wlr-export-dmabuf-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', + 'wlr-screencopy-unstable-v1.xml', ] client_protocols = [ @@ -51,8 +52,9 @@ client_protocols = [ 'idle.xml', 'screenshooter.xml', 'wlr-export-dmabuf-unstable-v1.xml', - 'wlr-layer-shell-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', + 'wlr-layer-shell-unstable-v1.xml', + 'wlr-screencopy-unstable-v1.xml', ] wl_protos_src = [] diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml new file mode 100644 index 00000000..6bd5a75f --- /dev/null +++ b/protocol/wlr-screencopy-unstable-v1.xml @@ -0,0 +1,122 @@ + + + + Copyright © 2018 Simon Ser + + 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. + + + + This protocol allows clients to ask the compositor to copy part of the + screen content to a client buffer. + + + + + This object is a manager which offers requests to start capturing from a + source. + + + + + Request to start capturing from the given output. + + + + + + + + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + + + + + + + This object represents a frame which is ready to have its resources + fetched and used. + + + + + + + + + Provides information about the frame's buffer. This event is sent once + as soon as the frame is created. + + The client should then create a buffer with the provided width and + height, and send a copy request. It can optionally create a buffer with + the preferred format and stride. + + + + + + + + + + + Copy the frame to the supplied buffer. The buffer must have a the + correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to + have a supported format. + + If the frame is successfully copied, a ready event is sent. Otherwise, + an abort event is sent. + + + + + + + + + + + + + Called as soon as the frame is copied, indicating it is available + for reading. + + Upon receiving this event, the client should destroy the object. + + + + + + This event indicates that the attempted frame copy has failed. + + Upon receiving this event, the client should destroy the object. + + + + + + Destroys the frame. + + + + -- cgit v1.2.3 From bd8be19b792797925f5cca14049a5ab2d0f6d06c Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 22 Jun 2018 22:31:33 +0100 Subject: screencopy: add presentation timestamp --- examples/screencopy.c | 5 ++-- protocol/wlr-screencopy-unstable-v1.xml | 48 ++++++++++++++++++++++++++++----- types/wlr_screencopy_v1.c | 8 ++++-- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'protocol') diff --git a/examples/screencopy.c b/examples/screencopy.c index 98df09b5..8b064a15 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -113,7 +113,8 @@ static void frame_handle_buffer(void *data, } static void frame_handle_ready(void *data, - struct zwlr_screencopy_frame_v1 *frame) { + struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) { buffer_copy_done = true; } @@ -217,7 +218,7 @@ int main(int argc, char *argv[]) { } struct zwlr_screencopy_frame_v1 *frame = - zwlr_screencopy_manager_v1_capture_output(screencopy_manager, output); + zwlr_screencopy_manager_v1_capture_output(screencopy_manager, 0, output); zwlr_screencopy_frame_v1_add_listener(frame, &frame_listener, NULL); while (!buffer_copy_done) { diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml index 6bd5a75f..52f3385e 100644 --- a/protocol/wlr-screencopy-unstable-v1.xml +++ b/protocol/wlr-screencopy-unstable-v1.xml @@ -26,6 +26,15 @@ This protocol allows clients to ask the compositor to copy part of the screen content to a client buffer. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. @@ -36,9 +45,11 @@ - Request to start capturing from the given output. + Capture the next frame of a an entire output. + @@ -52,8 +63,17 @@ - This object represents a frame which is ready to have its resources - fetched and used. + This object represents a single frame. + + When created, a "buffer" event will be sent. The client will then be able + to send a "copy" request. If the capture is successful, the compositor + will finally a "ready" event. + + If the capture failed, the "failed" event is sent. This can happen anytime + before the "ready" event. + + Once either a "ready" or a "failed" event is received, the client should + destroy the frame. @@ -99,23 +119,37 @@ Called as soon as the frame is copied, indicating it is available - for reading. + for reading. This event includes the time at which presentation happened + at. + + 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. - Upon receiving this event, the client should destroy the object. + After receiving this event, the client should destroy the object. + + + This event indicates that the attempted frame copy has failed. - Upon receiving this event, the client should destroy the object. + After receiving this event, the client should destroy the object. - Destroys the frame. + Destroys the frame. This request can be sent at any time by the client. diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 197ba330..6b6472e1 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -21,6 +21,7 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, void *_data) { struct wlr_screencopy_frame_v1 *frame = wl_container_of(listener, frame, output_swap_buffers); + struct wlr_output_event_swap_buffers *event = _data; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); @@ -51,7 +52,10 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, return; } - zwlr_screencopy_frame_v1_send_ready(frame->resource); + uint32_t tv_sec_hi = event->when->tv_sec >> 32; + uint32_t tv_sec_lo = event->when->tv_sec & 0xFFFFFFFF; + zwlr_screencopy_frame_v1_send_ready(frame->resource, + tv_sec_hi, tv_sec_lo, event->when->tv_nsec); // TODO: make frame resource inert } @@ -134,7 +138,7 @@ static struct wlr_screencopy_manager_v1 *manager_from_resource( static void manager_handle_capture_output(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, - struct wl_resource *output_resource) { + int32_t overlay_cursor, struct wl_resource *output_resource) { struct wlr_screencopy_manager_v1 *manager = manager_from_resource(manager_resource); struct wlr_output *output = wlr_output_from_resource(output_resource); -- cgit v1.2.3 From 2b9cbaddf3d285ce439bd5da9f19995a0ddbac3a Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 23 Jun 2018 14:02:43 +0100 Subject: screencopy: add support for frame flags --- backend/drm/drm.c | 2 +- examples/screencopy.c | 32 ++++++++++++++++++++++++-------- include/wlr/render/interface.h | 2 +- include/wlr/render/wlr_renderer.h | 9 ++++++++- protocol/wlr-screencopy-unstable-v1.xml | 17 ++++++++++++----- render/gles2/renderer.c | 28 ++++++++++++++++++++-------- render/wlr_renderer.c | 6 +++--- types/wlr_screencopy_v1.c | 9 ++++++--- types/wlr_screenshooter.c | 4 ++-- 9 files changed, 77 insertions(+), 32 deletions(-) (limited to 'protocol') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index f4a971a2..ae462568 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -683,7 +683,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, wlr_render_texture_with_matrix(rend, texture, matrix, 1.0); wlr_renderer_end(rend); - wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, + wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, NULL, bo_stride, plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data); swap_drm_surface_buffers(&plane->surf, NULL); diff --git a/examples/screencopy.c b/examples/screencopy.c index 8b064a15..7be06d68 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -45,6 +45,7 @@ static struct { struct wl_buffer *wl_buffer; void *data; int width, height, stride; + bool y_invert; } buffer; bool buffer_copy_done = false; @@ -99,7 +100,7 @@ static struct wl_buffer *create_shm_buffer(int width, int height, static void frame_handle_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t width, uint32_t height, - uint32_t flags, uint32_t format, uint32_t stride) { + uint32_t format, uint32_t stride) { buffer.width = width; buffer.height = height; buffer.wl_buffer = @@ -112,6 +113,11 @@ static void frame_handle_buffer(void *data, zwlr_screencopy_frame_v1_copy(frame, buffer.wl_buffer); } +static void frame_handle_flags(void *data, + struct zwlr_screencopy_frame_v1 *frame, uint32_t flags) { + buffer.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT; +} + static void frame_handle_ready(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { @@ -126,6 +132,7 @@ static void frame_handle_failed(void *data, static const struct zwlr_screencopy_frame_v1_listener frame_listener = { .buffer = frame_handle_buffer, + .flags = frame_handle_flags, .ready = frame_handle_ready, .failed = frame_handle_failed, }; @@ -153,8 +160,8 @@ static const struct wl_registry_listener registry_listener = { .global_remove = handle_global_remove, }; -static void write_image(const char *filename, int width, int height, int stride, - void *data) { +static void write_image(char *filename, int width, int height, int stride, + bool y_invert, void *data) { char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits sprintf(size, "%dx%d+0", width, height); @@ -183,10 +190,19 @@ static void write_image(const char *filename, int width, int height, int stride, exit(EXIT_FAILURE); } close(fd[0]); + // We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA // in big endian. - execlp("convert", "convert", "-depth", "8", "-size", size, "bgra:-", - "-alpha", "opaque", filename, NULL); + char *argv[11] = {"convert", "-depth", "8", "-size", size, "bgra:-", + "-alpha", "opaque", filename, NULL}; + if (y_invert) { + argv[8] = "-flip"; + argv[9] = filename; + argv[10] = NULL; + } + + execvp("convert", argv); + fprintf(stderr, "cannot execute convert\n"); exit(EXIT_FAILURE); } @@ -221,12 +237,12 @@ int main(int argc, char *argv[]) { zwlr_screencopy_manager_v1_capture_output(screencopy_manager, 0, output); zwlr_screencopy_frame_v1_add_listener(frame, &frame_listener, NULL); - while (!buffer_copy_done) { - wl_display_roundtrip(display); + while (!buffer_copy_done && wl_display_dispatch(display) != -1) { + // This space is intentionally left blank } write_image("wayland-screenshot.png", buffer.width, buffer.height, - buffer.stride, buffer.data); + buffer.stride, buffer.y_invert, buffer.data); wl_buffer_destroy(buffer.wl_buffer); return EXIT_SUCCESS; diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index fb427c89..1b138ea3 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -34,7 +34,7 @@ struct wlr_renderer_impl { int (*get_dmabuf_modifiers)(struct wlr_renderer *renderer, int format, uint64_t **modifiers); bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt, - uint32_t stride, uint32_t width, uint32_t height, + uint32_t *flags, 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, diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index c715e4b0..0650bf1b 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -7,6 +7,10 @@ #include #include +enum wlr_renderer_read_pixels_flags { + WLR_RENDERER_READ_PIXELS_Y_INVERT = 1, +}; + struct wlr_renderer_impl; struct wlr_renderer { @@ -87,9 +91,12 @@ int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *renderer, int format, /** * Reads out of pixels of the currently bound surface into data. `stride` is in * bytes. + * + * If `flags` is not NULl, the caller indicates that it accepts frame flags + * defined in `enum wlr_renderer_read_pixels_flags`. */ 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 *flags, 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); /** * Checks if a format is supported. diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml index 52f3385e..e62e3ff0 100644 --- a/protocol/wlr-screencopy-unstable-v1.xml +++ b/protocol/wlr-screencopy-unstable-v1.xml @@ -76,10 +76,6 @@ destroy the frame. - - - - Provides information about the frame's buffer. This event is sent once @@ -91,7 +87,6 @@ - @@ -116,6 +111,18 @@ summary="invalid width or height"/> + + + + + + + Provides flags about the frame. This event is sent once before the + "ready" event. + + + + Called as soon as the frame is copied, indicating it is available diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 05426fa9..0c57bfa1 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -250,9 +250,9 @@ static int gles2_get_dmabuf_modifiers(struct wlr_renderer *wlr_renderer, } 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) { + enum wl_shm_format wl_fmt, uint32_t *flags, 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_in_context(wlr_renderer); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); @@ -266,12 +266,24 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, // Make sure any pending drawing is finished before we try to read it glFinish(); - // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read - // the lines out row by row unsigned char *p = data + dst_y * stride; - for (size_t i = src_y; i < src_y + height; ++i) { - glReadPixels(src_x, src_y + height - i - 1, width, 1, fmt->gl_format, - fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8); + uint32_t pack_stride = width * fmt->bpp / 8; + if (pack_stride == stride && dst_x == 0 && flags != NULL) { + // Under these particular conditions, we can read the pixels with only + // one glReadPixels call + glReadPixels(src_x, src_y, width, height, fmt->gl_format, + fmt->gl_type, p); + *flags = WLR_RENDERER_READ_PIXELS_Y_INVERT; + } else { + // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read + // the lines out row by row + for (size_t i = src_y; i < src_y + height; ++i) { + glReadPixels(src_x, src_y + height - i - 1, width, 1, fmt->gl_format, + fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8); + } + if (flags != NULL) { + *flags = 0; + } } POP_GLES2_DEBUG; diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 00f1e411..d66edc13 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -139,14 +139,14 @@ int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *r, int format, } 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 *flags, 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); + return r->impl->read_pixels(r, fmt, flags, stride, width, height, + src_x, src_y, dst_x, dst_y, data); } bool wlr_renderer_format_supported(struct wlr_renderer *r, diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 6b6472e1..89680a48 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -43,8 +43,9 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, wl_shm_buffer_begin_access(buffer); void *data = wl_shm_buffer_get_data(buffer); - bool ok = wlr_renderer_read_pixels(renderer, fmt, stride, width, height, - 0, 0, 0, 0, data); + uint32_t flags = 0; + bool ok = wlr_renderer_read_pixels(renderer, fmt, &flags, stride, + width, height, 0, 0, 0, 0, data); wl_shm_buffer_end_access(buffer); if (!ok) { @@ -52,6 +53,8 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, return; } + zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); + uint32_t tv_sec_hi = event->when->tv_sec >> 32; uint32_t tv_sec_lo = event->when->tv_sec & 0xFFFFFFFF; zwlr_screencopy_frame_v1_send_ready(frame->resource, @@ -172,7 +175,7 @@ static void manager_handle_capture_output(struct wl_client *client, frame->height = output->height; // TODO: don't send zero zwlr_screencopy_frame_v1_send_buffer(frame->resource, - frame->width, frame->height, 0, 0, 0); + frame->width, frame->height, 0, 0); } static void manager_handle_destroy(struct wl_client *client, diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index e1386be6..5d9e9de3 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -50,8 +50,8 @@ static void output_handle_frame(struct wl_listener *listener, void *_data) { int32_t stride = wl_shm_buffer_get_stride(shm_buffer); wl_shm_buffer_begin_access(shm_buffer); void *data = wl_shm_buffer_get_data(shm_buffer); - bool ok = wlr_renderer_read_pixels(renderer, format, stride, width, height, - 0, 0, 0, 0, data); + bool ok = wlr_renderer_read_pixels(renderer, format, NULL, stride, + width, height, 0, 0, 0, 0, data); wl_shm_buffer_end_access(shm_buffer); if (!ok) { -- cgit v1.2.3 From bf7560b7cda5d3df8cdc7d24e969bfd91cf0ded5 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 23 Jun 2018 15:12:17 +0100 Subject: screencopy: add capture_output_region support --- include/wlr/types/wlr_screencopy_v1.h | 2 +- protocol/wlr-screencopy-unstable-v1.xml | 29 ++++++++++-- render/gles2/renderer.c | 11 +++-- types/wlr_screencopy_v1.c | 78 +++++++++++++++++++++++++-------- 4 files changed, 93 insertions(+), 27 deletions(-) (limited to 'protocol') diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index fbcc1ce2..4766d680 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -18,7 +18,7 @@ struct wlr_screencopy_frame_v1 { struct wlr_screencopy_manager_v1 *manager; struct wl_list link; - int32_t width, height; + struct wlr_box buffer_box; struct wl_shm_buffer *buffer; diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml index e62e3ff0..c54b7268 100644 --- a/protocol/wlr-screencopy-unstable-v1.xml +++ b/protocol/wlr-screencopy-unstable-v1.xml @@ -43,14 +43,37 @@ source. + + + + - - Capture the next frame of a an entire output. + + Capture the next frame of an entire output. + + + + + + + + + Capture the next frame of an output's region. + + The region is given in output logical coordinates, see + xdg_output.logical_size. Trying to capture a region spanning outside the + output extents is a protocol error. + summary="composite cursor onto the frame"/> + + + + diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 0c57bfa1..e8b0b27d 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -253,7 +253,8 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t *flags, 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_in_context(wlr_renderer); + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); if (fmt == NULL) { @@ -266,13 +267,15 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, // Make sure any pending drawing is finished before we try to read it glFinish(); + glGetError(); // Clear the error flag + unsigned char *p = data + dst_y * stride; uint32_t pack_stride = width * fmt->bpp / 8; if (pack_stride == stride && dst_x == 0 && flags != NULL) { // Under these particular conditions, we can read the pixels with only // one glReadPixels call - glReadPixels(src_x, src_y, width, height, fmt->gl_format, - fmt->gl_type, p); + glReadPixels(src_x, renderer->viewport_height - height - src_y, + width, height, fmt->gl_format, fmt->gl_type, p); *flags = WLR_RENDERER_READ_PIXELS_Y_INVERT; } else { // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read @@ -288,7 +291,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - return true; + return (glGetError() == GL_NO_ERROR); } static bool gles2_format_supported(struct wlr_renderer *wlr_renderer, diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 89680a48..a600a716 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -28,10 +28,8 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, wl_list_remove(&frame->output_swap_buffers.link); wl_list_init(&frame->output_swap_buffers.link); - if (output->width != frame->width || output->height != frame->height) { - zwlr_screencopy_frame_v1_send_failed(frame->resource); - return; - } + int x = frame->buffer_box.x; + int y = frame->buffer_box.y; struct wl_shm_buffer *buffer = frame->buffer; assert(buffer != NULL); @@ -45,7 +43,7 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, void *data = wl_shm_buffer_get_data(buffer); uint32_t flags = 0; bool ok = wlr_renderer_read_pixels(renderer, fmt, &flags, stride, - width, height, 0, 0, 0, 0, data); + width, height, x, y, 0, 0, data); wl_shm_buffer_end_access(buffer); if (!ok) { @@ -84,8 +82,8 @@ static void frame_handle_copy(struct wl_client *client, return; } - if (frame->width != wl_shm_buffer_get_width(buffer) || - frame->height != wl_shm_buffer_get_height(buffer)) { + if (frame->buffer_box.width != wl_shm_buffer_get_width(buffer) || + frame->buffer_box.height != wl_shm_buffer_get_height(buffer)) { wl_resource_post_error(frame->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_DIMENSIONS, "invalid width or height"); @@ -139,24 +137,37 @@ static struct wlr_screencopy_manager_v1 *manager_from_resource( return wl_resource_get_user_data(resource); } -static void manager_handle_capture_output(struct wl_client *client, - struct wl_resource *manager_resource, uint32_t id, - int32_t overlay_cursor, struct wl_resource *output_resource) { - struct wlr_screencopy_manager_v1 *manager = - manager_from_resource(manager_resource); - struct wlr_output *output = wlr_output_from_resource(output_resource); +static void capture_output(struct wl_client *client, + struct wlr_screencopy_manager_v1 *manager, uint32_t version, uint32_t id, + int32_t overlay_cursor, struct wlr_output *output, + const struct wlr_box *box) { + struct wlr_box buffer_box = {0}; + if (box == NULL) { + buffer_box.width = output->width; + buffer_box.height = output->height; + } else { + int ow, oh; + wlr_output_effective_resolution(output, &ow, &oh); + + buffer_box = *box; + + wlr_box_transform(&buffer_box, output->transform, ow, oh, &buffer_box); + buffer_box.x *= output->scale; + buffer_box.y *= output->scale; + buffer_box.width *= output->scale; + buffer_box.height *= output->scale; + } struct wlr_screencopy_frame_v1 *frame = calloc(1, sizeof(struct wlr_screencopy_frame_v1)); if (frame == NULL) { - wl_resource_post_no_memory(manager_resource); + wl_client_post_no_memory(client); return; } frame->manager = manager; frame->output = output; - uint32_t version = wl_resource_get_version(manager_resource); frame->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, version, id); if (frame->resource == NULL) { @@ -171,11 +182,39 @@ static void manager_handle_capture_output(struct wl_client *client, wl_list_init(&frame->output_swap_buffers.link); - frame->width = output->width; - frame->height = output->height; - // TODO: don't send zero + frame->buffer_box = buffer_box; zwlr_screencopy_frame_v1_send_buffer(frame->resource, - frame->width, frame->height, 0, 0); + frame->buffer_box.width, frame->buffer_box.height, + WL_SHM_FORMAT_XRGB8888, 4 * frame->buffer_box.width); +} + +static void manager_handle_capture_output(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + int32_t overlay_cursor, struct wl_resource *output_resource) { + struct wlr_screencopy_manager_v1 *manager = + manager_from_resource(manager_resource); + uint32_t version = wl_resource_get_version(manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); + + capture_output(client, manager, version, id, overlay_cursor, output, NULL); +} + +static void manager_handle_capture_output_region(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + int32_t overlay_cursor, struct wl_resource *output_resource, + int32_t x, int32_t y, int32_t width, int32_t height) { + struct wlr_screencopy_manager_v1 *manager = + manager_from_resource(manager_resource); + uint32_t version = wl_resource_get_version(manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); + + struct wlr_box box = { + .x = x, + .y = y, + .width = width, + .height = height, + }; + capture_output(client, manager, version, id, overlay_cursor, output, &box); } static void manager_handle_destroy(struct wl_client *client, @@ -185,6 +224,7 @@ static void manager_handle_destroy(struct wl_client *client, static const struct zwlr_screencopy_manager_v1_interface manager_impl = { .capture_output = manager_handle_capture_output, + .capture_output_region = manager_handle_capture_output_region, .destroy = manager_handle_destroy, }; -- cgit v1.2.3 From c421700f3da6333652488e2951c2b0cbb8e35e51 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 23 Jun 2018 18:41:40 +0100 Subject: screncopy: update protocol --- examples/screencopy.c | 56 ++++++++++++++++++++++++--------- include/wlr/types/wlr_screencopy_v1.h | 4 ++- protocol/wlr-screencopy-unstable-v1.xml | 29 +++++++---------- types/wlr_screencopy_v1.c | 37 ++++++++++------------ 4 files changed, 72 insertions(+), 54 deletions(-) (limited to 'protocol') diff --git a/examples/screencopy.c b/examples/screencopy.c index 7be06d68..dc1984e6 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -44,11 +44,24 @@ static struct wl_output *output = NULL; static struct { struct wl_buffer *wl_buffer; void *data; + enum wl_shm_format format; int width, height, stride; bool y_invert; } buffer; bool buffer_copy_done = false; +// wl_shm_format describes little-endian formats, ImageMagick uses big-endian +// formats. +static const struct { + enum wl_shm_format wl_format; + char *str_format; +} formats[] = { + {WL_SHM_FORMAT_XRGB8888, "BGRA"}, + {WL_SHM_FORMAT_ARGB8888, "BGRA"}, + {WL_SHM_FORMAT_XBGR8888, "RGBA"}, + {WL_SHM_FORMAT_ABGR8888, "RGBA"}, +}; + static int backingfile(off_t size) { char template[] = "/tmp/wlroots-shared-XXXXXX"; int fd = mkstemp(template); @@ -69,9 +82,8 @@ static int backingfile(off_t size) { return fd; } -static struct wl_buffer *create_shm_buffer(int width, int height, - int *stride_out, void **data_out) { - int stride = width * 4; +static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt, + int width, int height, int stride, void **data_out) { int size = stride * height; int fd = backingfile(size); @@ -90,21 +102,22 @@ static struct wl_buffer *create_shm_buffer(int width, int height, struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); close(fd); struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, - stride, WL_SHM_FORMAT_XRGB8888); + stride, fmt); wl_shm_pool_destroy(pool); *data_out = data; - *stride_out = stride; return buffer; } static void frame_handle_buffer(void *data, - struct zwlr_screencopy_frame_v1 *frame, uint32_t width, uint32_t height, - uint32_t format, uint32_t stride) { + struct zwlr_screencopy_frame_v1 *frame, uint32_t format, + uint32_t width, uint32_t height, uint32_t stride) { + buffer.format = format; buffer.width = width; buffer.height = height; + buffer.stride = stride; buffer.wl_buffer = - create_shm_buffer(width, height, &buffer.stride, &buffer.data); + create_shm_buffer(format, width, height, stride, &buffer.data); if (buffer.wl_buffer == NULL) { fprintf(stderr, "failed to create buffer\n"); exit(EXIT_FAILURE); @@ -160,11 +173,26 @@ static const struct wl_registry_listener registry_listener = { .global_remove = handle_global_remove, }; -static void write_image(char *filename, int width, int height, int stride, - bool y_invert, void *data) { +static void write_image(char *filename, enum wl_shm_format wl_fmt, int width, + int height, int stride, bool y_invert, void *data) { char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits sprintf(size, "%dx%d+0", width, height); + const char *fmt_str = NULL; + for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) { + if (formats[i].wl_format == wl_fmt) { + fmt_str = formats[i].str_format; + break; + } + } + if (fmt_str == NULL) { + fprintf(stderr, "unsupported format %"PRIu32"\n", wl_fmt); + exit(EXIT_FAILURE); + } + char convert[strlen(fmt_str) + 3]; + memcpy(convert, fmt_str, strlen(fmt_str) + 1); + strcat(convert, ":-"); + int fd[2]; if (pipe(fd) != 0) { fprintf(stderr, "cannot create pipe: %s\n", strerror(errno)); @@ -191,9 +219,7 @@ static void write_image(char *filename, int width, int height, int stride, } close(fd[0]); - // We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA - // in big endian. - char *argv[11] = {"convert", "-depth", "8", "-size", size, "bgra:-", + char *argv[11] = {"convert", "-depth", "8", "-size", size, convert, "-alpha", "opaque", filename, NULL}; if (y_invert) { argv[8] = "-flip"; @@ -241,8 +267,8 @@ int main(int argc, char *argv[]) { // This space is intentionally left blank } - write_image("wayland-screenshot.png", buffer.width, buffer.height, - buffer.stride, buffer.y_invert, buffer.data); + write_image("wayland-screenshot.png", buffer.format, buffer.width, + buffer.height, buffer.stride, buffer.y_invert, buffer.data); wl_buffer_destroy(buffer.wl_buffer); return EXIT_SUCCESS; diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index 4766d680..69f62437 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -18,7 +18,9 @@ struct wlr_screencopy_frame_v1 { struct wlr_screencopy_manager_v1 *manager; struct wl_list link; - struct wlr_box buffer_box; + enum wl_shm_format format; + struct wlr_box box; + int stride; struct wl_shm_buffer *buffer; diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml index c54b7268..a7a2d172 100644 --- a/protocol/wlr-screencopy-unstable-v1.xml +++ b/protocol/wlr-screencopy-unstable-v1.xml @@ -43,11 +43,6 @@ source. - - - - Capture the next frame of an entire output. @@ -63,8 +58,8 @@ Capture the next frame of an output's region. The region is given in output logical coordinates, see - xdg_output.logical_size. Trying to capture a region spanning outside the - output extents is a protocol error. + xdg_output.logical_size. The region will be clipped to the output's + extents. + - - + @@ -120,8 +114,8 @@ correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to have a supported format. - If the frame is successfully copied, a ready event is sent. Otherwise, - an abort event is sent. + If the frame is successfully copied, a "flags" and a "ready" events are + sent. Otherwise, a "failed" event is sent. @@ -129,9 +123,8 @@ - - + diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index a600a716..027d4b51 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -28,8 +28,8 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener, wl_list_remove(&frame->output_swap_buffers.link); wl_list_init(&frame->output_swap_buffers.link); - int x = frame->buffer_box.x; - int y = frame->buffer_box.y; + int x = frame->box.x; + int y = frame->box.y; struct wl_shm_buffer *buffer = frame->buffer; assert(buffer != NULL); @@ -66,27 +66,24 @@ static void frame_handle_copy(struct wl_client *client, struct wl_resource *buffer_resource) { struct wlr_screencopy_frame_v1 *frame = frame_from_resource(frame_resource); struct wlr_output *output = frame->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); struct wl_shm_buffer *buffer = wl_shm_buffer_get(buffer_resource); if (buffer == NULL) { - zwlr_screencopy_frame_v1_send_failed(frame_resource); - return; - } - - enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer); - if (!wlr_renderer_format_supported(renderer, fmt)) { wl_resource_post_error(frame->resource, - ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_FORMAT, - "unsupported format %"PRIu32, fmt); + ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, + "unsupported buffer type"); return; } - if (frame->buffer_box.width != wl_shm_buffer_get_width(buffer) || - frame->buffer_box.height != wl_shm_buffer_get_height(buffer)) { + enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer); + int32_t width = wl_shm_buffer_get_width(buffer); + int32_t height = wl_shm_buffer_get_height(buffer); + int32_t stride = wl_shm_buffer_get_stride(buffer); + if (fmt != frame->format || width != frame->box.width || + height != frame->box.height || stride != frame->stride) { wl_resource_post_error(frame->resource, - ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_DIMENSIONS, - "invalid width or height"); + ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, + "invalid buffer attributes"); return; } @@ -165,7 +162,6 @@ static void capture_output(struct wl_client *client, return; } frame->manager = manager; - frame->output = output; frame->resource = wl_resource_create(client, @@ -182,10 +178,11 @@ static void capture_output(struct wl_client *client, wl_list_init(&frame->output_swap_buffers.link); - frame->buffer_box = buffer_box; - zwlr_screencopy_frame_v1_send_buffer(frame->resource, - frame->buffer_box.width, frame->buffer_box.height, - WL_SHM_FORMAT_XRGB8888, 4 * frame->buffer_box.width); + frame->format = WL_SHM_FORMAT_XRGB8888; + frame->box = buffer_box; + frame->stride = 4 * buffer_box.width; + zwlr_screencopy_frame_v1_send_buffer(frame->resource, frame->format, + buffer_box.width, buffer_box.height, frame->stride); } static void manager_handle_capture_output(struct wl_client *client, -- cgit v1.2.3