Tizen 2.0 Release
[profile/ivi/osmesa.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 #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
31 struct drisw_display
32 {
33    __GLXDRIdisplay base;
34 };
35
36 struct drisw_context
37 {
38    struct glx_context base;
39    __DRIcontext *driContext;
40
41 };
42
43 struct drisw_screen
44 {
45    struct glx_screen 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
56 struct 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
68 static Bool
69 XCreateDrawable(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   /**
104    * swrast does not handle 24-bit depth with 24 bpp, so let X do the
105    * the conversion for us.
106    */
107   if (pdp->ximage->bits_per_pixel == 24)
108      pdp->ximage->bits_per_pixel = 32;
109
110    return True;
111 }
112
113 static void
114 XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
115 {
116    XDestroyImage(pdp->ximage);
117    XFree(pdp->visinfo);
118
119    XFreeGC(dpy, pdp->gc);
120    XFreeGC(dpy, pdp->swapgc);
121 }
122
123 /**
124  * swrast loader functions
125  */
126
127 static void
128 swrastGetDrawableInfo(__DRIdrawable * draw,
129                       int *x, int *y, int *w, int *h,
130                       void *loaderPrivate)
131 {
132    struct drisw_drawable *pdp = loaderPrivate;
133    __GLXDRIdrawable *pdraw = &(pdp->base);
134    Display *dpy = pdraw->psc->dpy;
135    Drawable drawable;
136
137    Window root;
138    unsigned uw, uh, bw, depth;
139
140    drawable = pdraw->xDrawable;
141
142    XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
143    *w = uw;
144    *h = uh;
145 }
146
147 /**
148  * Align renderbuffer pitch.
149  *
150  * This should be chosen by the driver and the loader (libGL, xserver/glx)
151  * should use the driver provided pitch.
152  *
153  * It seems that the xorg loader (that is the xserver loading swrast_dri for
154  * indirect rendering, not client-side libGL) requires that the pitch is
155  * exactly the image width padded to 32 bits. XXX
156  *
157  * The above restriction can probably be overcome by using ScratchPixmap and
158  * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
159  * the scratch pixmap to 'pitch / cpp'.
160  */
161 static inline int
162 bytes_per_line(unsigned pitch_bits, unsigned mul)
163 {
164    unsigned mask = mul - 1;
165
166    return ((pitch_bits + mask) & ~mask) / 8;
167 }
168
169 static void
170 swrastPutImage(__DRIdrawable * draw, int op,
171                int x, int y, int w, int h,
172                char *data, void *loaderPrivate)
173 {
174    struct drisw_drawable *pdp = loaderPrivate;
175    __GLXDRIdrawable *pdraw = &(pdp->base);
176    Display *dpy = pdraw->psc->dpy;
177    Drawable drawable;
178    XImage *ximage;
179    GC gc;
180
181    switch (op) {
182    case __DRI_SWRAST_IMAGE_OP_DRAW:
183       gc = pdp->gc;
184       break;
185    case __DRI_SWRAST_IMAGE_OP_SWAP:
186       gc = pdp->swapgc;
187       break;
188    default:
189       return;
190    }
191
192    drawable = pdraw->xDrawable;
193
194    ximage = pdp->ximage;
195    ximage->data = data;
196    ximage->width = w;
197    ximage->height = h;
198    ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
199
200    XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
201
202    ximage->data = NULL;
203 }
204
205 static void
206 swrastGetImage(__DRIdrawable * read,
207                int x, int y, int w, int h,
208                char *data, void *loaderPrivate)
209 {
210    struct drisw_drawable *prp = loaderPrivate;
211    __GLXDRIdrawable *pread = &(prp->base);
212    Display *dpy = pread->psc->dpy;
213    Drawable readable;
214    XImage *ximage;
215
216    readable = pread->xDrawable;
217
218    ximage = prp->ximage;
219    ximage->data = data;
220    ximage->width = w;
221    ximage->height = h;
222    ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
223
224    XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
225
226    ximage->data = NULL;
227 }
228
229 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
230    {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
231    swrastGetDrawableInfo,
232    swrastPutImage,
233    swrastGetImage
234 };
235
236 static const __DRIextension *loader_extensions[] = {
237    &systemTimeExtension.base,
238    &swrastLoaderExtension.base,
239    NULL
240 };
241
242 /**
243  * GLXDRI functions
244  */
245
246 static void
247 drisw_destroy_context(struct glx_context *context)
248 {
249    struct drisw_context *pcp = (struct drisw_context *) context;
250    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
251
252    driReleaseDrawables(&pcp->base);
253
254    if (context->xid)
255       glx_send_destroy_context(psc->base.dpy, context->xid);
256
257    if (context->extensions)
258       XFree((char *) context->extensions);
259
260    (*psc->core->destroyContext) (pcp->driContext);
261
262    Xfree(pcp);
263 }
264
265 static int
266 drisw_bind_context(struct glx_context *context, struct glx_context *old,
267                    GLXDrawable draw, GLXDrawable read)
268 {
269    struct drisw_context *pcp = (struct drisw_context *) context;
270    struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
271    struct drisw_drawable *pdraw, *pread;
272
273    pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
274    pread = (struct drisw_drawable *) driFetchDrawable(context, read);
275
276    driReleaseDrawables(&pcp->base);
277
278    if (pdraw == NULL || pread == NULL)
279       return GLXBadDrawable;
280
281    if ((*psc->core->bindContext) (pcp->driContext,
282                                   pdraw->driDrawable, pread->driDrawable))
283       return Success;
284
285    return GLXBadContext;
286 }
287
288 static void
289 drisw_unbind_context(struct glx_context *context, struct glx_context *new)
290 {
291    struct drisw_context *pcp = (struct drisw_context *) context;
292    struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
293
294    (*psc->core->unbindContext) (pcp->driContext);
295 }
296
297 static const struct glx_context_vtable drisw_context_vtable = {
298    drisw_destroy_context,
299    drisw_bind_context,
300    drisw_unbind_context,
301    NULL,
302    NULL,
303    DRI_glXUseXFont,
304    NULL,
305    NULL,
306    NULL, /* get_proc_address */
307 };
308
309 static struct glx_context *
310 drisw_create_context(struct glx_screen *base,
311                      struct glx_config *config_base,
312                      struct glx_context *shareList, int renderType)
313 {
314    struct drisw_context *pcp, *pcp_shared;
315    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
316    struct drisw_screen *psc = (struct drisw_screen *) base;
317    __DRIcontext *shared = NULL;
318
319    if (!psc->base.driScreen)
320       return NULL;
321
322    if (shareList) {
323       pcp_shared = (struct drisw_context *) shareList;
324       shared = pcp_shared->driContext;
325    }
326
327    pcp = Xmalloc(sizeof *pcp);
328    if (pcp == NULL)
329       return NULL;
330
331    memset(pcp, 0, sizeof *pcp);
332    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
333       Xfree(pcp);
334       return NULL;
335    }
336
337    pcp->driContext =
338       (*psc->core->createNewContext) (psc->driScreen,
339                                       config->driConfig, shared, pcp);
340    if (pcp->driContext == NULL) {
341       Xfree(pcp);
342       return NULL;
343    }
344
345    pcp->base.vtable = &drisw_context_vtable;
346
347    return &pcp->base;
348 }
349
350 static void
351 driswDestroyDrawable(__GLXDRIdrawable * pdraw)
352 {
353    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
354    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
355
356    (*psc->core->destroyDrawable) (pdp->driDrawable);
357
358    XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
359    Xfree(pdp);
360 }
361
362 static __GLXDRIdrawable *
363 driswCreateDrawable(struct glx_screen *base, XID xDrawable,
364                     GLXDrawable drawable, struct glx_config *modes)
365 {
366    struct drisw_drawable *pdp;
367    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
368    struct drisw_screen *psc = (struct drisw_screen *) base;
369
370    const __DRIswrastExtension *swrast = psc->swrast;
371
372    pdp = Xmalloc(sizeof(*pdp));
373    if (!pdp)
374       return NULL;
375
376    memset(pdp, 0, sizeof *pdp);
377    pdp->base.xDrawable = xDrawable;
378    pdp->base.drawable = drawable;
379    pdp->base.psc = &psc->base;
380
381    XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID);
382
383    /* Create a new drawable */
384    pdp->driDrawable =
385       (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
386
387    if (!pdp->driDrawable) {
388       XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
389       Xfree(pdp);
390       return NULL;
391    }
392
393    pdp->base.destroyDrawable = driswDestroyDrawable;
394
395    return &pdp->base;
396 }
397
398 static int64_t
399 driswSwapBuffers(__GLXDRIdrawable * pdraw,
400                  int64_t target_msc, int64_t divisor, int64_t remainder)
401 {
402    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
403    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
404
405    (void) target_msc;
406    (void) divisor;
407    (void) remainder;
408
409    (*psc->core->swapBuffers) (pdp->driDrawable);
410
411    return 0;
412 }
413
414 static void
415 driswDestroyScreen(struct glx_screen *base)
416 {
417    struct drisw_screen *psc = (struct drisw_screen *) base;
418
419    /* Free the direct rendering per screen data */
420    (*psc->core->destroyScreen) (psc->driScreen);
421    driDestroyConfigs(psc->driver_configs);
422    psc->driScreen = NULL;
423    if (psc->driver)
424       dlclose(psc->driver);
425 }
426
427 static void *
428 driOpenSwrast(void)
429 {
430    void *driver = NULL;
431
432    if (driver == NULL)
433       driver = driOpenDriver("swrast");
434
435    if (driver == NULL)
436       driver = driOpenDriver("swrastg");
437
438    return driver;
439 }
440
441 static const struct glx_screen_vtable drisw_screen_vtable = {
442    drisw_create_context
443 };
444
445 static struct glx_screen *
446 driswCreateScreen(int screen, struct glx_display *priv)
447 {
448    __GLXDRIscreen *psp;
449    const __DRIconfig **driver_configs;
450    const __DRIextension **extensions;
451    struct drisw_screen *psc;
452    int i;
453
454    psc = Xcalloc(1, sizeof *psc);
455    if (psc == NULL)
456       return NULL;
457
458    memset(psc, 0, sizeof *psc);
459    if (!glx_screen_init(&psc->base, screen, priv)) {
460       Xfree(psc);
461       return NULL;
462    }
463
464    psc->driver = driOpenSwrast();
465    if (psc->driver == NULL)
466       goto handle_error;
467
468    extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
469    if (extensions == NULL) {
470       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
471       goto handle_error;
472    }
473
474    for (i = 0; extensions[i]; i++) {
475       if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
476          psc->core = (__DRIcoreExtension *) extensions[i];
477       if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
478          psc->swrast = (__DRIswrastExtension *) extensions[i];
479    }
480
481    if (psc->core == NULL || psc->swrast == NULL) {
482       ErrorMessageF("core dri extension not found\n");
483       goto handle_error;
484    }
485
486    psc->driScreen =
487       psc->swrast->createNewScreen(screen, loader_extensions,
488                                    &driver_configs, psc);
489    if (psc->driScreen == NULL) {
490       ErrorMessageF("failed to create dri screen\n");
491       goto handle_error;
492    }
493
494    psc->base.configs =
495       driConvertConfigs(psc->core, psc->base.configs, driver_configs);
496    psc->base.visuals =
497       driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
498
499    psc->driver_configs = driver_configs;
500
501    psc->base.vtable = &drisw_screen_vtable;
502    psp = &psc->vtable;
503    psc->base.driScreen = psp;
504    psp->destroyScreen = driswDestroyScreen;
505    psp->createDrawable = driswCreateDrawable;
506    psp->swapBuffers = driswSwapBuffers;
507
508    return &psc->base;
509
510  handle_error:
511    if (psc->driver)
512       dlclose(psc->driver);
513    glx_screen_cleanup(&psc->base);
514    Xfree(psc);
515
516    ErrorMessageF("reverting to indirect rendering\n");
517
518    return NULL;
519 }
520
521 /* Called from __glXFreeDisplayPrivate.
522  */
523 static void
524 driswDestroyDisplay(__GLXDRIdisplay * dpy)
525 {
526    Xfree(dpy);
527 }
528
529 /*
530  * Allocate, initialize and return a __DRIdisplayPrivate object.
531  * This is called from __glXInitialize() when we are given a new
532  * display pointer.
533  */
534 _X_HIDDEN __GLXDRIdisplay *
535 driswCreateDisplay(Display * dpy)
536 {
537    struct drisw_display *pdpyp;
538
539    pdpyp = Xmalloc(sizeof *pdpyp);
540    if (pdpyp == NULL)
541       return NULL;
542
543    pdpyp->base.destroyDisplay = driswDestroyDisplay;
544    pdpyp->base.createScreen = driswCreateScreen;
545
546    return &pdpyp->base;
547 }
548
549 #endif /* GLX_DIRECT_RENDERING */