glxdriswrast.c revision 6747b715
1/*
2 * Copyright © 2008 George Sapountzis <gsap7@yahoo.gr>
3 * Copyright © 2008 Red Hat, Inc
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of the
10 * copyright holders not be used in advertising or publicity
11 * pertaining to distribution of the software without specific,
12 * written prior permission.  The copyright holders make no
13 * representations about the suitability of this software for any
14 * purpose.  It is provided "as is" without express or implied
15 * warranty.
16 *
17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
22 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 * SOFTWARE.
25 */
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdint.h>
32#include <stdio.h>
33#include <string.h>
34#include <errno.h>
35#include <sys/time.h>
36#include <dlfcn.h>
37
38#include <GL/gl.h>
39#include <GL/internal/dri_interface.h>
40#include <GL/glxtokens.h>
41
42#include "scrnintstr.h"
43#include "pixmapstr.h"
44#include "gcstruct.h"
45#include "os.h"
46
47#include "glxserver.h"
48#include "glxutil.h"
49#include "glxdricommon.h"
50
51#include "g_disptab.h"
52#include "glapitable.h"
53#include "glapi.h"
54#include "glthread.h"
55#include "dispatch.h"
56#include "extension_string.h"
57
58/* RTLD_LOCAL is not defined on Cygwin */
59#ifdef __CYGWIN__
60#ifndef RTLD_LOCAL
61#define RTLD_LOCAL 0
62#endif
63#endif
64
65typedef struct __GLXDRIscreen   __GLXDRIscreen;
66typedef struct __GLXDRIcontext  __GLXDRIcontext;
67typedef struct __GLXDRIdrawable __GLXDRIdrawable;
68
69struct __GLXDRIscreen {
70    __GLXscreen		 base;
71    __DRIscreen		*driScreen;
72    void		*driver;
73
74    const __DRIcoreExtension *core;
75    const __DRIswrastExtension *swrast;
76    const __DRIcopySubBufferExtension *copySubBuffer;
77    const __DRItexBufferExtension *texBuffer;
78};
79
80struct __GLXDRIcontext {
81    __GLXcontext	 base;
82    __DRIcontext	*driContext;
83};
84
85struct __GLXDRIdrawable {
86    __GLXdrawable	 base;
87    __DRIdrawable	*driDrawable;
88    __GLXDRIscreen	*screen;
89
90    GCPtr gc;		/* scratch GC for span drawing */
91    GCPtr swapgc;	/* GC for swapping the color buffers */
92};
93
94static void
95__glXDRIdrawableDestroy(__GLXdrawable *drawable)
96{
97    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
98    const __DRIcoreExtension *core = private->screen->core;
99
100    (*core->destroyDrawable)(private->driDrawable);
101
102    FreeScratchGC(private->gc);
103    FreeScratchGC(private->swapgc);
104
105    __glXDrawableRelease(drawable);
106
107    free(private);
108}
109
110static GLboolean
111__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
112{
113    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
114    const __DRIcoreExtension *core = private->screen->core;
115
116    (*core->swapBuffers)(private->driDrawable);
117
118    return TRUE;
119}
120
121static void
122__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
123			       int x, int y, int w, int h)
124{
125    __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
126    const __DRIcopySubBufferExtension *copySubBuffer =
127	    private->screen->copySubBuffer;
128
129    if (copySubBuffer)
130	(*copySubBuffer->copySubBuffer)(private->driDrawable, x, y, w, h);
131}
132
133static void
134__glXDRIcontextDestroy(__GLXcontext *baseContext)
135{
136    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
137    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
138
139    (*screen->core->destroyContext)(context->driContext);
140    __glXContextDestroy(&context->base);
141    free(context);
142}
143
144static int
145__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
146{
147    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
148    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
149    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
150    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
151
152    return (*screen->core->bindContext)(context->driContext,
153					draw->driDrawable,
154					read->driDrawable);
155}
156
157static int
158__glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
159{
160    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
161    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
162
163    return (*screen->core->unbindContext)(context->driContext);
164}
165
166static int
167__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
168		    unsigned long mask)
169{
170    __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
171    __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
172    __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
173
174    return (*screen->core->copyContext)(dst->driContext,
175					src->driContext, mask);
176}
177
178static int
179__glXDRIcontextForceCurrent(__GLXcontext *baseContext)
180{
181    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
182    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
183    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
184    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
185
186    return (*screen->core->bindContext)(context->driContext,
187					draw->driDrawable,
188					read->driDrawable);
189}
190
191#ifdef __DRI_TEX_BUFFER
192
193static int
194__glXDRIbindTexImage(__GLXcontext *baseContext,
195		     int buffer,
196		     __GLXdrawable *glxPixmap)
197{
198    __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
199    const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
200    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
201
202    if (texBuffer == NULL)
203        return Success;
204
205    texBuffer->setTexBuffer(context->driContext,
206			    glxPixmap->target,
207			    drawable->driDrawable);
208
209    return Success;
210}
211
212static int
213__glXDRIreleaseTexImage(__GLXcontext *baseContext,
214			int buffer,
215			__GLXdrawable *pixmap)
216{
217    /* FIXME: Just unbind the texture? */
218    return Success;
219}
220
221#else
222
223static int
224__glXDRIbindTexImage(__GLXcontext *baseContext,
225		     int buffer,
226		     __GLXdrawable *glxPixmap)
227{
228    return Success;
229}
230
231static int
232__glXDRIreleaseTexImage(__GLXcontext *baseContext,
233			int buffer,
234			__GLXdrawable *pixmap)
235{
236    return Success;
237}
238
239#endif
240
241static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
242    __glXDRIbindTexImage,
243    __glXDRIreleaseTexImage
244};
245
246static void
247__glXDRIscreenDestroy(__GLXscreen *baseScreen)
248{
249    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
250
251    (*screen->core->destroyScreen)(screen->driScreen);
252
253    dlclose(screen->driver);
254
255    __glXScreenDestroy(baseScreen);
256
257    free(screen);
258}
259
260static __GLXcontext *
261__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
262			    __GLXconfig *glxConfig,
263			    __GLXcontext *baseShareContext)
264{
265    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
266    __GLXDRIcontext *context, *shareContext;
267    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
268    const __DRIcoreExtension *core = screen->core;
269    __DRIcontext *driShare;
270
271    shareContext = (__GLXDRIcontext *) baseShareContext;
272    if (shareContext)
273	driShare = shareContext->driContext;
274    else
275	driShare = NULL;
276
277    context = calloc(1, sizeof *context);
278    if (context == NULL)
279	return NULL;
280
281    context->base.destroy           = __glXDRIcontextDestroy;
282    context->base.makeCurrent       = __glXDRIcontextMakeCurrent;
283    context->base.loseCurrent       = __glXDRIcontextLoseCurrent;
284    context->base.copy              = __glXDRIcontextCopy;
285    context->base.forceCurrent      = __glXDRIcontextForceCurrent;
286    context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
287
288    context->driContext =
289	(*core->createNewContext)(screen->driScreen,
290				  config->driConfig, driShare, context);
291
292    return &context->base;
293}
294
295static __GLXdrawable *
296__glXDRIscreenCreateDrawable(ClientPtr client,
297			     __GLXscreen *screen,
298			     DrawablePtr pDraw,
299			     XID drawId,
300			     int type,
301			     XID glxDrawId,
302			     __GLXconfig *glxConfig)
303{
304    ChangeGCVal gcvals[2];
305    __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
306    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
307    __GLXDRIdrawable *private;
308
309    ScreenPtr pScreen = driScreen->base.pScreen;
310
311    private = calloc(1, sizeof *private);
312    if (private == NULL)
313	return NULL;
314
315    private->screen = driScreen;
316    if (!__glXDrawableInit(&private->base, screen,
317			   pDraw, type, glxDrawId, glxConfig)) {
318        free(private);
319	return NULL;
320    }
321
322    private->base.destroy       = __glXDRIdrawableDestroy;
323    private->base.swapBuffers   = __glXDRIdrawableSwapBuffers;
324    private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
325
326    private->gc = CreateScratchGC(pScreen, pDraw->depth);
327    private->swapgc = CreateScratchGC(pScreen, pDraw->depth);
328
329    gcvals[0].val = GXcopy;
330    ChangeGC(NullClient, private->gc, GCFunction, gcvals);
331    gcvals[1].val = FALSE;
332    ChangeGC(NullClient, private->swapgc, GCFunction | GCGraphicsExposures, gcvals);
333
334    private->driDrawable =
335	(*driScreen->swrast->createNewDrawable)(driScreen->driScreen,
336						config->driConfig,
337						private);
338
339    return &private->base;
340}
341
342static void
343swrastGetDrawableInfo(__DRIdrawable *draw,
344		      int *x, int *y, int *w, int *h,
345		      void *loaderPrivate)
346{
347    __GLXDRIdrawable *drawable = loaderPrivate;
348    DrawablePtr pDraw = drawable->base.pDraw;
349
350    *x = pDraw->x;
351    *y = pDraw->x;
352    *w = pDraw->width;
353    *h = pDraw->height;
354}
355
356static void
357swrastPutImage(__DRIdrawable *draw, int op,
358	     int x, int y, int w, int h, char *data,
359	     void *loaderPrivate)
360{
361    __GLXDRIdrawable *drawable = loaderPrivate;
362    DrawablePtr pDraw = drawable->base.pDraw;
363    GCPtr gc;
364
365    switch (op) {
366    case __DRI_SWRAST_IMAGE_OP_DRAW:
367	gc = drawable->gc;
368	break;
369    case __DRI_SWRAST_IMAGE_OP_SWAP:
370	gc = drawable->swapgc;
371	break;
372    default:
373	return;
374    }
375
376    ValidateGC(pDraw, gc);
377
378    gc->ops->PutImage(pDraw, gc, pDraw->depth,
379		      x, y, w, h, 0, ZPixmap, data);
380}
381
382static void
383swrastGetImage(__DRIdrawable *draw,
384	     int x, int y, int w, int h, char *data,
385	     void *loaderPrivate)
386{
387    __GLXDRIdrawable *drawable = loaderPrivate;
388    DrawablePtr pDraw = drawable->base.pDraw;
389    ScreenPtr pScreen = pDraw->pScreen;
390
391    pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data);
392}
393
394static const __DRIswrastLoaderExtension swrastLoaderExtension = {
395    { __DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION },
396    swrastGetDrawableInfo,
397    swrastPutImage,
398    swrastGetImage
399};
400
401static const __DRIextension *loader_extensions[] = {
402    &systemTimeExtension.base,
403    &swrastLoaderExtension.base,
404    NULL
405};
406
407static void
408initializeExtensions(__GLXDRIscreen *screen)
409{
410    const __DRIextension **extensions;
411    int i;
412
413    extensions = screen->core->getExtensions(screen->driScreen);
414
415    for (i = 0; extensions[i]; i++) {
416#ifdef __DRI_COPY_SUB_BUFFER
417	if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
418	    screen->copySubBuffer =
419		(const __DRIcopySubBufferExtension *) extensions[i];
420	    /* GLX_MESA_copy_sub_buffer is always enabled. */
421	}
422#endif
423
424#ifdef __DRI_TEX_BUFFER
425	if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
426	    screen->texBuffer =
427		(const __DRItexBufferExtension *) extensions[i];
428	    /* GLX_EXT_texture_from_pixmap is always enabled. */
429	}
430#endif
431	/* Ignore unknown extensions */
432    }
433}
434
435static const char dri_driver_path[] = DRI_DRIVER_PATH;
436
437static __GLXscreen *
438__glXDRIscreenProbe(ScreenPtr pScreen)
439{
440    const char *driverName = "swrast";
441    __GLXDRIscreen *screen;
442    char filename[128];
443    const __DRIextension **extensions;
444    const __DRIconfig **driConfigs;
445    int i;
446
447    screen = calloc(1, sizeof *screen);
448    if (screen == NULL)
449	return NULL;
450
451    screen->base.destroy        = __glXDRIscreenDestroy;
452    screen->base.createContext  = __glXDRIscreenCreateContext;
453    screen->base.createDrawable = __glXDRIscreenCreateDrawable;
454    screen->base.swapInterval   = NULL;
455    screen->base.pScreen       = pScreen;
456
457    snprintf(filename, sizeof filename,
458	     "%s/%s_dri.so", dri_driver_path, driverName);
459
460    screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
461    if (screen->driver == NULL) {
462	LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
463		   filename, dlerror());
464        goto handle_error;
465    }
466
467    extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
468    if (extensions == NULL) {
469	LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
470		   driverName, dlerror());
471	goto handle_error;
472    }
473
474    for (i = 0; extensions[i]; i++) {
475        if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
476	    extensions[i]->version >= __DRI_CORE_VERSION) {
477		screen->core = (const __DRIcoreExtension *) extensions[i];
478	}
479        if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0 &&
480	    extensions[i]->version >= __DRI_SWRAST_VERSION) {
481		screen->swrast = (const __DRIswrastExtension *) extensions[i];
482	}
483    }
484
485    if (screen->core == NULL || screen->swrast == NULL) {
486	LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n",
487		   driverName);
488	goto handle_error;
489    }
490
491    screen->driScreen =
492	(*screen->swrast->createNewScreen)(pScreen->myNum,
493					   loader_extensions,
494					   &driConfigs,
495					   screen);
496
497    if (screen->driScreen == NULL) {
498	LogMessage(X_ERROR,
499		   "AIGLX error: Calling driver entry point failed\n");
500	goto handle_error;
501    }
502
503    initializeExtensions(screen);
504
505    screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs,
506					       GLX_WINDOW_BIT |
507					       GLX_PIXMAP_BIT |
508					       GLX_PBUFFER_BIT);
509
510    __glXScreenInit(&screen->base, pScreen);
511
512    screen->base.GLXmajor = 1;
513    screen->base.GLXminor = 4;
514
515    LogMessage(X_INFO,
516	       "AIGLX: Loaded and initialized %s\n", filename);
517
518    return &screen->base;
519
520 handle_error:
521    if (screen->driver)
522        dlclose(screen->driver);
523
524    free(screen);
525
526    LogMessage(X_ERROR, "GLX: could not load software renderer\n");
527
528    return NULL;
529}
530
531_X_EXPORT __GLXprovider __glXDRISWRastProvider = {
532    __glXDRIscreenProbe,
533    "DRISWRAST",
534    NULL
535};
536