gallium/swrast: fix front buffer blitting. (v2)

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>
This commit is contained in:
Dave Airlie 2015-10-09 01:38:08 +01:00 committed by Dave Airlie
parent 103de0225b
commit 2b67657096
9 changed files with 113 additions and 18 deletions

View 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);
};
/**

View 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;

View 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;

View 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

View 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,

View File

@ -90,6 +90,7 @@ struct sw_winsys
enum pipe_format format,
unsigned width, unsigned height,
unsigned alignment,
const void *front_private,
unsigned *stride );
/**

View 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
};

View 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;
}

View 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[] = {