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