Merge remote branch 'origin/gallium-0.2' into gallium-0.2
[mesa.git] / src / glx / x11 / drisw_glx.c
1 /*
2 * Copyright 2008 George Sapountzis
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #ifdef GLX_DIRECT_RENDERING
25
26 #include <X11/Xlib.h>
27 #include "glxclient.h"
28 #include "glcontextmodes.h"
29 #include <dlfcn.h>
30 #include "dri_common.h"
31
32 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
33 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
34 typedef struct __GLXDRIdrawablePrivateRec __GLXDRIdrawablePrivate;
35
36 struct __GLXDRIdisplayPrivateRec {
37 __GLXDRIdisplay base;
38 };
39
40 struct __GLXDRIcontextPrivateRec {
41 __GLXDRIcontext base;
42 __DRIcontext *driContext;
43 __GLXscreenConfigs *psc;
44 };
45
46 struct __GLXDRIdrawablePrivateRec {
47 __GLXDRIdrawable base;
48
49 GC gc;
50 GC swapgc;
51
52 XVisualInfo *visinfo;
53 XImage *ximage;
54 int bpp;
55 };
56
57 /**
58 * swrast loader functions
59 */
60
61 static Bool XCreateDrawable(__GLXDRIdrawablePrivate *pdp,
62 Display *dpy, XID drawable, int visualid)
63 {
64 XGCValues gcvalues;
65 long visMask;
66 XVisualInfo visTemp;
67 int num_visuals;
68
69 /* create GC's */
70 pdp->gc = XCreateGC(dpy, drawable, 0, NULL);
71 pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL);
72
73 gcvalues.function = GXcopy;
74 gcvalues.graphics_exposures = False;
75 XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues);
76 XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues);
77 XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues);
78
79 /* create XImage */
80 visTemp.screen = DefaultScreen(dpy);
81 visTemp.visualid = visualid;
82 visMask = (VisualScreenMask | VisualIDMask);
83 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals);
84
85 pdp->ximage = XCreateImage(dpy,
86 pdp->visinfo->visual,
87 pdp->visinfo->depth,
88 ZPixmap, 0, /* format, offset */
89 NULL, /* data */
90 0, 0, /* size */
91 32, /* bitmap_pad */
92 0); /* bytes_per_line */
93
94 /* get the true number of bits per pixel */
95 pdp->bpp = pdp->ximage->bits_per_pixel;
96
97 return True;
98 }
99
100 static void XDestroyDrawable(__GLXDRIdrawablePrivate *pdp,
101 Display *dpy, XID drawable)
102 {
103 XDestroyImage(pdp->ximage);
104 XFree(pdp->visinfo);
105
106 XFreeGC(dpy, pdp->gc);
107 XFreeGC(dpy, pdp->swapgc);
108 }
109
110 static void
111 swrastGetDrawableInfo(__DRIdrawable *draw,
112 int *x, int *y, int *w, int *h,
113 void *loaderPrivate)
114 {
115 __GLXDRIdrawablePrivate *pdp = loaderPrivate;
116 __GLXDRIdrawable *pdraw = &(pdp->base);;
117 Display *dpy = pdraw->psc->dpy;
118 Drawable drawable;
119
120 Window root;
121 Status stat;
122 unsigned int bw, depth;
123
124 drawable = pdraw->xDrawable;
125
126 stat = XGetGeometry(dpy, drawable, &root,
127 x, y, (unsigned int *)w, (unsigned int *)h,
128 &bw, &depth);
129 }
130
131 static inline int
132 bytes_per_line(int w, int bpp, unsigned mul)
133 {
134 unsigned mask = mul - 1;
135
136 return ((w * bpp + mask) & ~mask) / 8;
137 }
138
139 static void
140 swrastPutImage(__DRIdrawable *draw, int op,
141 int x, int y, int w, int h, char *data,
142 void *loaderPrivate)
143 {
144 __GLXDRIdrawablePrivate *pdp = loaderPrivate;
145 __GLXDRIdrawable *pdraw = &(pdp->base);;
146 Display *dpy = pdraw->psc->dpy;
147 Drawable drawable;
148 XImage *ximage;
149 GC gc;
150
151 switch (op) {
152 case __DRI_SWRAST_IMAGE_OP_DRAW:
153 gc = pdp->gc;
154 break;
155 case __DRI_SWRAST_IMAGE_OP_SWAP:
156 gc = pdp->swapgc;
157 break;
158 default:
159 return;
160 }
161
162 drawable = pdraw->xDrawable;
163
164 ximage = pdp->ximage;
165 ximage->data = data;
166 ximage->width = w;
167 ximage->height = h;
168 ximage->bytes_per_line = bytes_per_line(w, pdp->bpp, 32);
169
170 XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
171
172 ximage->data = NULL;
173 }
174
175 static void
176 swrastGetImage(__DRIdrawable *draw,
177 int x, int y, int w, int h, char *data,
178 void *loaderPrivate)
179 {
180 __GLXDRIdrawablePrivate *pdp = loaderPrivate;
181 __GLXDRIdrawable *pdraw = &(pdp->base);;
182 Display *dpy = pdraw->psc->dpy;
183 Drawable drawable;
184 XImage *ximage;
185
186 drawable = pdraw->xDrawable;
187
188 ximage = pdp->ximage;
189 ximage->data = data;
190 ximage->width = w;
191 ximage->height = h;
192 ximage->bytes_per_line = bytes_per_line(w, pdp->bpp, 32);
193
194 XGetSubImage(dpy, drawable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
195
196 ximage->data = NULL;
197 }
198
199 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
200 { __DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION },
201 swrastGetDrawableInfo,
202 swrastPutImage,
203 swrastGetImage
204 };
205
206 static const __DRIextension *loader_extensions[] = {
207 &systemTimeExtension.base,
208 &swrastLoaderExtension.base,
209 NULL
210 };
211
212 /**
213 * GLXDRI functions
214 */
215
216 static void driDestroyContext(__GLXDRIcontext *context,
217 __GLXscreenConfigs *psc, Display *dpy)
218 {
219 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
220 const __DRIcoreExtension *core = pcp->psc->core;
221
222 (*core->destroyContext)(pcp->driContext);
223
224 Xfree(pcp);
225 }
226
227 static Bool driBindContext(__GLXDRIcontext *context,
228 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
229 {
230 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
231 const __DRIcoreExtension *core = pcp->psc->core;
232
233 return (*core->bindContext)(pcp->driContext,
234 draw->driDrawable,
235 read->driDrawable);
236 }
237
238 static void driUnbindContext(__GLXDRIcontext *context)
239 {
240 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
241 const __DRIcoreExtension *core = pcp->psc->core;
242
243 (*core->unbindContext)(pcp->driContext);
244 }
245
246 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
247 const __GLcontextModes *mode,
248 GLXContext gc,
249 GLXContext shareList, int renderType)
250 {
251 __GLXDRIcontextPrivate *pcp, *pcp_shared;
252 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
253 const __DRIcoreExtension *core = psc->core;
254 __DRIcontext *shared = NULL;
255
256 if (!psc || !psc->driScreen)
257 return NULL;
258
259 if (shareList) {
260 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
261 shared = pcp_shared->driContext;
262 }
263
264 pcp = Xmalloc(sizeof *pcp);
265 if (pcp == NULL)
266 return NULL;
267
268 pcp->psc = psc;
269 pcp->driContext =
270 (*core->createNewContext)(psc->__driScreen,
271 config->driConfig, shared, pcp);
272 if (pcp->driContext == NULL) {
273 Xfree(pcp);
274 return NULL;
275 }
276
277 pcp->base.destroyContext = driDestroyContext;
278 pcp->base.bindContext = driBindContext;
279 pcp->base.unbindContext = driUnbindContext;
280
281 return &pcp->base;
282 }
283
284 static void driDestroyDrawable(__GLXDRIdrawable *pdraw)
285 {
286 __GLXDRIdrawablePrivate *pdp = (__GLXDRIdrawablePrivate *) pdraw;
287 const __DRIcoreExtension *core = pdraw->psc->core;
288
289 (*core->destroyDrawable)(pdraw->driDrawable);
290
291 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
292 Xfree(pdp);
293 }
294
295 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
296 XID xDrawable,
297 GLXDrawable drawable,
298 const __GLcontextModes *modes)
299 {
300 __GLXDRIdrawable *pdraw;
301 __GLXDRIdrawablePrivate *pdp;
302 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
303 const __DRIswrastExtension *swrast = psc->swrast;
304
305 /* Old dri can't handle GLX 1.3+ drawable constructors. */
306 if (xDrawable != drawable)
307 return NULL;
308
309 pdp = Xmalloc(sizeof(*pdp));
310 if (!pdp)
311 return NULL;
312
313 pdraw = &(pdp->base);
314 pdraw->xDrawable = xDrawable;
315 pdraw->drawable = drawable;
316 pdraw->psc = psc;
317
318 XCreateDrawable(pdp, psc->dpy, xDrawable, modes->visualID);
319
320 /* Create a new drawable */
321 pdraw->driDrawable =
322 (*swrast->createNewDrawable)(psc->__driScreen,
323 config->driConfig,
324 pdp);
325
326 if (!pdraw->driDrawable) {
327 XDestroyDrawable(pdp, psc->dpy, xDrawable);
328 Xfree(pdp);
329 return NULL;
330 }
331
332 pdraw->destroyDrawable = driDestroyDrawable;
333
334 return pdraw;
335 }
336
337 static void driSwapBuffers(__GLXDRIdrawable *pdraw)
338 {
339 (*pdraw->psc->core->swapBuffers)(pdraw->driDrawable);
340 }
341
342 static void driDestroyScreen(__GLXscreenConfigs *psc)
343 {
344 /* Free the direct rendering per screen data */
345 (*psc->core->destroyScreen)(psc->__driScreen);
346 psc->__driScreen = NULL;
347 if (psc->driver)
348 dlclose(psc->driver);
349 }
350
351 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
352 __GLXdisplayPrivate *priv)
353 {
354 __GLXDRIscreen *psp;
355 const __DRIconfig **driver_configs;
356 const __DRIextension **extensions;
357 const char *driverName = "swrast";
358 int i;
359
360 psp = Xmalloc(sizeof *psp);
361 if (psp == NULL)
362 return NULL;
363
364 /* Initialize per screen dynamic client GLX extensions */
365 psc->ext_list_first_time = GL_TRUE;
366
367 psc->driver = driOpenDriver(driverName);
368 if (psc->driver == NULL)
369 goto handle_error;
370
371 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
372 if (extensions == NULL) {
373 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
374 goto handle_error;
375 }
376
377 for (i = 0; extensions[i]; i++) {
378 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
379 psc->core = (__DRIcoreExtension *) extensions[i];
380 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
381 psc->swrast = (__DRIswrastExtension *) extensions[i];
382 }
383
384 if (psc->core == NULL || psc->swrast == NULL) {
385 ErrorMessageF("core dri extension not found\n");
386 goto handle_error;
387 }
388
389 psc->__driScreen =
390 psc->swrast->createNewScreen(screen,
391 loader_extensions, &driver_configs, psc);
392 if (psc->__driScreen == NULL) {
393 ErrorMessageF("failed to create dri screen\n");
394 goto handle_error;
395 }
396
397 driBindExtensions(psc, 0);
398
399 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
400 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
401
402 psp->destroyScreen = driDestroyScreen;
403 psp->createContext = driCreateContext;
404 psp->createDrawable = driCreateDrawable;
405 psp->swapBuffers = driSwapBuffers;
406
407 return psp;
408
409 handle_error:
410 Xfree(psp);
411
412 if (psc->driver)
413 dlclose(psc->driver);
414
415 ErrorMessageF("reverting to indirect rendering\n");
416
417 return NULL;
418 }
419
420 /* Called from __glXFreeDisplayPrivate.
421 */
422 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
423 {
424 Xfree(dpy);
425 }
426
427 /*
428 * Allocate, initialize and return a __DRIdisplayPrivate object.
429 * This is called from __glXInitialize() when we are given a new
430 * display pointer.
431 */
432 _X_HIDDEN __GLXDRIdisplay *driswCreateDisplay(Display *dpy)
433 {
434 __GLXDRIdisplayPrivate *pdpyp;
435
436 pdpyp = Xmalloc(sizeof *pdpyp);
437 if (pdpyp == NULL)
438 return NULL;
439
440 pdpyp->base.destroyDisplay = driDestroyDisplay;
441 pdpyp->base.createScreen = driCreateScreen;
442
443 return &pdpyp->base;
444 }
445
446 #endif /* GLX_DIRECT_RENDERING */