From 1ff7bbb0d3bf0ca467a6c68ff9e5ed9e53aeaa1b Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Wed, 20 Jul 2022 19:57:48 -0400 Subject: [PATCH] render/gles2: produce 16f screencopy data This commit introduces fairly awkward code to work around that fact that the GL ES implementation is allowed to provide either of the two distinct constants GL_HALF_FLOAT and GL_HALF_FLOAT_OES as the gl_type to use when reading data from a render buffer created from a DMABUF with half-float channels. The 'GLES3/gl3.h' header is also provided by the pkg-config library confusingly called 'glesv2', so no build changes are necessary. --- render/gles2/pixel_format.c | 11 +++++++++++ render/gles2/renderer.c | 23 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index acaac5ceb..aa196ff03 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "render/gles2.h" /* @@ -150,6 +151,16 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_drm(uint32_t fmt) { const struct wlr_gles2_pixel_format *get_gles2_format_from_gl( GLint gl_format, GLint gl_type, bool alpha) { + // Mesa may provide GL ES >= 3.0 instead of the minimum asked for 2.0; + // in this case, the gl_type associated to render buffers created from + // half float DMABUFs _may_ be the value GL_HALF_FLOAT = 0x140b from + // GL ES 3.0, not the value GL_HALF_FLOAT_OES = 0x8D61 from GL ES 2.0 + // extension OES_texture_half_float, which is used to define texture + // images for half-float shm buffers. + if (gl_type == GL_HALF_FLOAT) { + gl_type = GL_HALF_FLOAT_OES; + } + for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) { if (formats[i].gl_format == gl_format && formats[i].gl_type == gl_type && diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 6a86b1832..e19c6c8be 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -467,6 +467,23 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, push_gles2_debug(renderer); + // The 16F buffer formats have more than one possible color read + // format/type combination; the type can be GL_HALF_FLOAT = 0x140b, + // if the GLES implementation version is >= 3.0, or could be + // GL_HALF_FLOAT_OES (which would be appropriate at GLES 2.0.) + // To match glReadPixels' strict requirements on format+type, + // we submit exactly the implementation suggested format and type, + // if these are compatible with the drm_format. + GLint gl_format = -1, gl_type = -1; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format); + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type); + const struct wlr_gles2_pixel_format *impl_format = + get_gles2_format_from_gl(gl_format, gl_type, fmt->has_alpha); + if (impl_format != fmt) { + gl_format = fmt->gl_format; + gl_type = fmt->gl_type; + } + // Make sure any pending drawing is finished before we try to read it glFinish(); @@ -478,14 +495,14 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, // 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, src_y, width, height, gl_format, gl_type, p); } else { // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read // the lines out row by row for (size_t i = 0; i < height; ++i) { uint32_t y = src_y + i; - glReadPixels(src_x, y, width, 1, fmt->gl_format, - fmt->gl_type, p + i * stride + dst_x * drm_fmt->bpp / 8); + glReadPixels(src_x, y, width, 1, gl_format, + gl_type, p + i * stride + dst_x * drm_fmt->bpp / 8); } }