diff --git a/include/wlr/render.h b/include/wlr/render.h index 2fbfb476..5027064d 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -30,27 +30,32 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); * This will render the texture at <123, 321>. */ bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float (*matrix)[16]); + struct wlr_texture *texture, const float (*matrix)[16]); /** * Renders a solid quad in the specified color. */ void wlr_render_colored_quad(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]); + const float (*color)[4], const float (*matrix)[16]); /** * Renders a solid ellipse in the specified color. */ void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]); + const float (*color)[4], const float (*matrix)[16]); /** * Returns a list of pixel formats supported by this renderer. */ const enum wl_shm_format *wlr_renderer_get_formats( - struct wlr_renderer *r, size_t *len); + struct wlr_renderer *r, size_t *len); /** * Returns true if this wl_buffer is a DRM buffer. */ bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, - struct wl_resource *buffer); + struct wl_resource *buffer); +/** + * Reads pixels and stores them in out_data as ARGB8888. + */ +void wlr_renderer_read_pixels(struct wlr_renderer *r, int x, int y, + int width, int height, void *out_data); /** * Destroys this wlr_renderer. Textures must be destroyed separately. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index cbe33822..bbc5acb4 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -28,6 +28,8 @@ struct wlr_renderer_impl { struct wlr_renderer *renderer, size_t *len); bool (*buffer_is_drm)(struct wlr_renderer *renderer, struct wl_resource *buffer); + void (*read_pixels)(struct wlr_renderer *renderer, int x, int y, int width, + int height, void *out_data); void (*destroy)(struct wlr_renderer *renderer); }; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index ab3be5c7..52d377e3 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -72,9 +72,4 @@ void wlr_output_set_gamma(struct wlr_output *output, uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint16_t wlr_output_get_gamma_size(struct wlr_output *output); -/** - * Reads all pixels from the output and stores them as ARGB. - */ -void wlr_output_read_pixels(struct wlr_output *output, void *out_data); - #endif diff --git a/include/wlr/types/wlr_screenshooter.h b/include/wlr/types/wlr_screenshooter.h index 5d1a9254..4bda3d3c 100644 --- a/include/wlr/types/wlr_screenshooter.h +++ b/include/wlr/types/wlr_screenshooter.h @@ -4,18 +4,23 @@ struct wlr_screenshooter { struct wl_global *wl_global; + struct wlr_renderer *renderer; void *data; }; struct wlr_screenshot { struct wl_resource *resource; - struct wl_resource *output; + struct wl_resource *output_resource; + + struct wlr_output *output; + struct wlr_screenshooter *screenshooter; void* data; }; -struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display); +struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display, + struct wlr_renderer *renderer); void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter); #endif diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index d6c22ebe..9a013338 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -226,7 +226,23 @@ static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *_renderer, (struct wlr_gles2_renderer *)_renderer; EGLint format; return wlr_egl_query_buffer(renderer->egl, buffer, - EGL_TEXTURE_FORMAT, &format); + EGL_TEXTURE_FORMAT, &format); +} + +static void rgba_to_argb(uint32_t *data, size_t height, size_t stride) { + size_t n = height*stride/4; + for (size_t i = 0; i < n; ++i) { + uint32_t v = data[i]; + uint32_t rgb = (v & 0xffffff00) >> 8; + uint32_t a = v & 0x000000ff; + data[i] = rgb | (a << 24); + } +} + +static void wlr_gles2_read_pixels(struct wlr_renderer *renderer, int x, int y, + int width, int height, void *out_data) { + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, out_data); + rgba_to_argb(out_data, height, width*4); } static struct wlr_renderer_impl wlr_renderer_impl = { @@ -238,6 +254,7 @@ static struct wlr_renderer_impl wlr_renderer_impl = { .render_ellipse = wlr_gles2_render_ellipse, .formats = wlr_gles2_formats, .buffer_is_drm = wlr_gles2_buffer_is_drm, + .read_pixels = wlr_gles2_read_pixels, }; struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) { diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index fec5e38a..ef0c31be 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -51,3 +51,8 @@ bool wlr_renderer_buffer_is_drm(struct wlr_renderer *r, struct wl_resource *buffer) { return r->impl->buffer_is_drm(r, buffer); } + +void wlr_renderer_read_pixels(struct wlr_renderer *r, int x, int y, + int width, int height, void *out_data) { + r->impl->read_pixels(r, x, y, width, height, out_data); +} diff --git a/rootston/desktop.c b/rootston/desktop.c index 65333e77..c10cd641 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -182,7 +182,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->screenshooter = wlr_screenshooter_create(server->wl_display, + server->renderer); return desktop; } diff --git a/types/wlr_output.c b/types/wlr_output.c index 1db63151..64f67f2d 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -250,20 +250,3 @@ uint16_t wlr_output_get_gamma_size(struct wlr_output *output) { } return output->impl->get_gamma_size(output); } - -static void rgba_to_argb(uint32_t *data, size_t height, size_t stride) { - size_t n = height*stride/4; - for (size_t i = 0; i < n; ++i) { - uint32_t v = data[i]; - uint32_t rgb = (v & 0xffffff00) >> 8; - uint32_t a = v & 0x000000ff; - data[i] = rgb | (a << 24); - } -} - -void wlr_output_read_pixels(struct wlr_output *output, void *out_data) { - wlr_output_make_current(output); - glReadPixels(0, 0, output->width, output->height, GL_RGBA, GL_UNSIGNED_BYTE, - out_data); - rgba_to_argb(out_data, output->height, output->width*4); -} diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index ddcaf52b..38204aa1 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ struct screenshot_state { int32_t width, height, stride; uint8_t *pixels; struct wl_shm_buffer *shm_buffer; - struct wlr_output *output; struct wlr_screenshot *screenshot; struct wl_listener frame_listener; }; @@ -29,8 +29,12 @@ struct screenshot_state { static void output_frame_notify(struct wl_listener *listener, void *_data) { struct screenshot_state *state = wl_container_of(listener, state, frame_listener); + struct wlr_renderer *renderer = state->screenshot->screenshooter->renderer; + struct wlr_output *output = state->screenshot->output; - wlr_output_read_pixels(state->output, state->pixels); + wlr_output_make_current(output); + wlr_renderer_read_pixels(renderer, 0, 0, output->width, output->height, + state->pixels); void *data = wl_shm_buffer_get_data(state->shm_buffer); wl_shm_buffer_begin_access(state->shm_buffer); @@ -49,6 +53,8 @@ static void output_frame_notify(struct wl_listener *listener, void *_data) { static void screenshooter_shoot(struct wl_client *client, struct wl_resource *_screenshooter, uint32_t id, struct wl_resource *_output, struct wl_resource *_buffer) { + struct wlr_screenshooter *screenshooter = + wl_resource_get_user_data(_screenshooter); struct wlr_output *output = wl_resource_get_user_data(_output); if (!wl_shm_buffer_get(_buffer)) { wlr_log(L_ERROR, "Invalid buffer: not a shared memory buffer"); @@ -81,7 +87,9 @@ static void screenshooter_shoot(struct wl_client *client, wl_client_post_no_memory(client); return; } - screenshot->output = _output; + screenshot->output_resource = _output; + screenshot->output = output; + screenshot->screenshooter = screenshooter; screenshot->resource = wl_resource_create(client, &orbital_screenshot_interface, wl_resource_get_version(_screenshooter), id); @@ -91,12 +99,15 @@ static void screenshooter_shoot(struct wl_client *client, NULL); struct screenshot_state *state = calloc(1, sizeof(struct screenshot_state)); + if (!state) { + wl_client_post_no_memory(client); + return; + } state->width = width; state->height = height; state->stride = stride; state->pixels = pixels; state->shm_buffer = shm_buffer; - state->output = output; state->screenshot = screenshot; state->frame_listener.notify = output_frame_notify; wl_signal_add(&output->events.swap_buffers, &state->frame_listener); @@ -122,12 +133,15 @@ static void screenshooter_bind(struct wl_client *wl_client, screenshooter, NULL); } -struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display) { +struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display, + struct wlr_renderer *renderer) { struct wlr_screenshooter *screenshooter = calloc(1, sizeof(struct wlr_screenshooter)); if (!screenshooter) { return NULL; } + screenshooter->renderer = renderer; + struct wl_global *wl_global = wl_global_create(display, &orbital_screenshooter_interface, 1, screenshooter, screenshooter_bind); if (!wl_global) { @@ -135,6 +149,7 @@ struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display) { return NULL; } screenshooter->wl_global = wl_global; + return screenshooter; }