[Mesa-dev] [PATCH] drisw/gallium/llvmpipe: add MESA_copy_sub_buffer support

Dave Airlie airlied at gmail.com
Wed Nov 27 20:08:54 PST 2013


This patches add MESA_copy_sub_buffer support to the dri sw loader and
then to gallium state tracker, llvmpipe, softpipe and other bits.

It reuses the dri1 driver extension interface, and it updates the swrast
loader interface for a new putimage which can take a stride.

I've tested this with gnome-shell with a cogl hacked to reenable sub copies
for llvmpipe and the one piglit test.

I could probably split this patch up as well.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 include/GL/internal/dri_interface.h           |  9 +++-
 src/gallium/drivers/llvmpipe/lp_screen.c      | 17 +++++++
 src/gallium/drivers/softpipe/sp_screen.c      | 19 ++++++++
 src/gallium/include/pipe/p_screen.h           |  6 ++-
 src/gallium/include/state_tracker/drisw_api.h |  2 +
 src/gallium/include/state_tracker/sw_winsys.h |  6 +++
 src/gallium/state_trackers/dri/sw/drisw.c     | 64 ++++++++++++++++++++++++++-
 src/gallium/winsys/sw/dri/dri_sw_winsys.c     | 22 ++++++++-
 src/glx/drisw_glx.c                           | 43 +++++++++++++++---
 src/mesa/drivers/dri/common/dri_util.c        | 15 +++++++
 src/mesa/drivers/dri/common/dri_util.h        |  5 ++-
 11 files changed, 198 insertions(+), 10 deletions(-)

diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
index b012570..81f7e60 100644
--- a/include/GL/internal/dri_interface.h
+++ b/include/GL/internal/dri_interface.h
@@ -437,7 +437,7 @@ struct __DRIdamageExtensionRec {
  * SWRast Loader extension.
  */
 #define __DRI_SWRAST_LOADER "DRI_SWRastLoader"
-#define __DRI_SWRAST_LOADER_VERSION 1
+#define __DRI_SWRAST_LOADER_VERSION 2
 struct __DRIswrastLoaderExtensionRec {
     __DRIextension base;
 
@@ -461,6 +461,13 @@ struct __DRIswrastLoaderExtensionRec {
     void (*getImage)(__DRIdrawable *readable,
 		     int x, int y, int width, int height,
 		     char *data, void *loaderPrivate);
+
+    /**
+     * Put image to drawable
+     */
+    void (*putImage2)(__DRIdrawable *drawable, int op,
+                      int x, int y, int width, int height, int stride,
+                      char *data, void *loaderPrivate);
 };
 
 /**
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index f61df98..a4bf27a 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -415,6 +415,22 @@ llvmpipe_flush_frontbuffer(struct pipe_screen *_screen,
       winsys->displaytarget_display(winsys, texture->dt, context_private);
 }
 
+static void
+llvmpipe_flush_sub_frontbuffer(struct pipe_screen *_screen,
+                               struct pipe_resource *resource,
+                               unsigned level, unsigned layer,
+                               void *context_private,
+                               int x, int y, int w, int h)
+{
+   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
+   struct sw_winsys *winsys = screen->winsys;
+   struct llvmpipe_resource *texture = llvmpipe_resource(resource);
+
+   assert(texture->dt);
+   if (texture->dt)
+      winsys->displaytarget_sub_display(winsys, texture->dt, context_private,
+                                        x, y, w, h);
+}
 
 static void
 llvmpipe_destroy_screen( struct pipe_screen *_screen )
@@ -525,6 +541,7 @@ llvmpipe_create_screen(struct sw_winsys *winsys)
 
    screen->base.context_create = llvmpipe_create_context;
    screen->base.flush_frontbuffer = llvmpipe_flush_frontbuffer;
+   screen->base.flush_sub_frontbuffer = llvmpipe_flush_sub_frontbuffer;
    screen->base.fence_reference = llvmpipe_fence_reference;
    screen->base.fence_signalled = llvmpipe_fence_signalled;
    screen->base.fence_finish = llvmpipe_fence_finish;
diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index 47ef20e..093357b 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -377,6 +377,23 @@ softpipe_flush_frontbuffer(struct pipe_screen *_screen,
       winsys->displaytarget_display(winsys, texture->dt, context_private);
 }
 
+static void
+softpipe_flush_sub_frontbuffer(struct pipe_screen *_screen,
+                               struct pipe_resource *resource,
+                               unsigned level, unsigned layer,
+                               void *context_private,
+                               int x, int y, int w, int h)
+{
+   struct softpipe_screen *screen = softpipe_screen(_screen);
+   struct sw_winsys *winsys = screen->winsys;
+   struct softpipe_resource *texture = softpipe_resource(resource);
+
+   assert(texture->dt);
+   if (texture->dt)
+      winsys->displaytarget_sub_display(winsys, texture->dt, context_private,
+                                        x, y, w, h);
+}
+
 static uint64_t
 softpipe_get_timestamp(struct pipe_screen *_screen)
 {
@@ -411,6 +428,8 @@ softpipe_create_screen(struct sw_winsys *winsys)
    screen->base.context_create = softpipe_create_context;
    screen->base.flush_frontbuffer = softpipe_flush_frontbuffer;
 
+   screen->base.flush_sub_frontbuffer = softpipe_flush_sub_frontbuffer;
+
    screen->use_llvm = debug_get_option_use_llvm();
 
    util_format_s3tc_init();
diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
index 3ed7f26..8fd4f72 100644
--- a/src/gallium/include/pipe/p_screen.h
+++ b/src/gallium/include/pipe/p_screen.h
@@ -187,7 +187,11 @@ struct pipe_screen {
                               unsigned level, unsigned layer,
                               void *winsys_drawable_handle );
 
-
+   void (*flush_sub_frontbuffer)( struct pipe_screen *screen,
+                                  struct pipe_resource *resource,
+                                  unsigned level, unsigned layer,
+                                  void *winsys_drawable_handle,
+                                  int x, int y, int w, int h);
 
    /** Set ptr = fence, with reference counting */
    void (*fence_reference)( struct pipe_screen *screen,
diff --git a/src/gallium/include/state_tracker/drisw_api.h b/src/gallium/include/state_tracker/drisw_api.h
index 944a649..328440c 100644
--- a/src/gallium/include/state_tracker/drisw_api.h
+++ b/src/gallium/include/state_tracker/drisw_api.h
@@ -13,6 +13,8 @@ struct drisw_loader_funcs
 {
    void (*put_image) (struct dri_drawable *dri_drawable,
                       void *data, unsigned width, unsigned height);
+   void (*put_image2) (struct dri_drawable *dri_drawable,
+                       void *data, int x, int y, unsigned width, unsigned height, unsigned stride);
 };
 
 /**
diff --git a/src/gallium/include/state_tracker/sw_winsys.h b/src/gallium/include/state_tracker/sw_winsys.h
index 0b11fe3..6422f98 100644
--- a/src/gallium/include/state_tracker/sw_winsys.h
+++ b/src/gallium/include/state_tracker/sw_winsys.h
@@ -131,6 +131,12 @@ struct sw_winsys
                              struct sw_displaytarget *dt,
                              void *context_private );
 
+   void
+   (*displaytarget_sub_display)( struct sw_winsys *ws, 
+                                 struct sw_displaytarget *dt,
+                                 void *context_private,
+                                 int x, int y, int w, int h);
+
    void 
    (*displaytarget_destroy)( struct sw_winsys *ws, 
                              struct sw_displaytarget *dt );
diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c
index 9f00a53..6268906 100644
--- a/src/gallium/state_trackers/dri/sw/drisw.c
+++ b/src/gallium/state_trackers/dri/sw/drisw.c
@@ -71,6 +71,18 @@ put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)
 }
 
 static INLINE void
+put_image2(__DRIdrawable *dPriv, void *data, int x, int y,
+           unsigned width, unsigned height, unsigned stride)
+{
+   __DRIscreen *sPriv = dPriv->driScreenPriv;
+   const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
+
+   loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
+                     x, y, width, height, stride,
+                     data, dPriv->loaderPrivate);
+}
+
+static INLINE void
 get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)
 {
    __DRIscreen *sPriv = dPriv->driScreenPriv;
@@ -99,6 +111,16 @@ drisw_put_image(struct dri_drawable *drawable,
    put_image(dPriv, data, width, height);
 }
 
+static void
+drisw_put_image2(struct dri_drawable *drawable,
+                 void *data, int x, int y, unsigned width, unsigned height,
+                 unsigned stride)
+{
+   __DRIdrawable *dPriv = drawable->dPriv;
+
+   put_image2(dPriv, data, x, y, width, height, stride);
+}
+
 static INLINE void
 drisw_present_texture(__DRIdrawable *dPriv,
                       struct pipe_resource *ptex)
@@ -113,6 +135,20 @@ drisw_present_texture(__DRIdrawable *dPriv,
 }
 
 static INLINE void
+drisw_present_sub_texture(__DRIdrawable *dPriv,
+                          struct pipe_resource *ptex, int x, int y,
+                          int w, int h)
+{
+   struct dri_drawable *drawable = dri_drawable(dPriv);
+   struct dri_screen *screen = dri_screen(drawable->sPriv);
+
+   if (swrast_no_present)
+      return;
+
+   screen->base.screen->flush_sub_frontbuffer(screen->base.screen, ptex, 0, 0, drawable, x, y, w, h);
+}
+
+static INLINE void
 drisw_invalidate_drawable(__DRIdrawable *dPriv)
 {
    struct dri_drawable *drawable = dri_drawable(dPriv);
@@ -158,6 +194,29 @@ drisw_swap_buffers(__DRIdrawable *dPriv)
 }
 
 static void
+drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y,
+                      int w, int h)
+{
+   struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
+   struct dri_drawable *drawable = dri_drawable(dPriv);
+   struct pipe_resource *ptex;
+
+   if (!ctx)
+      return;
+
+   ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
+
+   if (ptex) {
+      if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
+         pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
+
+      ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
+
+      drisw_present_sub_texture(dPriv, ptex, x, dPriv->h - y - h, w, h);
+   }
+}
+
+static void
 drisw_flush_frontbuffer(struct dri_context *ctx,
                         struct dri_drawable *drawable,
                         enum st_attachment_type statt)
@@ -288,7 +347,8 @@ static const __DRIextension *drisw_screen_extensions[] = {
 };
 
 static struct drisw_loader_funcs drisw_lf = {
-   .put_image = drisw_put_image
+   .put_image = drisw_put_image,
+   .put_image2 = drisw_put_image2
 };
 
 static const __DRIconfig **
@@ -359,12 +419,14 @@ const struct __DriverAPIRec driDriverAPI = {
    .SwapBuffers = drisw_swap_buffers,
    .MakeCurrent = dri_make_current,
    .UnbindContext = dri_unbind_context,
+   .CopySubBuffer = drisw_copy_sub_buffer,
 };
 
 /* This is the table of extensions that the loader will dlsym() for. */
 PUBLIC const __DRIextension *__driDriverExtensions[] = {
     &driCoreExtension.base,
     &driSWRastExtension.base,
+    &driCopySubBufferExtension,
     &gallium_config_options.base,
     NULL
 };
diff --git a/src/gallium/winsys/sw/dri/dri_sw_winsys.c b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
index edb3a38..3854228 100644
--- a/src/gallium/winsys/sw/dri/dri_sw_winsys.c
+++ b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
@@ -184,6 +184,26 @@ dri_sw_displaytarget_display(struct sw_winsys *ws,
    dri_sw_ws->lf->put_image(dri_drawable, dri_sw_dt->data, width, height);
 }
 
+static void
+dri_sw_displaytarget_sub_display(struct sw_winsys *ws,
+                                 struct sw_displaytarget *dt,
+                                 void *context_private,
+                                 int x, int y, int w, int h)
+{
+   struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
+   struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
+   struct dri_drawable *dri_drawable = (struct dri_drawable *)context_private;
+   unsigned width, height;
+   int blsize = util_format_get_blocksize(dri_sw_dt->format);
+   int line;
+   void *data;
+
+   width = dri_sw_dt->stride / blsize;
+
+   data = dri_sw_dt->data + (dri_sw_dt->stride * y) + x * blsize;
+   dri_sw_ws->lf->put_image2(dri_drawable, data,
+                             x, y, w, h, dri_sw_dt->stride);
+}
 
 static void
 dri_destroy_sw_winsys(struct sw_winsys *winsys)
@@ -216,7 +236,7 @@ dri_create_sw_winsys(struct drisw_loader_funcs *lf)
    ws->base.displaytarget_unmap = dri_sw_displaytarget_unmap;
 
    ws->base.displaytarget_display = dri_sw_displaytarget_display;
-
+   ws->base.displaytarget_sub_display = dri_sw_displaytarget_sub_display;
    return &ws->base;
 }
 
diff --git a/src/glx/drisw_glx.c b/src/glx/drisw_glx.c
index cb1d650..13a4b96 100644
--- a/src/glx/drisw_glx.c
+++ b/src/glx/drisw_glx.c
@@ -49,6 +49,7 @@ struct drisw_screen
    const __DRIcoreExtension *core;
    const __DRIswrastExtension *swrast;
    const __DRItexBufferExtension *texBuffer;
+   const __DRIcopySubBufferExtension *copySubBuffer;
 
    const __DRIconfig **driver_configs;
 
@@ -171,9 +172,9 @@ bytes_per_line(unsigned pitch_bits, unsigned mul)
 }
 
 static void
-swrastPutImage(__DRIdrawable * draw, int op,
-               int x, int y, int w, int h,
-               char *data, void *loaderPrivate)
+swrastPutImage2(__DRIdrawable * draw, int op,
+                int x, int y, int w, int h, int stride,
+                char *data, void *loaderPrivate)
 {
    struct drisw_drawable *pdp = loaderPrivate;
    __GLXDRIdrawable *pdraw = &(pdp->base);
@@ -199,7 +200,7 @@ swrastPutImage(__DRIdrawable * draw, int op,
    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);
 
    XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
 
@@ -207,6 +208,14 @@ swrastPutImage(__DRIdrawable * draw, int op,
 }
 
 static void
+swrastPutImage(__DRIdrawable * draw, int op,
+               int x, int y, int w, int h,
+               char *data, void *loaderPrivate)
+{
+   swrastPutImage2(draw, op, x, y, w, h, 0, data, loaderPrivate);
+}
+
+static void
 swrastGetImage(__DRIdrawable * read,
                int x, int y, int w, int h,
                char *data, void *loaderPrivate)
@@ -234,7 +243,8 @@ static const __DRIswrastLoaderExtension swrastLoaderExtension = {
    {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
    swrastGetDrawableInfo,
    swrastPutImage,
-   swrastGetImage
+   swrastGetImage,
+   swrastPutImage2,
 };
 
 static const __DRIextension *loader_extensions[] = {
@@ -585,6 +595,21 @@ driswSwapBuffers(__GLXDRIdrawable * pdraw,
 }
 
 static void
+driswCopySubBuffer(__GLXDRIdrawable * pdraw,
+                   int x, int y, int width, int height, Bool flush)
+{
+   struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
+   struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
+
+   if (flush) {
+      glFlush();
+   }
+
+   (*psc->copySubBuffer->copySubBuffer) (pdp->driDrawable,
+					    x, y, width, height);
+}
+
+static void
 driswDestroyScreen(struct glx_screen *base)
 {
    struct drisw_screen *psc = (struct drisw_screen *) base;
@@ -632,6 +657,9 @@ driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
 				 "GLX_EXT_create_context_es2_profile");
    }
 
+   if (psc->copySubBuffer)
+      __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");      
+
    /* FIXME: Figure out what other extensions can be ported here from dri2. */
    for (i = 0; extensions[i]; i++) {
       if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
@@ -673,6 +701,8 @@ driswCreateScreen(int screen, struct glx_display *priv)
 	 psc->core = (__DRIcoreExtension *) extensions[i];
       if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
 	 psc->swrast = (__DRIswrastExtension *) extensions[i];
+      if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0)
+	 psc->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
    }
 
    if (psc->core == NULL || psc->swrast == NULL) {
@@ -718,6 +748,9 @@ driswCreateScreen(int screen, struct glx_display *priv)
    psp->createDrawable = driswCreateDrawable;
    psp->swapBuffers = driswSwapBuffers;
 
+   if (psc->copySubBuffer)
+      psp->copySubBuffer = driswCopySubBuffer;
+
    return &psc->base;
 
  handle_error:
diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c
index 0bce77e..fd2eca7 100644
--- a/src/mesa/drivers/dri/common/dri_util.c
+++ b/src/mesa/drivers/dri/common/dri_util.c
@@ -873,3 +873,18 @@ const __DRIimageDriverExtension driImageDriverExtension = {
     .getAPIMask                 = driGetAPIMask,
     .createContextAttribs       = driCreateContextAttribs,
 };
+
+/* swrast copy sub buffer entrypoint. */
+static void driCopySubBuffer(__DRIdrawable *pdp, int x, int y,
+                             int w, int h)
+{
+    assert(pdp->driScreenPriv->swrast_loader);
+
+    pdp->driScreenPriv->driver->CopySubBuffer(pdp, x, y, w, h);
+}
+
+/* for swrast only */
+const __DRIcopySubBufferExtension driCopySubBufferExtension = {
+   { __DRI_COPY_SUB_BUFFER, 1 },
+   .copySubBuffer = driCopySubBuffer,
+};
diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h
index 79a8564..4cfa75d 100644
--- a/src/mesa/drivers/dri/common/dri_util.h
+++ b/src/mesa/drivers/dri/common/dri_util.h
@@ -66,7 +66,7 @@ extern const __DRIcoreExtension driCoreExtension;
 extern const __DRIswrastExtension driSWRastExtension;
 extern const __DRIdri2Extension driDRI2Extension;
 extern const __DRI2configQueryExtension dri2ConfigQueryExtension;
-
+extern const __DRIcopySubBufferExtension driCopySubBufferExtension;
 /**
  * Driver callback functions.
  *
@@ -115,6 +115,9 @@ struct __DriverAPIRec {
                                     int width, int height);
 
     void (*ReleaseBuffer) (__DRIscreen *screenPrivate, __DRIbuffer *buffer);
+
+    void (*CopySubBuffer)(__DRIdrawable *driDrawPriv, int x, int y,
+                          int w, int h);
 };
 
 extern const struct __DriverAPIRec driDriverAPI;
-- 
1.8.3.1



More information about the mesa-dev mailing list