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