summaryrefslogtreecommitdiffstats
path: root/mesa-8.0-llvmpipe-shmget.patch
blob: 347ad160eb9e6d7c9b6607ba37b82dea508f972b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
diff -up mesa-20120424/src/gallium/state_trackers/dri/sw/drisw.c.jx mesa-20120424/src/gallium/state_trackers/dri/sw/drisw.c
--- mesa-20120424/src/gallium/state_trackers/dri/sw/drisw.c.jx	2012-04-24 07:37:03.000000000 -0400
+++ mesa-20120424/src/gallium/state_trackers/dri/sw/drisw.c	2012-05-16 13:30:36.596312047 -0400
@@ -252,8 +252,6 @@ drisw_update_tex_buffer(struct dri_drawa
    struct pipe_transfer *transfer;
    char *map;
    int x, y, w, h;
-   int ximage_stride, line;
-   int cpp = util_format_get_blocksize(res->format);
 
    get_drawable_info(dPriv, &x, &y, &w, &h);
 
@@ -266,14 +264,6 @@ drisw_update_tex_buffer(struct dri_drawa
    /* Copy the Drawable content to the mapped texture buffer */
    get_image(dPriv, x, y, w, h, map);
 
-   /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. */
-   ximage_stride = w * cpp;
-   for (line = h-1; line; --line) {
-      memmove(&map[line * transfer->stride],
-              &map[line * ximage_stride],
-              ximage_stride);
-   }
-
    pipe_transfer_unmap(pipe, transfer);
    pipe_transfer_destroy(pipe, transfer);
 }
diff -up mesa-20120424/src/glx/drisw_glx.c.jx mesa-20120424/src/glx/drisw_glx.c
--- mesa-20120424/src/glx/drisw_glx.c.jx	2012-04-24 07:37:03.000000000 -0400
+++ mesa-20120424/src/glx/drisw_glx.c	2012-05-16 13:29:25.087965268 -0400
@@ -24,6 +24,9 @@
 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
 
 #include <X11/Xlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
 #include "glxclient.h"
 #include <dlfcn.h>
 #include "dri_common.h"
@@ -206,6 +209,96 @@ swrastPutImage(__DRIdrawable * draw, int
    ximage->data = NULL;
 }
 
+static int shm_error;
+
+static int
+shm_handler(Display *d, XErrorEvent *e)
+{
+    shm_error = 1;
+    return 0;
+}
+
+static int
+align(int value, int alignment)
+{
+   return (value + alignment - 1) & ~(alignment - 1);
+}
+
+/*
+ * Slight fast path.  Short of changing how texture memory is allocated, we
+ * have two options for getting the pixels out.  GetImage is clamped by the
+ * server's write buffer size, so you end up doing lots of relatively small
+ * requests (128k each or so), with two memcpys: down into the kernel, and
+ * then back up.  ShmGetImage is one big blit into the shm segment (which
+ * could be GPU DMA, in principle) and then another one here.
+ */
+static Bool
+swrastShmGetImage(__DRIdrawable *read, char *data, struct drisw_drawable *prp)
+{
+    __GLXDRIdrawable *pread = &(prp->base);
+    Display *dpy = pread->psc->dpy;
+    XImage *ximage = prp->ximage;
+    unsigned long image_size = ximage->height * ximage->bytes_per_line;
+    Bool ret = 0;
+    XShmSegmentInfo seg = { 0, -1, (void *)-1, 0 };
+    int (*old_handler)(Display *, XErrorEvent *);
+
+    if (!XShmQueryExtension(dpy))
+	goto out;
+
+    /* image setup */
+    seg.shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT | 0777);
+    if (seg.shmid < 0)
+	goto out;
+
+    seg.shmaddr = shmat(seg.shmid, NULL, 0);
+    if (seg.shmaddr == (void *)-1)
+	goto out;
+
+    XSync(dpy, 0);
+    old_handler = XSetErrorHandler(shm_handler);
+    XShmAttach(dpy, &seg);
+    XSync(dpy, 0);
+    XSetErrorHandler(old_handler);
+    if (shm_error)
+	goto out;
+
+    ximage->data = seg.shmaddr;
+    ximage->obdata = &seg;
+    if (!XShmGetImage(dpy, pread->xDrawable, ximage, 0, 0, -1))
+	goto out;
+
+    /*
+     * ShmGetImage doesn't actually pay attention to ->bytes_per_line.
+     * We have to compensate for this somewhere since llvmpipe's natural
+     * tile width is 64.  Do it here so we don't have to undo it with a
+     * bunch of memmove in the driver.
+     */
+    do {
+	int i;
+	char *src = ximage->data;
+	int dst_width = align(ximage->width * ximage->bits_per_pixel / 8, 256);
+
+	for (i = 0; i < ximage->height; i++) {
+	    memcpy(data, src, ximage->bytes_per_line);
+	    data += dst_width;
+	    src += ximage->bytes_per_line;
+	}
+    } while (0);
+    ret = 1;
+
+out:
+    ximage->obdata = NULL;
+    ximage->data = NULL;
+    shm_error = 0;
+    XShmDetach(dpy, &seg);
+    if (seg.shmaddr != (void *)-1)
+	shmdt(seg.shmaddr);
+    if (seg.shmid > -1)
+	shmctl(seg.shmid, IPC_RMID, NULL);
+    return ret;
+}
+
 static void
 swrastGetImage(__DRIdrawable * read,
                int x, int y, int w, int h,
@@ -220,11 +313,17 @@ swrastGetImage(__DRIdrawable * read,
    readable = pread->xDrawable;
 
    ximage = prp->ximage;
-   ximage->data = data;
    ximage->width = w;
    ximage->height = h;
    ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
 
+   /* XXX check dimensions, if any caller ever sub-images */
+   if (swrastShmGetImage(read, data, prp))
+      return;
+
+   /* shm failed, fall back to protocol */
+   ximage->data = data;
+
    XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
 
    ximage->data = NULL;