glx: Drop broken drawable garbage collection
[profile/ivi/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 #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    return True;
104 }
105
106 static void
107 XDestroyDrawable(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
120 static void
121 swrastGetDrawableInfo(__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  */
156 static inline int
157 bytes_per_line(unsigned pitch_bits, unsigned mul)
158 {
159    unsigned mask = mul - 1;
160
161    return ((pitch_bits + mask) & ~mask) / 8;
162 }
163
164 static void
165 swrastPutImage(__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
200 static void
201 swrastGetImage(__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
224 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
225    {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
226    swrastGetDrawableInfo,
227    swrastPutImage,
228    swrastGetImage
229 };
230
231 static const __DRIextension *loader_extensions[] = {
232    &systemTimeExtension.base,
233    &swrastLoaderExtension.base,
234    NULL
235 };
236
237 /**
238  * GLXDRI functions
239  */
240
241 static void
242 drisw_destroy_context(struct glx_context *context)
243 {
244    struct drisw_context *pcp = (struct drisw_context *) context;
245    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
246
247    if (context->xid)
248       glx_send_destroy_context(psc->base.dpy, context->xid);
249
250    if (context->extensions)
251       XFree((char *) context->extensions);
252
253    (*psc->core->destroyContext) (pcp->driContext);
254
255    Xfree(pcp);
256 }
257
258 static int
259 drisw_bind_context(struct glx_context *context, struct glx_context *old,
260                    GLXDrawable draw, GLXDrawable read)
261 {
262    struct drisw_context *pcp = (struct drisw_context *) context;
263    struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
264    struct drisw_drawable *pdraw, *pread;
265
266    pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
267    pread = (struct drisw_drawable *) driFetchDrawable(context, read);
268
269    if (pdraw == NULL || pread == NULL)
270       return GLXBadDrawable;
271
272    if ((*psc->core->bindContext) (pcp->driContext,
273                                   pdraw->driDrawable, pread->driDrawable))
274       return Success;
275
276    return GLXBadContext;
277 }
278
279 static void
280 drisw_unbind_context(struct glx_context *context, struct glx_context *new)
281 {
282    struct drisw_context *pcp = (struct drisw_context *) context;
283    struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
284
285    (*psc->core->unbindContext) (pcp->driContext);
286
287    driReleaseDrawables(&pcp->base);
288 }
289
290 static const struct glx_context_vtable drisw_context_vtable = {
291    drisw_destroy_context,
292    drisw_bind_context,
293    drisw_unbind_context,
294    NULL,
295    NULL,
296    DRI_glXUseXFont,
297    NULL,
298    NULL,
299 };
300
301 static struct glx_context *
302 drisw_create_context(struct glx_screen *base,
303                      struct glx_config *config_base,
304                      struct glx_context *shareList, int renderType)
305 {
306    struct drisw_context *pcp, *pcp_shared;
307    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
308    struct drisw_screen *psc = (struct drisw_screen *) base;
309    __DRIcontext *shared = NULL;
310
311    if (!psc->base.driScreen)
312       return NULL;
313
314    if (shareList) {
315       pcp_shared = (struct drisw_context *) shareList;
316       shared = pcp_shared->driContext;
317    }
318
319    pcp = Xmalloc(sizeof *pcp);
320    if (pcp == NULL)
321       return NULL;
322
323    memset(pcp, 0, sizeof *pcp);
324    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
325       Xfree(pcp);
326       return NULL;
327    }
328
329    pcp->driContext =
330       (*psc->core->createNewContext) (psc->driScreen,
331                                       config->driConfig, shared, pcp);
332    if (pcp->driContext == NULL) {
333       Xfree(pcp);
334       return NULL;
335    }
336
337    pcp->base.vtable = &drisw_context_vtable;
338
339    return &pcp->base;
340 }
341
342 static void
343 driDestroyDrawable(__GLXDRIdrawable * pdraw)
344 {
345    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
346    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
347
348    (*psc->core->destroyDrawable) (pdp->driDrawable);
349
350    XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
351    Xfree(pdp);
352 }
353
354 static __GLXDRIdrawable *
355 driCreateDrawable(struct glx_screen *base, XID xDrawable,
356                   GLXDrawable drawable, struct glx_config *modes)
357 {
358    struct drisw_drawable *pdp;
359    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
360    struct drisw_screen *psc = (struct drisw_screen *) base;
361
362    const __DRIswrastExtension *swrast = psc->swrast;
363
364    /* Old dri can't handle GLX 1.3+ drawable constructors. */
365    if (xDrawable != drawable)
366       return NULL;
367
368    pdp = Xmalloc(sizeof(*pdp));
369    if (!pdp)
370       return NULL;
371
372    memset(pdp, 0, sizeof *pdp);
373    pdp->base.xDrawable = xDrawable;
374    pdp->base.drawable = drawable;
375    pdp->base.psc = &psc->base;
376
377    XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID);
378
379    /* Create a new drawable */
380    pdp->driDrawable =
381       (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
382
383    if (!pdp->driDrawable) {
384       XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
385       Xfree(pdp);
386       return NULL;
387    }
388
389    pdp->base.destroyDrawable = driDestroyDrawable;
390
391    return &pdp->base;
392 }
393
394 static int64_t
395 driSwapBuffers(__GLXDRIdrawable * pdraw,
396                int64_t target_msc, int64_t divisor, int64_t remainder)
397 {
398    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
399    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
400
401    (void) target_msc;
402    (void) divisor;
403    (void) remainder;
404
405    (*psc->core->swapBuffers) (pdp->driDrawable);
406
407    return 0;
408 }
409
410 static void
411 driDestroyScreen(struct glx_screen *base)
412 {
413    struct drisw_screen *psc = (struct drisw_screen *) base;
414
415    /* Free the direct rendering per screen data */
416    (*psc->core->destroyScreen) (psc->driScreen);
417    driDestroyConfigs(psc->driver_configs);
418    psc->driScreen = NULL;
419    if (psc->driver)
420       dlclose(psc->driver);
421 }
422
423 static void *
424 driOpenSwrast(void)
425 {
426    void *driver = NULL;
427
428    if (driver == NULL)
429       driver = driOpenDriver("swrast");
430
431    if (driver == NULL)
432       driver = driOpenDriver("swrastg");
433
434    return driver;
435 }
436
437 static const struct glx_screen_vtable drisw_screen_vtable = {
438    drisw_create_context
439 };
440
441 static struct glx_screen *
442 driCreateScreen(int screen, struct glx_display *priv)
443 {
444    __GLXDRIscreen *psp;
445    const __DRIconfig **driver_configs;
446    const __DRIextension **extensions;
447    struct drisw_screen *psc;
448    int i;
449
450    psc = Xcalloc(1, sizeof *psc);
451    if (psc == NULL)
452       return NULL;
453
454    memset(psc, 0, sizeof *psc);
455    if (!glx_screen_init(&psc->base, screen, priv))
456        return NULL;
457
458    psc->driver = driOpenSwrast();
459    if (psc->driver == NULL)
460       goto handle_error;
461
462    extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
463    if (extensions == NULL) {
464       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
465       goto handle_error;
466    }
467
468    for (i = 0; extensions[i]; i++) {
469       if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
470          psc->core = (__DRIcoreExtension *) extensions[i];
471       if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
472          psc->swrast = (__DRIswrastExtension *) extensions[i];
473    }
474
475    if (psc->core == NULL || psc->swrast == NULL) {
476       ErrorMessageF("core dri extension not found\n");
477       goto handle_error;
478    }
479
480    psc->driScreen =
481       psc->swrast->createNewScreen(screen, loader_extensions,
482                                    &driver_configs, psc);
483    if (psc->driScreen == NULL) {
484       ErrorMessageF("failed to create dri screen\n");
485       goto handle_error;
486    }
487
488    psc->base.configs =
489       driConvertConfigs(psc->core, psc->base.configs, driver_configs);
490    psc->base.visuals =
491       driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
492
493    psc->driver_configs = driver_configs;
494
495    psc->base.vtable = &drisw_screen_vtable;
496    psp = &psc->vtable;
497    psc->base.driScreen = psp;
498    psp->destroyScreen = driDestroyScreen;
499    psp->createDrawable = driCreateDrawable;
500    psp->swapBuffers = driSwapBuffers;
501
502    return &psc->base;
503
504  handle_error:
505    if (psc->driver)
506       dlclose(psc->driver);
507    Xfree(psc);
508
509    ErrorMessageF("reverting to indirect rendering\n");
510
511    return NULL;
512 }
513
514 /* Called from __glXFreeDisplayPrivate.
515  */
516 static void
517 driDestroyDisplay(__GLXDRIdisplay * dpy)
518 {
519    Xfree(dpy);
520 }
521
522 /*
523  * Allocate, initialize and return a __DRIdisplayPrivate object.
524  * This is called from __glXInitialize() when we are given a new
525  * display pointer.
526  */
527 _X_HIDDEN __GLXDRIdisplay *
528 driswCreateDisplay(Display * dpy)
529 {
530    struct drisw_display *pdpyp;
531
532    pdpyp = Xmalloc(sizeof *pdpyp);
533    if (pdpyp == NULL)
534       return NULL;
535
536    pdpyp->base.destroyDisplay = driDestroyDisplay;
537    pdpyp->base.createScreen = driCreateScreen;
538
539    return &pdpyp->base;
540 }
541
542 #endif /* GLX_DIRECT_RENDERING */