drisw: update comment
[mesa.git] / src / glx / 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 <dlfcn.h>
29 #include "dri_common.h"
30
31 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
32 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
33 typedef struct __GLXDRIdrawablePrivateRec __GLXDRIdrawablePrivate;
34
35 struct __GLXDRIdisplayPrivateRec
36 {
37 __GLXDRIdisplay base;
38 };
39
40 struct __GLXDRIcontextPrivateRec
41 {
42 __GLXDRIcontext base;
43 __DRIcontext *driContext;
44 __GLXscreenConfigs *psc;
45 };
46
47 struct __GLXDRIdrawablePrivateRec
48 {
49 __GLXDRIdrawable base;
50
51 GC gc;
52 GC swapgc;
53
54 XVisualInfo *visinfo;
55 XImage *ximage;
56 };
57
58 static Bool
59 XCreateDrawable(__GLXDRIdrawablePrivate * pdp,
60 Display * dpy, XID drawable, int visualid)
61 {
62 XGCValues gcvalues;
63 long visMask;
64 XVisualInfo visTemp;
65 int num_visuals;
66
67 /* create GC's */
68 pdp->gc = XCreateGC(dpy, drawable, 0, NULL);
69 pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL);
70
71 gcvalues.function = GXcopy;
72 gcvalues.graphics_exposures = False;
73 XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues);
74 XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues);
75 XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues);
76
77 /* visual */
78 visTemp.screen = DefaultScreen(dpy);
79 visTemp.visualid = visualid;
80 visMask = (VisualScreenMask | VisualIDMask);
81 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals);
82
83 /* create XImage */
84 pdp->ximage = XCreateImage(dpy,
85 pdp->visinfo->visual,
86 pdp->visinfo->depth,
87 ZPixmap, 0, /* format, offset */
88 NULL, /* data */
89 0, 0, /* width, height */
90 32, /* bitmap_pad */
91 0); /* bytes_per_line */
92
93 return True;
94 }
95
96 static void
97 XDestroyDrawable(__GLXDRIdrawablePrivate * pdp, Display * dpy, XID drawable)
98 {
99 XDestroyImage(pdp->ximage);
100 XFree(pdp->visinfo);
101
102 XFreeGC(dpy, pdp->gc);
103 XFreeGC(dpy, pdp->swapgc);
104 }
105
106 /**
107 * swrast loader functions
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 uw, uh, bw, depth;
123
124 drawable = pdraw->xDrawable;
125
126 stat = XGetGeometry(dpy, drawable, &root,
127 x, y, &uw, &uh, &bw, &depth);
128 *w = uw;
129 *h = uh;
130 }
131
132 static void
133 swrastPutImage2(__DRIdrawable * draw, int op,
134 int x, int y, int w, int h,
135 char *data, int pitch, void *loaderPrivate)
136 {
137 __GLXDRIdrawablePrivate *pdp = loaderPrivate;
138 __GLXDRIdrawable *pdraw = &(pdp->base);
139 Display *dpy = pdraw->psc->dpy;
140 Drawable drawable;
141 XImage *ximage;
142 GC gc;
143
144 switch (op) {
145 case __DRI_SWRAST_IMAGE_OP_DRAW:
146 gc = pdp->gc;
147 break;
148 case __DRI_SWRAST_IMAGE_OP_SWAP:
149 gc = pdp->swapgc;
150 break;
151 default:
152 return;
153 }
154
155 drawable = pdraw->xDrawable;
156
157 ximage = pdp->ximage;
158 ximage->data = data;
159 ximage->width = w;
160 ximage->height = h;
161 ximage->bytes_per_line = pitch;
162
163 XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
164
165 ximage->data = NULL;
166 }
167
168 static void
169 swrastGetImage2(__DRIdrawable * read,
170 int x, int y, int w, int h,
171 char *data, int pitch, void *loaderPrivate)
172 {
173 __GLXDRIdrawablePrivate *prp = loaderPrivate;
174 __GLXDRIdrawable *pread = &(prp->base);
175 Display *dpy = pread->psc->dpy;
176 Drawable readable;
177 XImage *ximage;
178
179 readable = pread->xDrawable;
180
181 ximage = prp->ximage;
182 ximage->data = data;
183 ximage->width = w;
184 ximage->height = h;
185 ximage->bytes_per_line = pitch;
186
187 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
188
189 ximage->data = NULL;
190 }
191
192 /**
193 * Align renderbuffer pitch.
194 *
195 * This should be chosen by the driver and the loader (libGL, xserver/glx)
196 * should use the driver provided pitch.
197 *
198 * It seems that the xorg loader (that is the xserver loading swrast_dri for
199 * indirect rendering, not client-side libGL) requires that the pitch is
200 * exactly the image width padded to 32 bits. XXX
201 *
202 * Is this a hard requirement that requires extra copies for different pitches
203 * or can the xorg loader use the driver pitch without extra copies ?
204 */
205 static inline int
206 bytes_per_line(unsigned pitch_bits, unsigned mul)
207 {
208 unsigned mask = mul - 1;
209
210 return ((pitch_bits + mask) & ~mask) / 8;
211 }
212
213 static void
214 swrastPutImage(__DRIdrawable * draw, int op,
215 int x, int y, int w, int h,
216 char *data, void *loaderPrivate)
217 {
218 __GLXDRIdrawablePrivate *pdp = loaderPrivate;
219 int bpp, pitch;
220
221 bpp = pdp->ximage->bits_per_pixel;
222
223 pitch = bytes_per_line(w * bpp, 32);
224
225 swrastPutImage2(draw, op, x, y, w, h, data, pitch, loaderPrivate);
226 }
227
228 static void
229 swrastGetImage(__DRIdrawable * read,
230 int x, int y, int w, int h,
231 char *data, void *loaderPrivate)
232 {
233 __GLXDRIdrawablePrivate *prp = loaderPrivate;
234 int bpp, pitch;
235
236 bpp = prp->ximage->bits_per_pixel;
237
238 pitch = bytes_per_line(w * bpp, 32);
239
240 swrastGetImage2(read, x, y, w, h, data, pitch, loaderPrivate);
241 }
242
243 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
244 {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
245 swrastGetDrawableInfo,
246 swrastPutImage,
247 swrastGetImage
248 };
249
250 static const __DRIextension *loader_extensions[] = {
251 &systemTimeExtension.base,
252 &swrastLoaderExtension.base,
253 NULL
254 };
255
256 /**
257 * GLXDRI functions
258 */
259
260 static void
261 driDestroyContext(__GLXDRIcontext * context,
262 __GLXscreenConfigs * psc, Display * dpy)
263 {
264 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
265 const __DRIcoreExtension *core = pcp->psc->core;
266
267 (*core->destroyContext) (pcp->driContext);
268
269 Xfree(pcp);
270 }
271
272 static Bool
273 driBindContext(__GLXDRIcontext * context,
274 __GLXDRIdrawable * draw, __GLXDRIdrawable * read)
275 {
276 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
277 const __DRIcoreExtension *core = pcp->psc->core;
278
279 return (*core->bindContext) (pcp->driContext,
280 draw->driDrawable, read->driDrawable);
281 }
282
283 static void
284 driUnbindContext(__GLXDRIcontext * context)
285 {
286 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
287 const __DRIcoreExtension *core = pcp->psc->core;
288
289 (*core->unbindContext) (pcp->driContext);
290 }
291
292 static __GLXDRIcontext *
293 driCreateContext(__GLXscreenConfigs * psc,
294 const __GLcontextModes * mode,
295 GLXContext gc, GLXContext shareList, int renderType)
296 {
297 __GLXDRIcontextPrivate *pcp, *pcp_shared;
298 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
299 const __DRIcoreExtension *core;
300 __DRIcontext *shared = NULL;
301
302 if (!psc || !psc->driScreen)
303 return NULL;
304
305 core = psc->core;
306
307 if (shareList) {
308 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
309 shared = pcp_shared->driContext;
310 }
311
312 pcp = Xmalloc(sizeof *pcp);
313 if (pcp == NULL)
314 return NULL;
315
316 pcp->psc = psc;
317 pcp->driContext =
318 (*core->createNewContext) (psc->__driScreen,
319 config->driConfig, shared, pcp);
320 if (pcp->driContext == NULL) {
321 Xfree(pcp);
322 return NULL;
323 }
324
325 pcp->base.destroyContext = driDestroyContext;
326 pcp->base.bindContext = driBindContext;
327 pcp->base.unbindContext = driUnbindContext;
328
329 return &pcp->base;
330 }
331
332 static void
333 driDestroyDrawable(__GLXDRIdrawable * pdraw)
334 {
335 __GLXDRIdrawablePrivate *pdp = (__GLXDRIdrawablePrivate *) pdraw;
336 const __DRIcoreExtension *core = pdraw->psc->core;
337
338 (*core->destroyDrawable) (pdraw->driDrawable);
339
340 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
341 Xfree(pdp);
342 }
343
344 static __GLXDRIdrawable *
345 driCreateDrawable(__GLXscreenConfigs * psc,
346 XID xDrawable,
347 GLXDrawable drawable, const __GLcontextModes * modes)
348 {
349 __GLXDRIdrawable *pdraw;
350 __GLXDRIdrawablePrivate *pdp;
351 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
352 const __DRIswrastExtension *swrast = psc->swrast;
353
354 /* Old dri can't handle GLX 1.3+ drawable constructors. */
355 if (xDrawable != drawable)
356 return NULL;
357
358 pdp = Xmalloc(sizeof(*pdp));
359 if (!pdp)
360 return NULL;
361
362 pdraw = &(pdp->base);
363 pdraw->xDrawable = xDrawable;
364 pdraw->drawable = drawable;
365 pdraw->psc = psc;
366
367 XCreateDrawable(pdp, psc->dpy, xDrawable, modes->visualID);
368
369 /* Create a new drawable */
370 pdraw->driDrawable =
371 (*swrast->createNewDrawable) (psc->__driScreen, config->driConfig, pdp);
372
373 if (!pdraw->driDrawable) {
374 XDestroyDrawable(pdp, psc->dpy, xDrawable);
375 Xfree(pdp);
376 return NULL;
377 }
378
379 pdraw->destroyDrawable = driDestroyDrawable;
380
381 return pdraw;
382 }
383
384 static int64_t
385 driSwapBuffers(__GLXDRIdrawable * pdraw,
386 int64_t target_msc, int64_t divisor, int64_t remainder)
387 {
388 (void) target_msc;
389 (void) divisor;
390 (void) remainder;
391
392 (*pdraw->psc->core->swapBuffers) (pdraw->driDrawable);
393
394 return 0;
395 }
396
397 static void
398 driDestroyScreen(__GLXscreenConfigs * psc)
399 {
400 /* Free the direct rendering per screen data */
401 (*psc->core->destroyScreen) (psc->__driScreen);
402 psc->__driScreen = NULL;
403 if (psc->driver)
404 dlclose(psc->driver);
405 }
406
407 static void *
408 driOpenSwrast(void)
409 {
410 void *driver = NULL;
411
412 if (driver == NULL)
413 driver = driOpenDriver("swrast");
414
415 if (driver == NULL)
416 driver = driOpenDriver("swrastg");
417
418 return driver;
419 }
420
421 static __GLXDRIscreen *
422 driCreateScreen(__GLXscreenConfigs * psc, int screen,
423 __GLXdisplayPrivate * priv)
424 {
425 __GLXDRIscreen *psp;
426 const __DRIconfig **driver_configs;
427 const __DRIextension **extensions;
428 int i;
429
430 psp = Xcalloc(1, sizeof *psp);
431 if (psp == NULL)
432 return NULL;
433
434 psc->driver = driOpenSwrast();
435 if (psc->driver == NULL)
436 goto handle_error;
437
438 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
439 if (extensions == NULL) {
440 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
441 goto handle_error;
442 }
443
444 for (i = 0; extensions[i]; i++) {
445 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
446 psc->core = (__DRIcoreExtension *) extensions[i];
447 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
448 psc->swrast = (__DRIswrastExtension *) extensions[i];
449 }
450
451 if (psc->core == NULL || psc->swrast == NULL) {
452 ErrorMessageF("core dri extension not found\n");
453 goto handle_error;
454 }
455
456 psc->__driScreen =
457 psc->swrast->createNewScreen(screen,
458 loader_extensions, &driver_configs, psc);
459 if (psc->__driScreen == NULL) {
460 ErrorMessageF("failed to create dri screen\n");
461 goto handle_error;
462 }
463
464 driBindExtensions(psc);
465 driBindCommonExtensions(psc);
466
467 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
468 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
469
470 psc->driver_configs = driver_configs;
471
472 psp->destroyScreen = driDestroyScreen;
473 psp->createContext = driCreateContext;
474 psp->createDrawable = driCreateDrawable;
475 psp->swapBuffers = driSwapBuffers;
476 psp->waitX = NULL;
477 psp->waitGL = NULL;
478
479 return psp;
480
481 handle_error:
482 Xfree(psp);
483
484 if (psc->driver)
485 dlclose(psc->driver);
486
487 ErrorMessageF("reverting to indirect rendering\n");
488
489 return NULL;
490 }
491
492 /* Called from __glXFreeDisplayPrivate.
493 */
494 static void
495 driDestroyDisplay(__GLXDRIdisplay * dpy)
496 {
497 Xfree(dpy);
498 }
499
500 /*
501 * Allocate, initialize and return a __DRIdisplayPrivate object.
502 * This is called from __glXInitialize() when we are given a new
503 * display pointer.
504 */
505 _X_HIDDEN __GLXDRIdisplay *
506 driswCreateDisplay(Display * dpy)
507 {
508 __GLXDRIdisplayPrivate *pdpyp;
509
510 pdpyp = Xmalloc(sizeof *pdpyp);
511 if (pdpyp == NULL)
512 return NULL;
513
514 pdpyp->base.destroyDisplay = driDestroyDisplay;
515 pdpyp->base.createScreen = driCreateScreen;
516
517 return &pdpyp->base;
518 }
519
520 #endif /* GLX_DIRECT_RENDERING */