[Mesa-dev] [PATCH] gallium/swrast: fix front buffer blitting.
Ian Romanick
idr at freedesktop.org
Wed Oct 7 22:26:12 PDT 2015
On 10/07/2015 08:05 PM, Dave Airlie wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> 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
>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91930
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
> include/GL/internal/dri_interface.h | 11 ++++++++-
> src/gallium/drivers/llvmpipe/lp_texture.c | 21 +++++++++++++-----
> src/gallium/drivers/softpipe/sp_texture.c | 18 +++++++++++----
> src/gallium/include/pipe/p_screen.h | 4 ++++
> src/gallium/include/state_tracker/drisw_api.h | 3 +++
> src/gallium/include/state_tracker/sw_winsys.h | 1 +
> src/gallium/state_trackers/dri/drisw.c | 32 +++++++++++++++++++++++++--
> src/gallium/winsys/sw/dri/dri_sw_winsys.c | 15 +++++++++++++
> src/glx/drisw_glx.c | 17 ++++++++++----
> 9 files changed, 105 insertions(+), 17 deletions(-)
>
> diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
> index a0f155a..6bbd3fa 100644
> --- a/include/GL/internal/dri_interface.h
> +++ b/include/GL/internal/dri_interface.h
> @@ -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);
> };
>
> /**
> diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
> index af46342..7862ac8 100644
> --- a/src/gallium/drivers/llvmpipe/lp_texture.c
> +++ b/src/gallium/drivers/llvmpipe/lp_texture.c
> @@ -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;
> diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c
> index e1ea5df..3347f5f 100644
> --- a/src/gallium/drivers/softpipe/sp_texture.c
> +++ b/src/gallium/drivers/softpipe/sp_texture.c
> @@ -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;
> diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
> index a22fb93..f868d71 100644
> --- a/src/gallium/include/pipe/p_screen.h
> +++ b/src/gallium/include/pipe/p_screen.h
> @@ -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
> diff --git a/src/gallium/include/state_tracker/drisw_api.h b/src/gallium/include/state_tracker/drisw_api.h
> index 328440c..cd5a27e 100644
> --- a/src/gallium/include/state_tracker/drisw_api.h
> +++ b/src/gallium/include/state_tracker/drisw_api.h
> @@ -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,
> diff --git a/src/gallium/include/state_tracker/sw_winsys.h b/src/gallium/include/state_tracker/sw_winsys.h
> index a3479eb..0b792cd 100644
> --- a/src/gallium/include/state_tracker/sw_winsys.h
> +++ b/src/gallium/include/state_tracker/sw_winsys.h
> @@ -90,6 +90,7 @@ struct sw_winsys
> enum pipe_format format,
> unsigned width, unsigned height,
> unsigned alignment,
> + const void *front_private,
> unsigned *stride );
>
> /**
> diff --git a/src/gallium/state_trackers/dri/drisw.c b/src/gallium/state_trackers/dri/drisw.c
> index 4ec6992..7fb1ff3 100644
> --- a/src/gallium/state_trackers/dri/drisw.c
> +++ b/src/gallium/state_trackers/dri/drisw.c
> @@ -95,6 +95,17 @@ 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;
> +
> + loader->getImage2(dPriv,
> + x, y, width, height, stride,
> + data, dPriv->loaderPrivate);
> +}
> +
> static void
> drisw_update_drawable_info(struct dri_drawable *drawable)
> {
> @@ -105,6 +116,18 @@ drisw_update_drawable_info(struct dri_drawable *drawable)
> }
>
> 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)
> {
> @@ -281,8 +304,12 @@ 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) {
> + 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 +365,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
> };
> diff --git a/src/gallium/winsys/sw/dri/dri_sw_winsys.c b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
> index 8451d83..5c98f26 100644
> --- a/src/gallium/winsys/sw/dri/dri_sw_winsys.c
> +++ b/src/gallium/winsys/sw/dri/dri_sw_winsys.c
> @@ -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;
> }
>
> diff --git a/src/glx/drisw_glx.c b/src/glx/drisw_glx.c
> index 749ceb0..ffad35b 100644
> --- a/src/glx/drisw_glx.c
> +++ b/src/glx/drisw_glx.c
> @@ -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,13 +193,21 @@ 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 },
Doesn't this need to get changed to 3? And shouldn't something,
somewhere check that version? What happens if you use a newer
swrast_dri.so with an older libGL.so? And vice versa?
>
> @@ -207,6 +215,7 @@ static const __DRIswrastLoaderExtension swrastLoaderExtension = {
> .putImage = swrastPutImage,
> .getImage = swrastGetImage,
> .putImage2 = swrastPutImage2,
> + .getImage2 = swrastGetImage2,
> };
>
> static const __DRIextension *loader_extensions[] = {
>
More information about the mesa-dev
mailing list