Commit bcd80be4 authored by Marc-André Lureau's avatar Marc-André Lureau 🎺 Committed by Dave Airlie
Browse files

drisw/glx: use XShm if possible



Implements putImageShm from DRIswrastLoaderExtension.

If XShm extension is not available, or fails, it will fallback on
regular XPutImage().

Tested on Linux only with 16bpp and 32bpp visual.

(airlied: tested on 24bpp as well)
Reviewed-by: default avatarDave Airlie <airlied@redhat.com>
Reviewed-by: Adam Jackson's avatarAdam Jackson <ajax@redhat.com>
parent cf54bd5e
......@@ -28,10 +28,12 @@
#include <dlfcn.h>
#include "dri_common.h"
#include "drisw_priv.h"
#include <X11/extensions/shmproto.h>
#include <assert.h>
static Bool
XCreateDrawable(struct drisw_drawable * pdp,
Display * dpy, XID drawable, int visualid)
XCreateGCs(struct drisw_drawable * pdp,
Display * dpy, XID drawable, int visualid)
{
XGCValues gcvalues;
long visMask;
......@@ -56,15 +58,78 @@ XCreateDrawable(struct drisw_drawable * pdp,
if (!pdp->visinfo || num_visuals == 0)
return False;
/* create XImage */
pdp->ximage = XCreateImage(dpy,
pdp->visinfo->visual,
pdp->visinfo->depth,
ZPixmap, 0, /* format, offset */
NULL, /* data */
0, 0, /* width, height */
32, /* bitmap_pad */
0); /* bytes_per_line */
return True;
}
static int xshm_error = 0;
static int xshm_opcode = -1;
/**
* Catches potential Xlib errors.
*/
static int
handle_xerror(Display *dpy, XErrorEvent *event)
{
(void) dpy;
assert(xshm_opcode != -1);
if (event->request_code != xshm_opcode ||
event->minor_code != X_ShmAttach)
return 0;
xshm_error = 1;
return 0;
}
static Bool
XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy)
{
if (pdp->ximage) {
XDestroyImage(pdp->ximage);
pdp->ximage = NULL;
}
if (!xshm_error && shmid >= 0) {
pdp->shminfo.shmid = shmid;
pdp->ximage = XShmCreateImage(dpy,
pdp->visinfo->visual,
pdp->visinfo->depth,
ZPixmap, /* format */
NULL, /* data */
&pdp->shminfo, /* shminfo */
0, 0); /* width, height */
if (pdp->ximage != NULL) {
int (*old_handler)(Display *, XErrorEvent *);
/* dispatch pending errors */
XSync(dpy, False);
old_handler = XSetErrorHandler(handle_xerror);
/* This may trigger the X protocol error we're ready to catch: */
XShmAttach(dpy, &pdp->shminfo);
XSync(dpy, False);
if (xshm_error) {
/* we are on a remote display, this error is normal, don't print it */
XDestroyImage(pdp->ximage);
pdp->ximage = NULL;
}
(void) XSetErrorHandler(old_handler);
}
}
if (pdp->ximage == NULL) {
pdp->shminfo.shmid = -1;
pdp->ximage = XCreateImage(dpy,
pdp->visinfo->visual,
pdp->visinfo->depth,
ZPixmap, 0, /* format, offset */
NULL, /* data */
0, 0, /* width, height */
32, /* bitmap_pad */
0); /* bytes_per_line */
}
/**
* swrast does not handle 24-bit depth with 24 bpp, so let X do the
......@@ -79,7 +144,9 @@ XCreateDrawable(struct drisw_drawable * pdp,
static void
XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
{
XDestroyImage(pdp->ximage);
if (pdp->ximage)
XDestroyImage(pdp->ximage);
free(pdp->visinfo);
XFreeGC(dpy, pdp->gc);
......@@ -133,9 +200,9 @@ bytes_per_line(unsigned pitch_bits, unsigned mul)
}
static void
swrastPutImage2(__DRIdrawable * draw, int op,
swrastXPutImage(__DRIdrawable * draw, int op,
int x, int y, int w, int h, int stride,
char *data, void *loaderPrivate)
int shmid, char *data, void *loaderPrivate)
{
struct drisw_drawable *pdp = loaderPrivate;
__GLXDRIdrawable *pdraw = &(pdp->base);
......@@ -144,6 +211,11 @@ swrastPutImage2(__DRIdrawable * draw, int op,
XImage *ximage;
GC gc;
if (!pdp->ximage || shmid != pdp->shminfo.shmid) {
if (!XCreateDrawable(pdp, shmid, dpy))
return;
}
switch (op) {
case __DRI_SWRAST_IMAGE_OP_DRAW:
gc = pdp->gc;
......@@ -156,24 +228,52 @@ swrastPutImage2(__DRIdrawable * draw, int op,
}
drawable = pdraw->xDrawable;
ximage = pdp->ximage;
ximage->data = data;
ximage->width = w;
ximage->height = h;
ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
ximage->data = data;
XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
if (pdp->shminfo.shmid >= 0) {
ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8);
ximage->height = h;
XShmPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h, False);
XSync(dpy, False);
} else {
ximage->width = w;
ximage->height = h;
XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
}
ximage->data = NULL;
}
static void
swrastPutImageShm(__DRIdrawable * draw, int op,
int x, int y, int w, int h, int stride,
int shmid, char *shmaddr, unsigned offset,
void *loaderPrivate)
{
struct drisw_drawable *pdp = loaderPrivate;
pdp->shminfo.shmaddr = shmaddr;
swrastXPutImage(draw, op, x, y, w, h, stride, shmid,
shmaddr + offset, loaderPrivate);
}
static void
swrastPutImage2(__DRIdrawable * draw, int op,
int x, int y, int w, int h, int stride,
char *data, void *loaderPrivate)
{
swrastXPutImage(draw, op, x, y, w, h, stride, -1,
data, loaderPrivate);
}
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);
swrastXPutImage(draw, op, x, y, w, h, 0, -1,
data, loaderPrivate);
}
static void
......@@ -187,6 +287,11 @@ swrastGetImage2(__DRIdrawable * read,
Drawable readable;
XImage *ximage;
if (!prp->ximage || prp->shminfo.shmid >= 0) {
if (!XCreateDrawable(prp, -1, dpy))
return;
}
readable = pread->xDrawable;
ximage = prp->ximage;
......@@ -208,14 +313,15 @@ swrastGetImage(__DRIdrawable * read,
swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate);
}
static const __DRIswrastLoaderExtension swrastLoaderExtension = {
.base = {__DRI_SWRAST_LOADER, 3 },
static __DRIswrastLoaderExtension swrastLoaderExtension = {
.base = {__DRI_SWRAST_LOADER, 4 },
.getDrawableInfo = swrastGetDrawableInfo,
.putImage = swrastPutImage,
.getImage = swrastGetImage,
.putImage2 = swrastPutImage2,
.getImage2 = swrastGetImage2,
.putImageShm = swrastPutImageShm,
};
static const __DRIextension *loader_extensions[] = {
......@@ -527,7 +633,7 @@ driswCreateDrawable(struct glx_screen *base, XID xDrawable,
pdp->base.drawable = drawable;
pdp->base.psc = &psc->base;
ret = XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID);
ret = XCreateGCs(pdp, psc->base.dpy, xDrawable, modes->visualID);
if (!ret) {
free(pdp);
return NULL;
......@@ -661,6 +767,14 @@ driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
}
}
static int
check_xshm(Display *dpy)
{
int ignore;
return XQueryExtension(dpy, "MIT-SHM", &xshm_opcode, &ignore, &ignore);
}
static struct glx_screen *
driswCreateScreen(int screen, struct glx_display *priv)
{
......@@ -688,6 +802,9 @@ driswCreateScreen(int screen, struct glx_display *priv)
if (extensions == NULL)
goto handle_error;
if (!check_xshm(psc->base.dpy))
swrastLoaderExtension.putImageShm = NULL;
for (i = 0; extensions[i]; i++) {
if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
psc->core = (__DRIcoreExtension *) extensions[i];
......
......@@ -23,6 +23,8 @@
* SOFTWARE.
*/
#include <X11/extensions/XShm.h>
struct drisw_display
{
__GLXDRIdisplay base;
......@@ -62,6 +64,7 @@ struct drisw_drawable
__DRIdrawable *driDrawable;
XVisualInfo *visinfo;
XImage *ximage;
XShmSegmentInfo shminfo;
};
_X_HIDDEN int
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment