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 "glapitable.h"
52#include "glapi.h"
53#include "glthread.h"
54#include "dispatch.h"
55#include "extension_string.h"
56
57/* RTLD_LOCAL is not defined on Cygwin */
58#ifdef __CYGWIN__
59#ifndef RTLD_LOCAL
60#define RTLD_LOCAL 0
61#endif
62#endif
63
64typedef struct __GLXDRIscreen   __GLXDRIscreen;
65typedef struct __GLXDRIcontext  __GLXDRIcontext;
66typedef struct __GLXDRIdrawable __GLXDRIdrawable;
67
68struct __GLXDRIscreen {
69    __GLXscreen		 base;
70    __DRIscreen		*driScreen;
71    void		*driver;
72
73    const __DRIcoreExtension *core;
74    const __DRIswrastExtension *swrast;
75    const __DRIcopySubBufferExtension *copySubBuffer;
76    const __DRItexBufferExtension *texBuffer;
77};
78
79struct __GLXDRIcontext {
80    __GLXcontext	 base;
81    __DRIcontext	*driContext;
82};
83
84struct __GLXDRIdrawable {
85    __GLXdrawable	 base;
86    __DRIdrawable	*driDrawable;
87    __GLXDRIscreen	*screen;
88
89    GCPtr gc;		/* scratch GC for span drawing */
90    GCPtr swapgc;	/* GC for swapping the color buffers */
91};
92
93static void
94__glXDRIdrawableDestroy(__GLXdrawable *drawable)
95{
96    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
97    const __DRIcoreExtension *core = private->screen->core;
98
99    (*core->destroyDrawable)(private->driDrawable);
100
101    FreeGC(private->gc, (GContext)0);
102    FreeGC(private->swapgc, (GContext)0);
103
104    __glXDrawableRelease(drawable);
105
106    free(private);
107}
108
109static GLboolean
110__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
111{
112    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
113    const __DRIcoreExtension *core = private->screen->core;
114
115    (*core->swapBuffers)(private->driDrawable);
116
117    return TRUE;
118}
119
120static void
121__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
122			       int x, int y, int w, int h)
123{
124    __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
125    const __DRIcopySubBufferExtension *copySubBuffer =
126	    private->screen->copySubBuffer;
127
128    if (copySubBuffer)
129	(*copySubBuffer->copySubBuffer)(private->driDrawable, x, y, w, h);
130}
131
132static void
133__glXDRIcontextDestroy(__GLXcontext *baseContext)
134{
135    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
136    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
137
138    (*screen->core->destroyContext)(context->driContext);
139    __glXContextDestroy(&context->base);
140    free(context);
141}
142
143static int
144__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
145{
146    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
147    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
148    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
149    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
150
151    return (*screen->core->bindContext)(context->driContext,
152					draw->driDrawable,
153					read->driDrawable);
154}
155
156static int
157__glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
158{
159    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
160    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
161
162    return (*screen->core->unbindContext)(context->driContext);
163}
164
165static int
166__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
167		    unsigned long mask)
168{
169    __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
170    __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
171    __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
172
173    return (*screen->core->copyContext)(dst->driContext,
174					src->driContext, mask);
175}
176
177static int
178__glXDRIcontextForceCurrent(__GLXcontext *baseContext)
179{
180    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
181    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
182    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
183    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
184
185    return (*screen->core->bindContext)(context->driContext,
186					draw->driDrawable,
187					read->driDrawable);
188}
189
190#ifdef __DRI_TEX_BUFFER
191
192static int
193__glXDRIbindTexImage(__GLXcontext *baseContext,
194		     int buffer,
195		     __GLXdrawable *glxPixmap)
196{
197    __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
198    const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
199    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
200
201    if (texBuffer == NULL)
202        return Success;
203
204#if __DRI_TEX_BUFFER_VERSION >= 2
205    if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
206	(*texBuffer->setTexBuffer2)(context->driContext,
207				    glxPixmap->target,
208				    glxPixmap->format,
209				    drawable->driDrawable);
210    } else
211#endif
212    texBuffer->setTexBuffer(context->driContext,
213			    glxPixmap->target,
214			    drawable->driDrawable);
215
216    return Success;
217}
218
219static int
220__glXDRIreleaseTexImage(__GLXcontext *baseContext,
221			int buffer,
222			__GLXdrawable *pixmap)
223{
224    /* FIXME: Just unbind the texture? */
225    return Success;
226}
227
228#else
229
230static int
231__glXDRIbindTexImage(__GLXcontext *baseContext,
232		     int buffer,
233		     __GLXdrawable *glxPixmap)
234{
235    return Success;
236}
237
238static int
239__glXDRIreleaseTexImage(__GLXcontext *baseContext,
240			int buffer,
241			__GLXdrawable *pixmap)
242{
243    return Success;
244}
245
246#endif
247
248static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
249    __glXDRIbindTexImage,
250    __glXDRIreleaseTexImage
251};
252
253static void
254__glXDRIscreenDestroy(__GLXscreen *baseScreen)
255{
256    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
257
258    (*screen->core->destroyScreen)(screen->driScreen);
259
260    dlclose(screen->driver);
261
262    __glXScreenDestroy(baseScreen);
263
264    free(screen);
265}
266
267static __GLXcontext *
268__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
269			    __GLXconfig *glxConfig,
270			    __GLXcontext *baseShareContext)
271{
272    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
273    __GLXDRIcontext *context, *shareContext;
274    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
275    const __DRIcoreExtension *core = screen->core;
276    __DRIcontext *driShare;
277
278    shareContext = (__GLXDRIcontext *) baseShareContext;
279    if (shareContext)
280	driShare = shareContext->driContext;
281    else
282	driShare = NULL;
283
284    context = calloc(1, sizeof *context);
285    if (context == NULL)
286	return NULL;
287
288    context->base.destroy           = __glXDRIcontextDestroy;
289    context->base.makeCurrent       = __glXDRIcontextMakeCurrent;
290    context->base.loseCurrent       = __glXDRIcontextLoseCurrent;
291    context->base.copy              = __glXDRIcontextCopy;
292    context->base.forceCurrent      = __glXDRIcontextForceCurrent;
293    context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
294
295    context->driContext =
296	(*core->createNewContext)(screen->driScreen,
297				  config->driConfig, driShare, context);
298
299    return &context->base;
300}
301
302static __GLXdrawable *
303__glXDRIscreenCreateDrawable(ClientPtr client,
304			     __GLXscreen *screen,
305			     DrawablePtr pDraw,
306			     XID drawId,
307			     int type,
308			     XID glxDrawId,
309			     __GLXconfig *glxConfig)
310{
311    XID gcvals[2];
312    int status;
313    __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
314    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
315    __GLXDRIdrawable *private;
316
317    private = calloc(1, sizeof *private);
318    if (private == NULL)
319	return NULL;
320
321    private->screen = driScreen;
322    if (!__glXDrawableInit(&private->base, screen,
323			   pDraw, type, glxDrawId, glxConfig)) {
324        free(private);
325	return NULL;
326    }
327
328    private->base.destroy       = __glXDRIdrawableDestroy;
329    private->base.swapBuffers   = __glXDRIdrawableSwapBuffers;
330    private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
331
332    gcvals[0] = GXcopy;
333    private->gc = CreateGC(pDraw, GCFunction, gcvals, &status, (XID)0, serverClient);
334    gcvals[1] = FALSE;
335    private->swapgc = CreateGC(pDraw, GCFunction | GCGraphicsExposures, gcvals, &status, (XID)0, serverClient);
336
337    private->driDrawable =
338	(*driScreen->swrast->createNewDrawable)(driScreen->driScreen,
339						config->driConfig,
340						private);
341
342    return &private->base;
343}
344
345static void
346swrastGetDrawableInfo(__DRIdrawable *draw,
347		      int *x, int *y, int *w, int *h,
348		      void *loaderPrivate)
349{
350    __GLXDRIdrawable *drawable = loaderPrivate;
351    DrawablePtr pDraw = drawable->base.pDraw;
352
353    *x = pDraw->x;
354    *y = pDraw->x;
355    *w = pDraw->width;
356    *h = pDraw->height;
357}
358
359static void
360swrastPutImage(__DRIdrawable *draw, int op,
361	     int x, int y, int w, int h, char *data,
362	     void *loaderPrivate)
363{
364    __GLXDRIdrawable *drawable = loaderPrivate;
365    DrawablePtr pDraw = drawable->base.pDraw;
366    GCPtr gc;
367
368    switch (op) {
369    case __DRI_SWRAST_IMAGE_OP_DRAW:
370	gc = drawable->gc;
371	break;
372    case __DRI_SWRAST_IMAGE_OP_SWAP:
373	gc = drawable->swapgc;
374	break;
375    default:
376	return;
377    }
378
379    ValidateGC(pDraw, gc);
380
381    gc->ops->PutImage(pDraw, gc, pDraw->depth,
382		      x, y, w, h, 0, ZPixmap, data);
383}
384
385static void
386swrastGetImage(__DRIdrawable *draw,
387	     int x, int y, int w, int h, char *data,
388	     void *loaderPrivate)
389{
390    __GLXDRIdrawable *drawable = loaderPrivate;
391    DrawablePtr pDraw = drawable->base.pDraw;
392    ScreenPtr pScreen = pDraw->pScreen;
393
394    pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data);
395}
396
397static const __DRIswrastLoaderExtension swrastLoaderExtension = {
398    { __DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION },
399    swrastGetDrawableInfo,
400    swrastPutImage,
401    swrastGetImage
402};
403
404static const __DRIextension *loader_extensions[] = {
405    &systemTimeExtension.base,
406    &swrastLoaderExtension.base,
407    NULL
408};
409
410static void
411initializeExtensions(__GLXDRIscreen *screen)
412{
413    const __DRIextension **extensions;
414    int i;
415
416    extensions = screen->core->getExtensions(screen->driScreen);
417
418    for (i = 0; extensions[i]; i++) {
419#ifdef __DRI_COPY_SUB_BUFFER
420	if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
421	    screen->copySubBuffer =
422		(const __DRIcopySubBufferExtension *) extensions[i];
423	    /* GLX_MESA_copy_sub_buffer is always enabled. */
424	}
425#endif
426
427#ifdef __DRI_TEX_BUFFER
428	if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
429	    screen->texBuffer =
430		(const __DRItexBufferExtension *) extensions[i];
431	    /* GLX_EXT_texture_from_pixmap is always enabled. */
432	}
433#endif
434	/* Ignore unknown extensions */
435    }
436}
437
438static const char dri_driver_path[] = DRI_DRIVER_PATH;
439
440static __GLXscreen *
441__glXDRIscreenProbe(ScreenPtr pScreen)
442{
443    const char *driverName = "swrast";
444    __GLXDRIscreen *screen;
445    char filename[128];
446    const __DRIextension **extensions;
447    const __DRIconfig **driConfigs;
448    int i;
449
450    screen = calloc(1, sizeof *screen);
451    if (screen == NULL)
452	return NULL;
453
454    screen->base.destroy        = __glXDRIscreenDestroy;
455    screen->base.createContext  = __glXDRIscreenCreateContext;
456    screen->base.createDrawable = __glXDRIscreenCreateDrawable;
457    screen->base.swapInterval   = NULL;
458    screen->base.pScreen       = pScreen;
459
460    snprintf(filename, sizeof filename,
461	     "%s/%s_dri.so", dri_driver_path, driverName);
462
463    screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
464    if (screen->driver == NULL) {
465	LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
466		   filename, dlerror());
467        goto handle_error;
468    }
469
470    extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
471    if (extensions == NULL) {
472	LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
473		   driverName, dlerror());
474	goto handle_error;
475    }
476
477    for (i = 0; extensions[i]; i++) {
478        if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
479	    extensions[i]->version >= __DRI_CORE_VERSION) {
480		screen->core = (const __DRIcoreExtension *) extensions[i];
481	}
482        if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0 &&
483	    extensions[i]->version >= __DRI_SWRAST_VERSION) {
484		screen->swrast = (const __DRIswrastExtension *) extensions[i];
485	}
486    }
487
488    if (screen->core == NULL || screen->swrast == NULL) {
489	LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n",
490		   driverName);
491	goto handle_error;
492    }
493
494    screen->driScreen =
495	(*screen->swrast->createNewScreen)(pScreen->myNum,
496					   loader_extensions,
497					   &driConfigs,
498					   screen);
499
500    if (screen->driScreen == NULL) {
501	LogMessage(X_ERROR,
502		   "AIGLX error: Calling driver entry point failed\n");
503	goto handle_error;
504    }
505
506    initializeExtensions(screen);
507
508    screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs,
509					       GLX_WINDOW_BIT |
510					       GLX_PIXMAP_BIT |
511					       GLX_PBUFFER_BIT);
512
513    __glXScreenInit(&screen->base, pScreen);
514
515    screen->base.GLXmajor = 1;
516    screen->base.GLXminor = 4;
517
518    LogMessage(X_INFO,
519	       "AIGLX: Loaded and initialized %s\n", filename);
520
521    return &screen->base;
522
523 handle_error:
524    if (screen->driver)
525        dlclose(screen->driver);
526
527    free(screen);
528
529    LogMessage(X_ERROR, "GLX: could not load software renderer\n");
530
531    return NULL;
532}
533
534_X_EXPORT __GLXprovider __glXDRISWRastProvider = {
535    __glXDRIscreenProbe,
536    "DRISWRAST",
537    NULL
538};
539