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