[Mesa-dev] [PATCH 1/4] gallium/swrast: fix software blitting with front buffers

Karl Lessard karl at kubx.ca
Sat Jan 21 04:13:29 UTC 2017


This patch is mainly a workaround of commit
2b676570960277d47477822ffeccc672613f914 and fixes many problems with
framebuffer blitting in software drivers when the front buffer is
involved. It resolves regression issues listed above but also problems
with gtk-gl applications (like
https://github.com/ebassi/glarea-example.git, which was still
broken).

The new idea is to keep track of when a resource such as a fake front
buffer needs to be refreshed from the drawable data before being mapped
for read/write operations:

Every time a resource is being written/displayed to the drawable, a
"snapshot" number is increased and set to both the resource and the
drawable. If the snapshot number of the front buffer does not
match the drawable one at map time, it means that another resource has
been displayed meanwhile and therefore, a refresh is required.

Signed-off-by: Karl Lessard <karl at kubx.ca>
Bugzilla [1]: https://bugs.freedesktop.org/show_bug.cgi?id=92954
Bugzilla [2]: https://bugs.freedesktop.org/show_bug.cgi?id=92946
Bugzilla [3]: https://bugs.freedesktop.org/show_bug.cgi?id=93203 
---
 src/gallium/include/pipe/p_defines.h          |  5 +++
 src/gallium/include/state_tracker/drisw_api.h |  7 ++++
 src/gallium/include/state_tracker/sw_winsys.h |  2 +-
 src/gallium/state_trackers/dri/dri_drawable.c |  2 --
 src/gallium/state_trackers/dri/dri_drawable.h |  2 +-
 src/gallium/state_trackers/dri/drisw.c        | 46 +++++++++++++++++++++------
 src/gallium/winsys/sw/dri/dri_sw_winsys.c     | 38 +++++++++++++++++-----
 7 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 3eb5b3b..342923e 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -451,6 +451,11 @@ enum pipe_flush_flags
 #define PIPE_BIND_SHARED      (1 << 20) /* get_texture_handle ??? */
 #define PIPE_BIND_LINEAR      (1 << 21)
 
+/**
+ * This flag, in addition to PIPE_BIND_DISPLAY_TARGET, ensure that the resource
+ * will be kept in sync with any changes that could occur on the display.
+ */
+#define PIPE_BIND_DISPLAY_SYNC  (1 << 22)
 
 /**
  * Flags for the driver about resource behaviour:
diff --git a/src/gallium/include/state_tracker/drisw_api.h b/src/gallium/include/state_tracker/drisw_api.h
index 03d5ee4..ca0b361 100644
--- a/src/gallium/include/state_tracker/drisw_api.h
+++ b/src/gallium/include/state_tracker/drisw_api.h
@@ -20,4 +20,11 @@ struct drisw_loader_funcs
                        void *data, int x, int y, unsigned width, unsigned height, unsigned stride);
 };
 
+struct drisw_drawable_ref
+{
+   struct dri_drawable *handle;
+
+   uint32_t current_snapshot_nb;
+};
+
 #endif
diff --git a/src/gallium/include/state_tracker/sw_winsys.h b/src/gallium/include/state_tracker/sw_winsys.h
index 0b792cd..d1342cd 100644
--- a/src/gallium/include/state_tracker/sw_winsys.h
+++ b/src/gallium/include/state_tracker/sw_winsys.h
@@ -90,7 +90,7 @@ struct sw_winsys
                             enum pipe_format format,
                             unsigned width, unsigned height,
                             unsigned alignment,
-                            const void *front_private,
+                            const void *winsys_private,
                             unsigned *stride );
 
    /**
diff --git a/src/gallium/state_trackers/dri/dri_drawable.c b/src/gallium/state_trackers/dri/dri_drawable.c
index edcd0e6..854b14a 100644
--- a/src/gallium/state_trackers/dri/dri_drawable.c
+++ b/src/gallium/state_trackers/dri/dri_drawable.c
@@ -168,8 +168,6 @@ dri_destroy_buffer(__DRIdrawable * dPriv)
    struct dri_drawable *drawable = dri_drawable(dPriv);
    int i;
 
-   pipe_surface_reference(&drawable->drisw_surface, NULL);
-
    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
       pipe_resource_reference(&drawable->textures[i], NULL);
    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
diff --git a/src/gallium/state_trackers/dri/dri_drawable.h b/src/gallium/state_trackers/dri/dri_drawable.h
index 1f9842e..3829232 100644
--- a/src/gallium/state_trackers/dri/dri_drawable.h
+++ b/src/gallium/state_trackers/dri/dri_drawable.h
@@ -68,7 +68,7 @@ struct dri_drawable
    boolean flushing; /* prevents recursion in dri_flush */
 
    /* used only by DRISW */
-   struct pipe_surface *drisw_surface;
+   struct drisw_drawable_ref *drisw_reference;
 
    /* hooks filled in by dri2 & drisw */
    void (*allocate_textures)(struct dri_context *ctx,
diff --git a/src/gallium/state_trackers/dri/drisw.c b/src/gallium/state_trackers/dri/drisw.c
index b85a73c..072ba07 100644
--- a/src/gallium/state_trackers/dri/drisw.c
+++ b/src/gallium/state_trackers/dri/drisw.c
@@ -264,7 +264,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_screen *pscreen = screen->base.screen;
    struct pipe_resource templ;
    unsigned width, height;
    boolean resized;
@@ -301,23 +301,28 @@ drisw_allocate_textures(struct dri_context *stctx,
       dri_drawable_get_format(drawable, statts[i], &format, &bind);
 
       /* if we don't do any present, no need for display targets */
-      if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present)
+      if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present) {
          bind |= PIPE_BIND_DISPLAY_TARGET;
 
+         if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
+            bind |= PIPE_BIND_DISPLAY_SYNC;
+         }
+      }
+
       if (format == PIPE_FORMAT_NONE)
          continue;
 
       templ.format = format;
       templ.bind = bind;
 
-      if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
-          screen->base.screen->resource_create_front &&
-          loader->base.version >= 3) {
+      if (pscreen->resource_create_front) {
          drawable->textures[statts[i]] =
-            screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
-      } else
+            pscreen->resource_create_front(pscreen, &templ, (const void *)drawable->drisw_reference);
+
+      } else {
          drawable->textures[statts[i]] =
-            screen->base.screen->resource_create(screen->base.screen, &templ);
+            pscreen->resource_create(pscreen, &templ);
+      }
    }
 
    drawable->old_w = width;
@@ -422,6 +427,7 @@ drisw_create_buffer(__DRIscreen * sPriv,
                     const struct gl_config * visual, boolean isPixmap)
 {
    struct dri_drawable *drawable = NULL;
+   struct drisw_drawable_ref *drisw_reference = NULL;
 
    if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
       return FALSE;
@@ -433,7 +439,29 @@ drisw_create_buffer(__DRIscreen * sPriv,
    drawable->flush_frontbuffer = drisw_flush_frontbuffer;
    drawable->update_tex_buffer = drisw_update_tex_buffer;
 
+   drisw_reference = CALLOC_STRUCT(drisw_drawable_ref);
+   if (drisw_reference == NULL)
+      goto fail;
+   drisw_reference->handle = drawable;
+   drisw_reference->current_snapshot_nb = 1;
+
+   drawable->drisw_reference = drisw_reference;
+
    return TRUE;
+
+fail:
+   dri_destroy_buffer(dPriv);
+   return FALSE;
+}
+
+static void
+drisw_destroy_buffer(__DRIdrawable * dPriv)
+{
+   struct dri_drawable *drawable = dri_drawable(dPriv);
+
+   FREE(drawable->drisw_reference);
+
+   dri_destroy_buffer(dPriv);
 }
 
 /**
@@ -447,7 +475,7 @@ const struct __DriverAPIRec galliumsw_driver_api = {
    .CreateContext = dri_create_context,
    .DestroyContext = dri_destroy_context,
    .CreateBuffer = drisw_create_buffer,
-   .DestroyBuffer = dri_destroy_buffer,
+   .DestroyBuffer = drisw_destroy_buffer,
    .SwapBuffers = drisw_swap_buffers,
    .MakeCurrent = dri_make_current,
    .UnbindContext = dri_unbind_context,
diff --git a/src/gallium/winsys/sw/dri/dri_sw_winsys.c b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
index 94d5092..f3756f4 100644
--- a/src/gallium/winsys/sw/dri/dri_sw_winsys.c
+++ b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
@@ -36,18 +36,21 @@
 #include "state_tracker/sw_winsys.h"
 #include "dri_sw_winsys.h"
 
-
 struct dri_sw_displaytarget
 {
    enum pipe_format format;
    unsigned width;
    unsigned height;
    unsigned stride;
+   unsigned usage;
 
    unsigned map_flags;
    void *data;
    void *mapped;
-   const void *front_private;
+
+   struct drisw_drawable_ref *drawable;
+
+   uint32_t snapshot_nb;
 };
 
 struct dri_sw_winsys
@@ -85,7 +88,7 @@ dri_sw_displaytarget_create(struct sw_winsys *winsys,
                             enum pipe_format format,
                             unsigned width, unsigned height,
                             unsigned alignment,
-                            const void *front_private,
+                            const void *winsys_private,
                             unsigned *stride)
 {
    struct dri_sw_displaytarget *dri_sw_dt;
@@ -98,7 +101,14 @@ 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;
+   dri_sw_dt->usage = tex_usage;
+
+   if (winsys_private) {
+      dri_sw_dt->drawable = (struct drisw_drawable_ref *)winsys_private;
+      dri_sw_dt->snapshot_nb = dri_sw_dt->drawable->current_snapshot_nb - 1; // Out-of-sync at start
+   } else {
+      dri_sw_dt->snapshot_nb = -1;
+   }
 
    format_stride = util_format_get_stride(format, width);
    dri_sw_dt->stride = align(format_stride, alignment);
@@ -138,9 +148,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)) {
+   if ((dri_sw_dt->usage & PIPE_BIND_DISPLAY_SYNC) && dri_sw_dt->drawable
+         && (dri_sw_dt->snapshot_nb != dri_sw_dt->drawable->current_snapshot_nb)) {
       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_ws->lf->get_image((void *)dri_sw_dt->drawable->handle, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride, dri_sw_dt->data);
+
+      dri_sw_dt->snapshot_nb = dri_sw_dt->drawable->current_snapshot_nb;
    }
    dri_sw_dt->map_flags = flags;
    return dri_sw_dt->mapped;
@@ -151,9 +164,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)) {
+   
+   if ((dri_sw_dt->usage & PIPE_BIND_DISPLAY_SYNC) && dri_sw_dt->drawable 
+   		&& (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_ws->lf->put_image2((void *)dri_sw_dt->drawable->handle, 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;
@@ -206,6 +221,13 @@ dri_sw_displaytarget_display(struct sw_winsys *ws,
    } else {
        dri_sw_ws->lf->put_image(dri_drawable, dri_sw_dt->data, width, height);
    }
+
+   /* Increase the snapshot number so any other resource with the
+    * PIPE_BIND_DISPLAY_SYNC flag will detect that changes were made to the display.
+    */
+   if (dri_sw_dt->drawable && (dri_sw_dt->drawable->handle == dri_drawable)) {
+       dri_sw_dt->snapshot_nb = ++dri_sw_dt->drawable->current_snapshot_nb;
+   }
 }
 
 static void
-- 
2.7.4



More information about the mesa-dev mailing list