gallium/swrast: fix front buffer blitting. (v2)
authorDave Airlie <airlied@redhat.com>
Fri, 9 Oct 2015 00:38:08 +0000 (01:38 +0100)
committerDave Airlie <airlied@gmail.com>
Sat, 31 Oct 2015 06:04:36 +0000 (16:04 +1000)
So I've known this was broken before, cogl has a workaround
for it from what I know, but with the gallium based swrast
drivers BlitFramebuffer from back to front or vice-versa
was pretty broken.

The legacy swrast driver tracks when a front buffer is used
and does the get/put images when it is mapped/unmapped,
so this patch attempts to add the same functionality to the
gallium drivers.

It creates a new context interface to denote when a front
buffer is being created, and passes a private pointer to it,
this pointer is then used to decide on map/unmap if the
contents should be updated from the real frontbuffer using
get/put image.

This is primarily to make gtk's gl code work, the only
thing I've tested so far is the glarea test from
https://github.com/ebassi/glarea-example.git

v2: bump extension version,
check extension version before calling get image. (Ian)

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91930

Cc: <mesa-stable@lists.freedesktop.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
include/GL/internal/dri_interface.h
src/gallium/drivers/llvmpipe/lp_texture.c
src/gallium/drivers/softpipe/sp_texture.c
src/gallium/include/pipe/p_screen.h
src/gallium/include/state_tracker/drisw_api.h
src/gallium/include/state_tracker/sw_winsys.h
src/gallium/state_trackers/dri/drisw.c
src/gallium/winsys/sw/dri/dri_sw_winsys.c
src/glx/drisw_glx.c

index a0f155a1f4220af3aea9c9bb2f9ef9611e49c35e..6bbd3fa87f52ff210db3ae930025da058d6f9ed5 100644 (file)
@@ -495,7 +495,7 @@ struct __DRIdamageExtensionRec {
  * SWRast Loader extension.
  */
 #define __DRI_SWRAST_LOADER "DRI_SWRastLoader"
-#define __DRI_SWRAST_LOADER_VERSION 2
+#define __DRI_SWRAST_LOADER_VERSION 3
 struct __DRIswrastLoaderExtensionRec {
     __DRIextension base;
 
@@ -528,6 +528,15 @@ struct __DRIswrastLoaderExtensionRec {
     void (*putImage2)(__DRIdrawable *drawable, int op,
                       int x, int y, int width, int height, int stride,
                       char *data, void *loaderPrivate);
+
+   /**
+     * Put image to drawable
+     *
+     * \since 3
+     */
+   void (*getImage2)(__DRIdrawable *readable,
+                    int x, int y, int width, int height, int stride,
+                    char *data, void *loaderPrivate);
 };
 
 /**
index af46342fdf2fef7eec21a527b234a433b3b742b0..7862ac8f2173002065092540b49caa776ff48633 100644 (file)
@@ -200,7 +200,8 @@ llvmpipe_can_create_resource(struct pipe_screen *screen,
 
 static boolean
 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
-                              struct llvmpipe_resource *lpr)
+                              struct llvmpipe_resource *lpr,
+                              const void *map_front_private)
 {
    struct sw_winsys *winsys = screen->winsys;
 
@@ -215,12 +216,13 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
                                           lpr->base.format,
                                           width, height,
                                           64,
+                                          map_front_private,
                                           &lpr->row_stride[0] );
 
    if (lpr->dt == NULL)
       return FALSE;
 
-   {
+   if (!map_front_private) {
       void *map = winsys->displaytarget_map(winsys, lpr->dt,
                                             PIPE_TRANSFER_WRITE);
 
@@ -235,8 +237,9 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
 
 
 static struct pipe_resource *
-llvmpipe_resource_create(struct pipe_screen *_screen,
-                         const struct pipe_resource *templat)
+llvmpipe_resource_create_front(struct pipe_screen *_screen,
+                               const struct pipe_resource *templat,
+                               const void *map_front_private)
 {
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
@@ -254,7 +257,7 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
                             PIPE_BIND_SCANOUT |
                             PIPE_BIND_SHARED)) {
          /* displayable surface */
-         if (!llvmpipe_displaytarget_layout(screen, lpr))
+         if (!llvmpipe_displaytarget_layout(screen, lpr, map_front_private))
             goto fail;
       }
       else {
@@ -300,7 +303,12 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
    FREE(lpr);
    return NULL;
 }
-
+static struct pipe_resource *
+llvmpipe_resource_create(struct pipe_screen *_screen,
+                         const struct pipe_resource *templat)
+{
+   return llvmpipe_resource_create_front(_screen, templat, NULL);
+}
 
 static void
 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
@@ -797,6 +805,7 @@ llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
 #endif
 
    screen->resource_create = llvmpipe_resource_create;
+   screen->resource_create_front = llvmpipe_resource_create_front;
    screen->resource_destroy = llvmpipe_resource_destroy;
    screen->resource_from_handle = llvmpipe_resource_from_handle;
    screen->resource_get_handle = llvmpipe_resource_get_handle;
index e1ea5df24ca420a1dbe836cf8a9ae597c855c2dc..3347f5f1883bed50ac0f0666caf0ca4ade08fe4b 100644 (file)
@@ -127,7 +127,8 @@ softpipe_can_create_resource(struct pipe_screen *screen,
  */
 static boolean
 softpipe_displaytarget_layout(struct pipe_screen *screen,
-                              struct softpipe_resource *spr)
+                              struct softpipe_resource *spr,
+                              const void *map_front_private)
 {
    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
 
@@ -139,6 +140,7 @@ softpipe_displaytarget_layout(struct pipe_screen *screen,
                                           spr->base.width0, 
                                           spr->base.height0,
                                           64,
+                                          map_front_private,
                                           &spr->stride[0] );
 
    return spr->dt != NULL;
@@ -149,8 +151,9 @@ softpipe_displaytarget_layout(struct pipe_screen *screen,
  * Create new pipe_resource given the template information.
  */
 static struct pipe_resource *
-softpipe_resource_create(struct pipe_screen *screen,
-                         const struct pipe_resource *templat)
+softpipe_resource_create_front(struct pipe_screen *screen,
+                               const struct pipe_resource *templat,
+                               const void *map_front_private)
 {
    struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
    if (!spr)
@@ -169,7 +172,7 @@ softpipe_resource_create(struct pipe_screen *screen,
    if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
                         PIPE_BIND_SCANOUT |
                         PIPE_BIND_SHARED)) {
-      if (!softpipe_displaytarget_layout(screen, spr))
+      if (!softpipe_displaytarget_layout(screen, spr, map_front_private))
          goto fail;
    }
    else {
@@ -184,6 +187,12 @@ softpipe_resource_create(struct pipe_screen *screen,
    return NULL;
 }
 
+static struct pipe_resource *
+softpipe_resource_create(struct pipe_screen *screen,
+                         const struct pipe_resource *templat)
+{
+   return softpipe_resource_create_front(screen, templat, NULL);
+}
 
 static void
 softpipe_resource_destroy(struct pipe_screen *pscreen,
@@ -514,6 +523,7 @@ void
 softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
 {
    screen->resource_create = softpipe_resource_create;
+   screen->resource_create_front = softpipe_resource_create_front;
    screen->resource_destroy = softpipe_resource_destroy;
    screen->resource_from_handle = softpipe_resource_from_handle;
    screen->resource_get_handle = softpipe_resource_get_handle;
index a22fb938dbb7a66eb283527a20454c89b76fe818..f868d71db231da9ca6945ba83dff15c4d8164634 100644 (file)
@@ -169,6 +169,10 @@ struct pipe_screen {
    struct pipe_resource * (*resource_create)(struct pipe_screen *,
                                             const struct pipe_resource *templat);
 
+   struct pipe_resource * (*resource_create_front)(struct pipe_screen *,
+                                                   const struct pipe_resource *templat,
+                                                   const void *map_front_private);
+
    /**
     * Create a texture from a winsys_handle. The handle is often created in
     * another process by first creating a pipe texture and then calling
index 328440cf5ffe76be9e454f95e4cb65fad2cc62c6..cd5a27e2482c9da0a2fd696651d25d10dc79c04a 100644 (file)
@@ -11,6 +11,9 @@ struct dri_drawable;
  */
 struct drisw_loader_funcs
 {
+   void (*get_image) (struct dri_drawable *dri_drawable,
+                      int x, int y, unsigned width, unsigned height, unsigned stride,
+                      void *data);
    void (*put_image) (struct dri_drawable *dri_drawable,
                       void *data, unsigned width, unsigned height);
    void (*put_image2) (struct dri_drawable *dri_drawable,
index a3479eb0bc38132c3fc3d83d4fad057c509f2b24..0b792cd0ce4c4e9c82374cbfecaf6203dd3026b6 100644 (file)
@@ -90,6 +90,7 @@ struct sw_winsys
                             enum pipe_format format,
                             unsigned width, unsigned height,
                             unsigned alignment,
+                            const void *front_private,
                             unsigned *stride );
 
    /**
index 4ec6992643a23e7455bad46c8f7c62f1644ea8b3..753c59d696a8e69509c52d7e84bf9a255afed551 100644 (file)
@@ -95,6 +95,21 @@ get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)
                     data, dPriv->loaderPrivate);
 }
 
+static inline void
+get_image2(__DRIdrawable *dPriv, int x, int y, int width, int height, int stride, void *data)
+{
+   __DRIscreen *sPriv = dPriv->driScreenPriv;
+   const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
+
+   /* getImage2 support is only in version 3 or newer */
+   if (loader->base.version < 3)
+      return;
+
+   loader->getImage2(dPriv,
+                     x, y, width, height, stride,
+                     data, dPriv->loaderPrivate);
+}
+
 static void
 drisw_update_drawable_info(struct dri_drawable *drawable)
 {
@@ -104,6 +119,18 @@ drisw_update_drawable_info(struct dri_drawable *drawable)
    get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h);
 }
 
+static void
+drisw_get_image(struct dri_drawable *drawable,
+                int x, int y, unsigned width, unsigned height, unsigned stride,
+                void *data)
+{
+   __DRIdrawable *dPriv = drawable->dPriv;
+   int draw_x, draw_y, draw_w, draw_h;
+
+   get_drawable_info(dPriv, &draw_x, &draw_y, &draw_w, &draw_h);
+   get_image2(dPriv, x, y, draw_w, draw_h, stride, data);
+}
+
 static void
 drisw_put_image(struct dri_drawable *drawable,
                 void *data, unsigned width, unsigned height)
@@ -236,6 +263,7 @@ drisw_allocate_textures(struct dri_context *stctx,
                         unsigned count)
 {
    struct dri_screen *screen = dri_screen(drawable->sPriv);
+   const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader;
    struct pipe_resource templ;
    unsigned width, height;
    boolean resized;
@@ -281,8 +309,14 @@ drisw_allocate_textures(struct dri_context *stctx,
       templ.format = format;
       templ.bind = bind;
 
-      drawable->textures[statts[i]] =
-         screen->base.screen->resource_create(screen->base.screen, &templ);
+      if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
+          screen->base.screen->resource_create_front &&
+          loader->base.version >= 3) {
+         drawable->textures[statts[i]] =
+            screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
+      } else
+         drawable->textures[statts[i]] =
+            screen->base.screen->resource_create(screen->base.screen, &templ);
    }
 
    drawable->old_w = width;
@@ -338,6 +372,7 @@ static const __DRIextension *drisw_screen_extensions[] = {
 };
 
 static struct drisw_loader_funcs drisw_lf = {
+   .get_image = drisw_get_image,
    .put_image = drisw_put_image,
    .put_image2 = drisw_put_image2
 };
index 8451d832806b32ce646c1ec5c2f910d3b6723f05..5c98f2603c71444791f17596e4d7b549f82b2230 100644 (file)
@@ -44,8 +44,10 @@ struct dri_sw_displaytarget
    unsigned height;
    unsigned stride;
 
+   unsigned map_flags;
    void *data;
    void *mapped;
+   const void *front_private;
 };
 
 struct dri_sw_winsys
@@ -83,6 +85,7 @@ dri_sw_displaytarget_create(struct sw_winsys *winsys,
                             enum pipe_format format,
                             unsigned width, unsigned height,
                             unsigned alignment,
+                            const void *front_private,
                             unsigned *stride)
 {
    struct dri_sw_displaytarget *dri_sw_dt;
@@ -95,6 +98,7 @@ dri_sw_displaytarget_create(struct sw_winsys *winsys,
    dri_sw_dt->format = format;
    dri_sw_dt->width = width;
    dri_sw_dt->height = height;
+   dri_sw_dt->front_private = front_private;
 
    format_stride = util_format_get_stride(format, width);
    dri_sw_dt->stride = align(format_stride, alignment);
@@ -133,6 +137,12 @@ dri_sw_displaytarget_map(struct sw_winsys *ws,
 {
    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
    dri_sw_dt->mapped = dri_sw_dt->data;
+
+   if (dri_sw_dt->front_private && (flags & PIPE_TRANSFER_READ)) {
+      struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
+      dri_sw_ws->lf->get_image((void *)dri_sw_dt->front_private, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride, dri_sw_dt->data);
+   }
+   dri_sw_dt->map_flags = flags;
    return dri_sw_dt->mapped;
 }
 
@@ -141,6 +151,11 @@ dri_sw_displaytarget_unmap(struct sw_winsys *ws,
                            struct sw_displaytarget *dt)
 {
    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
+   if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_TRANSFER_WRITE)) {
+      struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
+      dri_sw_ws->lf->put_image2((void *)dri_sw_dt->front_private, dri_sw_dt->data, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride);
+   }
+   dri_sw_dt->map_flags = 0;
    dri_sw_dt->mapped = NULL;
 }
 
index 749ceb08aacbc9e9ece0ff1b95b3993b42ca0f7c..76cc3214b7bbefefa296e99f77705a1c9843f962 100644 (file)
@@ -177,9 +177,9 @@ swrastPutImage(__DRIdrawable * draw, int op,
 }
 
 static void
-swrastGetImage(__DRIdrawable * read,
-               int x, int y, int w, int h,
-               char *data, void *loaderPrivate)
+swrastGetImage2(__DRIdrawable * read,
+                int x, int y, int w, int h, int stride,
+                char *data, void *loaderPrivate)
 {
    struct drisw_drawable *prp = loaderPrivate;
    __GLXDRIdrawable *pread = &(prp->base);
@@ -193,20 +193,29 @@ swrastGetImage(__DRIdrawable * read,
    ximage->data = data;
    ximage->width = w;
    ximage->height = h;
-   ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
+   ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
 
    XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
 
    ximage->data = NULL;
 }
 
+static void
+swrastGetImage(__DRIdrawable * read,
+               int x, int y, int w, int h,
+               char *data, void *loaderPrivate)
+{
+   swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate);
+}
+
 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
-   .base = {__DRI_SWRAST_LOADER, 2 },
+   .base = {__DRI_SWRAST_LOADER, 3 },
 
    .getDrawableInfo     = swrastGetDrawableInfo,
    .putImage            = swrastPutImage,
    .getImage            = swrastGetImage,
    .putImage2           = swrastPutImage2,
+   .getImage2           = swrastGetImage2,
 };
 
 static const __DRIextension *loader_extensions[] = {