xlib: Add support for MIT-SHM in xlib winsys driver
Gives about a 3% performance increase in gears on x86-64 (non-tiled) and about 10% performance increase in gears on Cell (tiled). I actually expected more of a boost. :(
This commit is contained in:
parent
84d8030735
commit
b09de96a17
|
@ -104,12 +104,16 @@ static int host_byte_order( void )
|
|||
* 1 = shared XImage support available
|
||||
* 2 = shared Pixmap support available also
|
||||
*/
|
||||
static int check_for_xshm( XMesaDisplay *display )
|
||||
int xmesa_check_for_xshm( XMesaDisplay *display )
|
||||
{
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
int major, minor, ignore;
|
||||
Bool pixmaps;
|
||||
|
||||
if (getenv("MESA_NOSHM")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) {
|
||||
if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) {
|
||||
return (pixmaps==True) ? 2 : 1;
|
||||
|
@ -528,7 +532,7 @@ initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
|
|||
/* Setup for single/double buffering */
|
||||
if (v->mesa_visual.doubleBufferMode) {
|
||||
/* Double buffered */
|
||||
b->shm = check_for_xshm( v->display );
|
||||
b->shm = xmesa_check_for_xshm( v->display );
|
||||
}
|
||||
|
||||
/* X11 graphics context */
|
||||
|
@ -770,13 +774,16 @@ XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
|
|||
pf = choose_pixel_format(v);
|
||||
assert(pf);
|
||||
|
||||
c->xm_visual = v;
|
||||
c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */
|
||||
|
||||
if (!getenv("XM_AUB")) {
|
||||
xmesa_mode = XMESA_SOFTPIPE;
|
||||
pipe = xmesa_create_pipe_context( c, pf );
|
||||
}
|
||||
else {
|
||||
xmesa_mode = XMESA_AUB;
|
||||
pipe = xmesa_create_i965simple( xmesa_get_pipe_winsys_aub() );
|
||||
pipe = xmesa_create_i965simple(xmesa_get_pipe_winsys_aub(v));
|
||||
}
|
||||
|
||||
c->st = st_create_context(pipe, &v->mesa_visual,
|
||||
|
@ -800,9 +807,6 @@ XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
|
|||
#endif
|
||||
|
||||
/* finish up xmesa context initializations */
|
||||
c->xm_visual = v;
|
||||
c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */
|
||||
|
||||
c->st->haveFramebufferSurfaces = GL_TRUE;
|
||||
|
||||
return c;
|
||||
|
|
|
@ -65,8 +65,19 @@ struct xm_buffer
|
|||
boolean userBuffer; /** Is this a user-space buffer? */
|
||||
void *data;
|
||||
void *mapped;
|
||||
|
||||
XImage *tempImage;
|
||||
int shm;
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
XShmSegmentInfo shminfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
# define XSHM_ENABLED(b) ((b)->shm)
|
||||
#else
|
||||
# define XSHM_ENABLED(b) 0
|
||||
#endif
|
||||
|
||||
struct xmesa_surface
|
||||
{
|
||||
|
@ -88,6 +99,16 @@ struct xmesa_softpipe_winsys
|
|||
};
|
||||
|
||||
|
||||
struct xmesa_pipe_winsys
|
||||
{
|
||||
struct pipe_winsys base;
|
||||
struct xmesa_visual *xm_visual;
|
||||
int shm;
|
||||
};
|
||||
|
||||
|
||||
static void alloc_shm_ximage(struct xm_buffer *b, struct xmesa_buffer *xmb,
|
||||
unsigned width, unsigned height);
|
||||
|
||||
/** Cast wrapper */
|
||||
static INLINE struct xmesa_surface *
|
||||
|
@ -136,13 +157,27 @@ xm_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf)
|
|||
|
||||
static void
|
||||
xm_buffer_destroy(struct pipe_winsys *pws,
|
||||
struct pipe_buffer *buf)
|
||||
struct pipe_buffer *buf)
|
||||
{
|
||||
struct xm_buffer *oldBuf = xm_buffer(buf);
|
||||
|
||||
if (oldBuf->data) {
|
||||
if (!oldBuf->userBuffer)
|
||||
align_free(oldBuf->data);
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
if (oldBuf->shminfo.shmid >= 0) {
|
||||
shmdt(oldBuf->shminfo.shmaddr);
|
||||
shmctl(oldBuf->shminfo.shmid, IPC_RMID, 0);
|
||||
|
||||
oldBuf->shminfo.shmid = -1;
|
||||
oldBuf->shminfo.shmaddr = (char *) -1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!oldBuf->userBuffer) {
|
||||
align_free(oldBuf->data);
|
||||
}
|
||||
}
|
||||
|
||||
oldBuf->data = NULL;
|
||||
}
|
||||
|
||||
|
@ -157,7 +192,7 @@ xm_buffer_destroy(struct pipe_winsys *pws,
|
|||
static void
|
||||
xmesa_display_surface_tiled(XMesaBuffer b, const struct pipe_surface *surf)
|
||||
{
|
||||
XImage *ximage = b->tempImage;
|
||||
XImage *ximage;
|
||||
struct xm_buffer *xm_buf = xm_buffer(surf->buffer);
|
||||
const uint tilesPerRow = (surf->width + TILE_SIZE - 1) / TILE_SIZE;
|
||||
uint x, y;
|
||||
|
@ -166,10 +201,18 @@ xmesa_display_surface_tiled(XMesaBuffer b, const struct pipe_surface *surf)
|
|||
assert(ximage->format);
|
||||
assert(ximage->bitmap_unit);
|
||||
|
||||
/* update XImage's fields */
|
||||
ximage->width = TILE_SIZE;
|
||||
ximage->height = TILE_SIZE;
|
||||
ximage->bytes_per_line = TILE_SIZE * 4;
|
||||
if (XSHM_ENABLED(xm_buf) && (xm_buf->tempImage == NULL)) {
|
||||
alloc_shm_ximage(xm_buf, b, TILE_SIZE, TILE_SIZE);
|
||||
}
|
||||
|
||||
ximage = (XSHM_ENABLED(xm_buf)) ? xm_buf->tempImage : b->tempImage;
|
||||
|
||||
if (!XSHM_ENABLED(xm_buf)) {
|
||||
/* update XImage's fields */
|
||||
ximage->width = TILE_SIZE;
|
||||
ximage->height = TILE_SIZE;
|
||||
ximage->bytes_per_line = TILE_SIZE * 4;
|
||||
}
|
||||
|
||||
for (y = 0; y < surf->height; y += TILE_SIZE) {
|
||||
for (x = 0; x < surf->width; x += TILE_SIZE) {
|
||||
|
@ -183,8 +226,15 @@ xmesa_display_surface_tiled(XMesaBuffer b, const struct pipe_surface *surf)
|
|||
|
||||
ximage->data = (char *) xm_buf->data + offset;
|
||||
|
||||
XPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, dx, dy, TILE_SIZE, TILE_SIZE);
|
||||
if (XSHM_ENABLED(xm_buf)) {
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
XShmPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, x, y, TILE_SIZE, TILE_SIZE, False);
|
||||
#endif
|
||||
} else {
|
||||
XPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, dx, dy, TILE_SIZE, TILE_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +247,7 @@ xmesa_display_surface_tiled(XMesaBuffer b, const struct pipe_surface *surf)
|
|||
void
|
||||
xmesa_display_surface(XMesaBuffer b, const struct pipe_surface *surf)
|
||||
{
|
||||
XImage *ximage = b->tempImage;
|
||||
XImage *ximage;
|
||||
struct xm_buffer *xm_buf = xm_buffer(surf->buffer);
|
||||
const struct xmesa_surface *xm_surf
|
||||
= xmesa_surface((struct pipe_surface *) surf);
|
||||
|
@ -207,19 +257,33 @@ xmesa_display_surface(XMesaBuffer b, const struct pipe_surface *surf)
|
|||
return;
|
||||
}
|
||||
|
||||
/* check that the XImage has been previously initialized */
|
||||
assert(ximage->format);
|
||||
assert(ximage->bitmap_unit);
|
||||
|
||||
/* update XImage's fields */
|
||||
ximage->width = surf->width;
|
||||
ximage->height = surf->height;
|
||||
ximage->bytes_per_line = surf->pitch * (ximage->bits_per_pixel / 8);
|
||||
if (XSHM_ENABLED(xm_buf) && (xm_buf->tempImage == NULL)) {
|
||||
alloc_shm_ximage(xm_buf, b, surf->pitch, surf->height);
|
||||
}
|
||||
|
||||
ximage = (XSHM_ENABLED(xm_buf)) ? xm_buf->tempImage : b->tempImage;
|
||||
ximage->data = xm_buf->data;
|
||||
|
||||
/* display image in Window */
|
||||
XPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, 0, 0, surf->width, surf->height);
|
||||
if (XSHM_ENABLED(xm_buf)) {
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
XShmPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, 0, 0, surf->width, surf->height, False);
|
||||
#endif
|
||||
} else {
|
||||
/* check that the XImage has been previously initialized */
|
||||
assert(ximage->format);
|
||||
assert(ximage->bitmap_unit);
|
||||
|
||||
/* update XImage's fields */
|
||||
ximage->width = surf->width;
|
||||
ximage->height = surf->height;
|
||||
ximage->bytes_per_line = surf->pitch * surf->cpp;
|
||||
|
||||
XPutImage(b->xm_visual->display, b->drawable, b->gc,
|
||||
ximage, 0, 0, 0, 0, surf->width, surf->height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -256,6 +320,119 @@ xm_get_name(struct pipe_winsys *pws)
|
|||
}
|
||||
|
||||
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
static volatile int mesaXErrorFlag = 0;
|
||||
|
||||
/**
|
||||
* Catches potential Xlib errors.
|
||||
*/
|
||||
static int
|
||||
mesaHandleXError(XMesaDisplay *dpy, XErrorEvent *event)
|
||||
{
|
||||
(void) dpy;
|
||||
(void) event;
|
||||
mesaXErrorFlag = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static GLboolean alloc_shm(struct xm_buffer *buf, unsigned size)
|
||||
{
|
||||
XShmSegmentInfo *const shminfo = & buf->shminfo;
|
||||
|
||||
shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
|
||||
if (shminfo->shmid < 0) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
|
||||
if (shminfo->shmaddr == (char *) -1) {
|
||||
shmctl(shminfo->shmid, IPC_RMID, 0);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
shminfo->readOnly = False;
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a shared memory XImage back buffer for the given XMesaBuffer.
|
||||
*/
|
||||
static void
|
||||
alloc_shm_ximage(struct xm_buffer *b, struct xmesa_buffer *xmb,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
/*
|
||||
* We have to do a _lot_ of error checking here to be sure we can
|
||||
* really use the XSHM extension. It seems different servers trigger
|
||||
* errors at different points if the extension won't work. Therefore
|
||||
* we have to be very careful...
|
||||
*/
|
||||
#if 0
|
||||
GC gc;
|
||||
#endif
|
||||
int (*old_handler)(XMesaDisplay *, XErrorEvent *);
|
||||
|
||||
b->tempImage = XShmCreateImage(xmb->xm_visual->display,
|
||||
xmb->xm_visual->visinfo->visual,
|
||||
xmb->xm_visual->visinfo->depth,
|
||||
ZPixmap,
|
||||
NULL,
|
||||
&b->shminfo,
|
||||
width, height);
|
||||
if (b->tempImage == NULL) {
|
||||
b->shm = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mesaXErrorFlag = 0;
|
||||
old_handler = XSetErrorHandler(mesaHandleXError);
|
||||
/* This may trigger the X protocol error we're ready to catch: */
|
||||
XShmAttach(xmb->xm_visual->display, &b->shminfo);
|
||||
XSync(xmb->xm_visual->display, False);
|
||||
|
||||
if (mesaXErrorFlag) {
|
||||
/* we are on a remote display, this error is normal, don't print it */
|
||||
XFlush(xmb->xm_visual->display);
|
||||
mesaXErrorFlag = 0;
|
||||
XDestroyImage(b->tempImage);
|
||||
b->tempImage = NULL;
|
||||
b->shm = 0;
|
||||
(void) XSetErrorHandler(old_handler);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Finally, try an XShmPutImage to be really sure the extension works */
|
||||
#if 0
|
||||
gc = XCreateGC(xmb->xm_visual->display, xmb->drawable, 0, NULL);
|
||||
XShmPutImage(xmb->xm_visual->display, xmb->drawable, gc,
|
||||
b->tempImage, 0, 0, 0, 0, 1, 1 /*one pixel*/, False);
|
||||
XSync(xmb->xm_visual->display, False);
|
||||
XFreeGC(xmb->xm_visual->display, gc);
|
||||
(void) XSetErrorHandler(old_handler);
|
||||
if (mesaXErrorFlag) {
|
||||
XFlush(xmb->xm_visual->display);
|
||||
mesaXErrorFlag = 0;
|
||||
XDestroyImage(b->tempImage);
|
||||
b->tempImage = NULL;
|
||||
b->shm = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void
|
||||
alloc_shm_ximage(struct xm_buffer *b, struct xmesa_buffer *xmb,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
b->shm = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static struct pipe_buffer *
|
||||
xm_buffer_create(struct pipe_winsys *pws,
|
||||
unsigned alignment,
|
||||
|
@ -263,13 +440,35 @@ xm_buffer_create(struct pipe_winsys *pws,
|
|||
unsigned size)
|
||||
{
|
||||
struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
struct xmesa_pipe_winsys *xpws = (struct xmesa_pipe_winsys *) pws;
|
||||
#endif
|
||||
|
||||
buffer->base.refcount = 1;
|
||||
buffer->base.alignment = alignment;
|
||||
buffer->base.usage = usage;
|
||||
buffer->base.size = size;
|
||||
|
||||
/* align to 16-byte multiple for Cell */
|
||||
buffer->data = align_malloc(size, max(alignment, 16));
|
||||
|
||||
#if defined(USE_XSHM) && !defined(XFree86Server)
|
||||
buffer->shminfo.shmid = -1;
|
||||
buffer->shminfo.shmaddr = (char *) -1;
|
||||
|
||||
if (xpws->shm && (usage & PIPE_BUFFER_USAGE_PIXEL) != 0) {
|
||||
buffer->shm = xpws->shm;
|
||||
|
||||
if (alloc_shm(buffer, size)) {
|
||||
buffer->data = buffer->shminfo.shmaddr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (buffer->data == NULL) {
|
||||
buffer->shm = 0;
|
||||
|
||||
/* align to 16-byte multiple for Cell */
|
||||
buffer->data = align_malloc(size, max(alignment, 16));
|
||||
}
|
||||
|
||||
return &buffer->base;
|
||||
}
|
||||
|
@ -286,6 +485,7 @@ xm_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
|
|||
buffer->base.size = bytes;
|
||||
buffer->userBuffer = TRUE;
|
||||
buffer->data = ptr;
|
||||
buffer->shm = 0;
|
||||
|
||||
return &buffer->base;
|
||||
}
|
||||
|
@ -377,35 +577,38 @@ xm_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
|
|||
* Nothing special for the Xlib driver so no subclassing or anything.
|
||||
*/
|
||||
struct pipe_winsys *
|
||||
xmesa_get_pipe_winsys_aub(void)
|
||||
xmesa_get_pipe_winsys_aub(struct xmesa_visual *xm_vis)
|
||||
{
|
||||
static struct pipe_winsys *ws = NULL;
|
||||
static struct xmesa_pipe_winsys *ws = NULL;
|
||||
|
||||
if (!ws && getenv("XM_AUB")) {
|
||||
ws = xmesa_create_pipe_winsys_aub();
|
||||
ws = (struct xmesa_pipe_winsys *) xmesa_create_pipe_winsys_aub();
|
||||
}
|
||||
else if (!ws) {
|
||||
ws = CALLOC_STRUCT(pipe_winsys);
|
||||
|
||||
ws = CALLOC_STRUCT(xmesa_pipe_winsys);
|
||||
|
||||
ws->xm_visual = xm_vis;
|
||||
ws->shm = xmesa_check_for_xshm(xm_vis->display);
|
||||
|
||||
/* Fill in this struct with callbacks that pipe will need to
|
||||
* communicate with the window system, buffer manager, etc.
|
||||
*/
|
||||
ws->buffer_create = xm_buffer_create;
|
||||
ws->user_buffer_create = xm_user_buffer_create;
|
||||
ws->buffer_map = xm_buffer_map;
|
||||
ws->buffer_unmap = xm_buffer_unmap;
|
||||
ws->buffer_destroy = xm_buffer_destroy;
|
||||
ws->base.buffer_create = xm_buffer_create;
|
||||
ws->base.user_buffer_create = xm_user_buffer_create;
|
||||
ws->base.buffer_map = xm_buffer_map;
|
||||
ws->base.buffer_unmap = xm_buffer_unmap;
|
||||
ws->base.buffer_destroy = xm_buffer_destroy;
|
||||
|
||||
ws->surface_alloc = xm_surface_alloc;
|
||||
ws->surface_alloc_storage = xm_surface_alloc_storage;
|
||||
ws->surface_release = xm_surface_release;
|
||||
ws->base.surface_alloc = xm_surface_alloc;
|
||||
ws->base.surface_alloc_storage = xm_surface_alloc_storage;
|
||||
ws->base.surface_release = xm_surface_release;
|
||||
|
||||
ws->flush_frontbuffer = xm_flush_frontbuffer;
|
||||
ws->printf = xm_printf;
|
||||
ws->get_name = xm_get_name;
|
||||
ws->base.flush_frontbuffer = xm_flush_frontbuffer;
|
||||
ws->base.printf = xm_printf;
|
||||
ws->base.get_name = xm_get_name;
|
||||
}
|
||||
|
||||
return ws;
|
||||
return &ws->base;
|
||||
}
|
||||
|
||||
|
||||
|
@ -445,27 +648,27 @@ xmesa_get_softpipe_winsys(uint pixelformat)
|
|||
struct pipe_context *
|
||||
xmesa_create_pipe_context(XMesaContext xmesa, uint pixelformat)
|
||||
{
|
||||
struct pipe_winsys *pws = xmesa_get_pipe_winsys_aub();
|
||||
struct pipe_winsys *pws = xmesa_get_pipe_winsys_aub(xmesa->xm_visual);
|
||||
struct pipe_context *pipe;
|
||||
|
||||
#ifdef GALLIUM_CELL
|
||||
if (!getenv("GALLIUM_NOCELL")) {
|
||||
struct cell_winsys *cws = cell_get_winsys(pixelformat);
|
||||
struct pipe_screen *screen = cell_create_screen(pws);
|
||||
|
||||
pipe = cell_create_context(screen, cws);
|
||||
if (pipe)
|
||||
pipe->priv = xmesa;
|
||||
return pipe;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct softpipe_winsys *spws = xmesa_get_softpipe_winsys(pixelformat);
|
||||
struct pipe_screen *screen = softpipe_create_screen(pws);
|
||||
pipe = softpipe_create( screen, pws, spws );
|
||||
if (pipe)
|
||||
pipe->priv = xmesa;
|
||||
|
||||
return pipe;
|
||||
pipe = softpipe_create(screen, pws, spws);
|
||||
}
|
||||
|
||||
if (pipe)
|
||||
pipe->priv = xmesa;
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ void xmesa_commands_aub(struct pipe_winsys *winsys,
|
|||
void xmesa_display_aub( /* struct pipe_winsys *winsys, */
|
||||
struct pipe_surface *surface );
|
||||
|
||||
struct pipe_winsys *xmesa_get_pipe_winsys_aub(void);
|
||||
extern struct pipe_winsys *
|
||||
xmesa_get_pipe_winsys_aub(struct xmesa_visual *xm_vis);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -173,4 +173,7 @@ xmesa_buffer_height(XMesaBuffer b)
|
|||
extern void
|
||||
xmesa_display_surface(XMesaBuffer b, const struct pipe_surface *surf);
|
||||
|
||||
extern int
|
||||
xmesa_check_for_xshm(XMesaDisplay *display);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue