From b1606a9f2cff9043d0219e7f7615c5c5f276064b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 6 Jun 2023 14:58:57 +0200 Subject: [PATCH] gl-renderer: support automatically downloading FBO renderbuffers For software backends like VNC, support downloading the FBO renderbuffer contents via glReadPixels automatically at the end of repaint_output. Signed-off-by: Philipp Zabel --- libweston/backend-headless/headless.c | 2 +- libweston/renderer-gl/gl-renderer.c | 39 +++++++++++++++++++++++++-- libweston/renderer-gl/gl-renderer.h | 8 ++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/libweston/backend-headless/headless.c b/libweston/backend-headless/headless.c index 377b42867..40c51d611 100644 --- a/libweston/backend-headless/headless.c +++ b/libweston/backend-headless/headless.c @@ -294,7 +294,7 @@ headless_output_enable_gl(struct headless_output *output) output->renderbuffer = renderer->gl->create_fbo(&output->base, b->formats[0], options.fb_size.width, - options.fb_size.height); + options.fb_size.height, NULL); if (!output->renderbuffer) goto err_renderbuffer; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 210617dbe..524e09839 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -94,6 +94,7 @@ struct gl_renderbuffer { /* The fbo value zero represents the default surface framebuffer. */ GLuint fbo; GLuint rb; + uint32_t *pixels; struct wl_list link; int age; }; @@ -760,7 +761,7 @@ gl_renderer_create_dummy_renderbuffer(struct weston_output *output) static struct weston_renderbuffer * gl_renderer_create_fbo(struct weston_output *output, const struct pixel_format_info *format, - int width, int height) + int width, int height, uint32_t *pixels) { struct gl_renderer *gr = get_renderer(output->compositor); struct gl_output_state *go = get_output_state(output); @@ -805,6 +806,8 @@ gl_renderer_create_fbo(struct weston_output *output, return NULL; } + renderbuffer->pixels = pixels; + pixman_region32_init(&renderbuffer->base.damage); /* * One reference is kept on the renderbuffer_list, @@ -2028,7 +2031,6 @@ gl_renderer_repaint_output(struct weston_output *output, glFlush(); } - pixman_region32_clear(&rb->base.damage); rb->border_damage = BORDER_STATUS_CLEAN; go->border_status = BORDER_STATUS_CLEAN; @@ -2040,6 +2042,39 @@ gl_renderer_repaint_output(struct weston_output *output, update_buffer_release_fences(compositor, output); + if (rb->pixels) { + uint32_t *pixels = rb->pixels; + int stride = go->fb_size.width; + pixman_box32_t *extents = &rb->base.damage.extents; + struct weston_geometry rect = { + .x = go->area.x, + .width = go->area.width, + }; + + if (gr->fan_debug) { + rect.y = go->fb_size.height - go->area.y - go->area.height; + rect.height = go->area.height; + } else { + rect.y = go->fb_size.height - go->area.y - extents->y2; + rect.height = extents->y2 - extents->y1; + pixels += rect.width * extents->y1; + } + + if (gr->gl_version >= gr_gl_version(3, 0) && ! gr->fan_debug) { + glPixelStorei(GL_PACK_ROW_LENGTH, stride); + rect.width = extents->x2 - extents->x1; + rect.x += extents->x1; + pixels += extents->x1; + } + + gl_renderer_do_read_pixels(gr, compositor->read_format, pixels, stride, &rect); + + if (gr->gl_version >= gr_gl_version(3, 0)) + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + } + + pixman_region32_clear(&rb->base.damage); + gl_renderer_garbage_collect_programs(gr); } diff --git a/libweston/renderer-gl/gl-renderer.h b/libweston/renderer-gl/gl-renderer.h index 765457744..6fc7f6f03 100644 --- a/libweston/renderer-gl/gl-renderer.h +++ b/libweston/renderer-gl/gl-renderer.h @@ -222,12 +222,16 @@ struct gl_renderer_interface { * \param format The renderbuffer pixel format. * \param width The renderbuffer width. * \param height The renderbuffer height. + * \param pixels Optional buffer to download the pixels to after rendering. * \return 0 on success, -1 on failure. * * This function creates an FBO renderbuffer that can be passed to \c - * repaint_output. + * repaint_output. If pixels is non-NULL, repaint_output will call + * glReadPixels to download pixel data into the provided buffer after + * repaint. */ struct weston_renderbuffer *(*create_fbo)(struct weston_output *output, const struct pixel_format_info *format, - int width, int height); + int width, int height, + uint32_t *pixels); };