From c7617d8908a970124321ce731b43d5996c3c5775 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mathias=20Fr=C3=B6hlich?= Date: Fri, 13 Dec 2019 17:09:56 +0100 Subject: [PATCH] egl: Implement getImage/putImage on pbuffer swrast. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This change adds getImage/putImage callbacks to the swrast pbuffer loader extension. This fixes a recent crash with Weston as well as a crashing test with classic swrast without an official gitlab issue. v2: Determine bytes per pixel differently and fix non X11 builds. v3: Plug memory leak and fix crash on out of bounds access. (Daniel Stone) v4: Follow the code structure of the wayland get/put image implementation - hopefully being more obvious. Handle 64 bits formats. Use BufferSize directly. (Emil Velikov) v5: Change pixel size computation. (Eric Engestrom) Reviewed-by: Daniel Stone Reviewed-by: Emil Velikov Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/2219 Fixes: d6edccee8da "egl: add EGL_platform_device support" Signed-off-by: Mathias Fröhlich Tested-by: Marge Bot Part-of: --- src/egl/drivers/dri2/egl_dri2.c | 92 +++++++++++++++++++-- src/egl/drivers/dri2/egl_dri2.h | 3 + src/egl/drivers/dri2/platform_device.c | 3 + src/egl/drivers/dri2/platform_surfaceless.c | 3 + 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index b418d81c56b..5e497b79bc4 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -66,6 +66,7 @@ #include "util/u_vector.h" #include "mapi/glapi/glapi.h" #include "util/bitscan.h" +#include "util/u_math.h" /* Additional definitions not yet in the drm_fourcc.h. */ @@ -162,15 +163,96 @@ dri2_get_pbuffer_drawable_info(__DRIdrawable * draw, *h = dri2_surf->base.Height; } -/* HACK: technically we should have swrast_null, instead of these. We - * get away since only pbuffers are supported, thus the callbacks are - * unused. +static int +dri2_get_bytes_per_pixel(struct dri2_egl_surface *dri2_surf) +{ + const int depth = dri2_surf->base.Config->BufferSize; + return depth ? util_next_power_of_two(depth / 8) : 0; +} + +static void +dri2_put_image(__DRIdrawable * draw, int op, + int x, int y, int w, int h, + char *data, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + const int bpp = dri2_get_bytes_per_pixel(dri2_surf); + const int width = dri2_surf->base.Width; + const int height = dri2_surf->base.Height; + const int dst_stride = width*bpp; + const int src_stride = w*bpp; + const int x_offset = x*bpp; + int copy_width = src_stride; + + if (!dri2_surf->swrast_device_buffer) + dri2_surf->swrast_device_buffer = malloc(height*dst_stride); + + if (dri2_surf->swrast_device_buffer) { + const char *src = data; + char *dst = dri2_surf->swrast_device_buffer; + + dst += x_offset; + dst += y*dst_stride; + + /* Drivers are allowed to submit OOB PutImage requests, so clip here. */ + if (copy_width > dst_stride - x_offset) + copy_width = dst_stride - x_offset; + if (h > height - y) + h = height - y; + + for (; 0 < h; --h) { + memcpy(dst, src, copy_width); + dst += dst_stride; + src += src_stride; + } + } +} + +static void +dri2_get_image(__DRIdrawable * read, + int x, int y, int w, int h, + char *data, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + const int bpp = dri2_get_bytes_per_pixel(dri2_surf); + const int width = dri2_surf->base.Width; + const int height = dri2_surf->base.Height; + const int src_stride = width*bpp; + const int dst_stride = w*bpp; + const int x_offset = x*bpp; + int copy_width = dst_stride; + const char *src = dri2_surf->swrast_device_buffer; + char *dst = data; + + if (!src) { + memset(data, 0, copy_width * h); + return; + } + + src += x_offset; + src += y*src_stride; + + /* Drivers are allowed to submit OOB GetImage requests, so clip here. */ + if (copy_width > src_stride - x_offset) + copy_width = src_stride - x_offset; + if (h > height - y) + h = height - y; + + for (; 0 < h; --h) { + memcpy(dst, src, copy_width); + src += src_stride; + dst += dst_stride; + } + +} + +/* HACK: technically we should have swrast_null, instead of these. */ const __DRIswrastLoaderExtension swrast_pbuffer_loader_extension = { .base = { __DRI_SWRAST_LOADER, 1 }, .getDrawableInfo = dri2_get_pbuffer_drawable_info, - .putImage = NULL, - .getImage = NULL, + .putImage = dri2_put_image, + .getImage = dri2_get_image, }; static const EGLint dri2_to_egl_attribute_map[__DRI_ATTRIB_MAX] = { diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 146f954eacf..8272da886ee 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -338,6 +338,9 @@ struct dri2_egl_surface int out_fence_fd; EGLBoolean enable_out_fence; + + /* swrast device */ + char *swrast_device_buffer; }; struct dri2_egl_config diff --git a/src/egl/drivers/dri2/platform_device.c b/src/egl/drivers/dri2/platform_device.c index 9bd7a93270d..eb2a743b01d 100644 --- a/src/egl/drivers/dri2/platform_device.c +++ b/src/egl/drivers/dri2/platform_device.c @@ -66,6 +66,9 @@ device_free_images(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->destroyImage(dri2_surf->front); dri2_surf->front = NULL; } + + free(dri2_surf->swrast_device_buffer); + dri2_surf->swrast_device_buffer = NULL; } static int diff --git a/src/egl/drivers/dri2/platform_surfaceless.c b/src/egl/drivers/dri2/platform_surfaceless.c index 1a2d3be0aad..19d28aa61ab 100644 --- a/src/egl/drivers/dri2/platform_surfaceless.c +++ b/src/egl/drivers/dri2/platform_surfaceless.c @@ -60,6 +60,9 @@ surfaceless_free_images(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->destroyImage(dri2_surf->front); dri2_surf->front = NULL; } + + free(dri2_surf->swrast_device_buffer); + dri2_surf->swrast_device_buffer = NULL; } static int -- 2.30.2