egl: Implement getImage/putImage on pbuffer swrast.
authorMathias Fröhlich <mathias.froehlich@web.de>
Fri, 13 Dec 2019 16:09:56 +0000 (17:09 +0100)
committerDaniel Stone <daniels@collabora.com>
Mon, 17 Feb 2020 04:01:37 +0000 (04:01 +0000)
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 <daniels@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/2219
Fixes: d6edccee8da "egl: add EGL_platform_device support"
Signed-off-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3711>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3711>

src/egl/drivers/dri2/egl_dri2.c
src/egl/drivers/dri2/egl_dri2.h
src/egl/drivers/dri2/platform_device.c
src/egl/drivers/dri2/platform_surfaceless.c

index b418d81..5e497b7 100644 (file)
@@ -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] = {
index 146f954..8272da8 100644 (file)
@@ -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
index 9bd7a93..eb2a743 100644 (file)
@@ -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
index 1a2d3be..19d28aa 100644 (file)
@@ -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