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