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