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
76struct __GLXDRIcontext {
77    __GLXcontext base;
78    __DRIcontext *driContext;
79};
80
81struct __GLXDRIdrawable {
82    __GLXdrawable base;
83    __DRIdrawable *driDrawable;
84    __GLXDRIscreen *screen;
85};
86
87/* white lie */
88extern glx_func_ptr glXGetProcAddressARB(const char *);
89
90static void
91__glXDRIdrawableDestroy(__GLXdrawable * drawable)
92{
93    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
94    const __DRIcoreExtension *core = private->screen->core;
95
96    (*core->destroyDrawable) (private->driDrawable);
97
98    __glXDrawableRelease(drawable);
99
100    free(private);
101}
102
103static GLboolean
104__glXDRIdrawableSwapBuffers(ClientPtr client, __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    free(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, read->driDrawable);
147}
148
149static int
150__glXDRIcontextLoseCurrent(__GLXcontext * baseContext)
151{
152    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
153    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
154
155    return (*screen->core->unbindContext) (context->driContext);
156}
157
158static int
159__glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc,
160                    unsigned long mask)
161{
162    __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
163    __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
164    __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
165
166    return (*screen->core->copyContext) (dst->driContext,
167                                         src->driContext, mask);
168}
169
170static int
171__glXDRIbindTexImage(__GLXcontext * baseContext,
172                     int buffer, __GLXdrawable * glxPixmap)
173{
174    __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
175    const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
176    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
177
178    if (texBuffer == NULL)
179        return Success;
180
181#if __DRI_TEX_BUFFER_VERSION >= 2
182    if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
183        (*texBuffer->setTexBuffer2) (context->driContext,
184                                     glxPixmap->target,
185                                     glxPixmap->format, drawable->driDrawable);
186    }
187    else
188#endif
189        texBuffer->setTexBuffer(context->driContext,
190                                glxPixmap->target, drawable->driDrawable);
191
192    return Success;
193}
194
195static int
196__glXDRIreleaseTexImage(__GLXcontext * baseContext,
197                        int buffer, __GLXdrawable * pixmap)
198{
199    /* FIXME: Just unbind the texture? */
200    return Success;
201}
202
203static __GLXcontext *
204__glXDRIscreenCreateContext(__GLXscreen * baseScreen,
205                            __GLXconfig * glxConfig,
206                            __GLXcontext * baseShareContext,
207                            unsigned num_attribs,
208                            const uint32_t *attribs,
209                            int *error)
210{
211    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
212    __GLXDRIcontext *context, *shareContext;
213    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
214    const __DRIconfig *driConfig = config ? config->driConfig : NULL;
215    const __DRIcoreExtension *core = screen->core;
216    __DRIcontext *driShare;
217
218    /* DRISWRAST won't support createContextAttribs, so these parameters will
219     * never be used.
220     */
221    (void) num_attribs;
222    (void) attribs;
223    (void) error;
224
225    shareContext = (__GLXDRIcontext *) baseShareContext;
226    if (shareContext)
227        driShare = shareContext->driContext;
228    else
229        driShare = NULL;
230
231    context = calloc(1, sizeof *context);
232    if (context == NULL)
233        return NULL;
234
235    context->base.config = glxConfig;
236    context->base.destroy = __glXDRIcontextDestroy;
237    context->base.makeCurrent = __glXDRIcontextMakeCurrent;
238    context->base.loseCurrent = __glXDRIcontextLoseCurrent;
239    context->base.copy = __glXDRIcontextCopy;
240    context->base.bindTexImage = __glXDRIbindTexImage;
241    context->base.releaseTexImage = __glXDRIreleaseTexImage;
242
243    context->driContext =
244        (*core->createNewContext) (screen->driScreen, driConfig, driShare,
245                                   context);
246
247    return &context->base;
248}
249
250static __GLXdrawable *
251__glXDRIscreenCreateDrawable(ClientPtr client,
252                             __GLXscreen * screen,
253                             DrawablePtr pDraw,
254                             XID drawId,
255                             int type, XID glxDrawId, __GLXconfig * glxConfig)
256{
257    __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
258    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
259    __GLXDRIdrawable *private;
260
261    private = calloc(1, sizeof *private);
262    if (private == NULL)
263        return NULL;
264
265    private->screen = driScreen;
266    if (!__glXDrawableInit(&private->base, screen,
267                           pDraw, type, glxDrawId, glxConfig)) {
268        free(private);
269        return NULL;
270    }
271
272    private->base.destroy = __glXDRIdrawableDestroy;
273    private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
274    private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
275
276    private->driDrawable =
277        (*driScreen->swrast->createNewDrawable) (driScreen->driScreen,
278                                                 config->driConfig, private);
279
280    return &private->base;
281}
282
283static void
284swrastGetDrawableInfo(__DRIdrawable * draw,
285                      int *x, int *y, int *w, int *h, void *loaderPrivate)
286{
287    __GLXDRIdrawable *drawable = loaderPrivate;
288    DrawablePtr pDraw = drawable->base.pDraw;
289
290    *x = pDraw->x;
291    *y = pDraw->y;
292    *w = pDraw->width;
293    *h = pDraw->height;
294}
295
296static void
297swrastPutImage(__DRIdrawable * draw, int op,
298               int x, int y, int w, int h, char *data, void *loaderPrivate)
299{
300    __GLXDRIdrawable *drawable = loaderPrivate;
301    DrawablePtr pDraw = drawable->base.pDraw;
302    GCPtr gc;
303    __GLXcontext *cx = lastGLContext;
304
305    if ((gc = GetScratchGC(pDraw->depth, pDraw->pScreen))) {
306        ValidateGC(pDraw, gc);
307        gc->ops->PutImage(pDraw, gc, pDraw->depth, x, y, w, h, 0, ZPixmap,
308                          data);
309        FreeScratchGC(gc);
310    }
311
312    if (cx != lastGLContext) {
313        lastGLContext = cx;
314        cx->makeCurrent(cx);
315    }
316}
317
318static void
319swrastGetImage(__DRIdrawable * draw,
320               int x, int y, int w, int h, char *data, void *loaderPrivate)
321{
322    __GLXDRIdrawable *drawable = loaderPrivate;
323    DrawablePtr pDraw = drawable->base.pDraw;
324    ScreenPtr pScreen = pDraw->pScreen;
325    __GLXcontext *cx = lastGLContext;
326
327    pScreen->SourceValidate(pDraw, x, y, w, h, IncludeInferiors);
328    pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data);
329    if (cx != lastGLContext) {
330        lastGLContext = cx;
331        cx->makeCurrent(cx);
332    }
333}
334
335static const __DRIswrastLoaderExtension swrastLoaderExtension = {
336    {__DRI_SWRAST_LOADER, 1},
337    swrastGetDrawableInfo,
338    swrastPutImage,
339    swrastGetImage
340};
341
342static const __DRIextension *loader_extensions[] = {
343    &swrastLoaderExtension.base,
344    NULL
345};
346
347static void
348initializeExtensions(__GLXscreen * screen)
349{
350    const __DRIextension **extensions;
351    __GLXDRIscreen *dri = (__GLXDRIscreen *)screen;
352    int i;
353
354    __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer");
355    __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_no_config_context");
356
357    if (dri->swrast->base.version >= 3) {
358        __glXEnableExtension(screen->glx_enable_bits,
359                             "GLX_ARB_create_context");
360        __glXEnableExtension(screen->glx_enable_bits,
361                             "GLX_ARB_create_context_no_error");
362        __glXEnableExtension(screen->glx_enable_bits,
363                             "GLX_ARB_create_context_profile");
364        __glXEnableExtension(screen->glx_enable_bits,
365                             "GLX_EXT_create_context_es_profile");
366        __glXEnableExtension(screen->glx_enable_bits,
367                             "GLX_EXT_create_context_es2_profile");
368    }
369
370    /* these are harmless to enable unconditionally */
371    __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_framebuffer_sRGB");
372    __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float");
373    __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float");
374    __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_texture_from_pixmap");
375
376    extensions = dri->core->getExtensions(dri->driScreen);
377
378    for (i = 0; extensions[i]; i++) {
379        if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
380            dri->copySubBuffer =
381                (const __DRIcopySubBufferExtension *) extensions[i];
382        }
383
384        if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
385            dri->texBuffer = (const __DRItexBufferExtension *) extensions[i];
386        }
387
388#ifdef __DRI2_FLUSH_CONTROL
389        if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
390            __glXEnableExtension(screen->glx_enable_bits,
391                                 "GLX_ARB_context_flush_control");
392        }
393#endif
394
395    }
396}
397
398static void
399__glXDRIscreenDestroy(__GLXscreen * baseScreen)
400{
401    int i;
402
403    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
404
405    (*screen->core->destroyScreen) (screen->driScreen);
406
407    dlclose(screen->driver);
408
409    __glXScreenDestroy(baseScreen);
410
411    if (screen->driConfigs) {
412        for (i = 0; screen->driConfigs[i] != NULL; i++)
413            free((__DRIconfig **) screen->driConfigs[i]);
414        free(screen->driConfigs);
415    }
416
417    free(screen);
418}
419
420static __GLXscreen *
421__glXDRIscreenProbe(ScreenPtr pScreen)
422{
423    const char *driverName = "swrast";
424    __GLXDRIscreen *screen;
425
426    screen = calloc(1, sizeof *screen);
427    if (screen == NULL)
428        return NULL;
429
430    screen->base.destroy = __glXDRIscreenDestroy;
431    screen->base.createContext = __glXDRIscreenCreateContext;
432    screen->base.createDrawable = __glXDRIscreenCreateDrawable;
433    screen->base.swapInterval = NULL;
434    screen->base.pScreen = pScreen;
435
436    __glXInitExtensionEnableBits(screen->base.glx_enable_bits);
437
438    screen->driver = glxProbeDriver(driverName,
439                                    (void **) &screen->core,
440                                    __DRI_CORE, 1,
441                                    (void **) &screen->swrast,
442                                    __DRI_SWRAST, 1);
443    if (screen->driver == NULL) {
444        goto handle_error;
445    }
446
447    screen->driScreen =
448        (*screen->swrast->createNewScreen) (pScreen->myNum,
449                                            loader_extensions,
450                                            &screen->driConfigs, screen);
451
452    if (screen->driScreen == NULL) {
453        LogMessage(X_ERROR, "IGLX error: Calling driver entry point failed\n");
454        goto handle_error;
455    }
456
457    initializeExtensions(&screen->base);
458
459    screen->base.fbconfigs = glxConvertConfigs(screen->core,
460                                               screen->driConfigs);
461
462#if !defined(XQUARTZ) && !defined(WIN32)
463    screen->base.glvnd = strdup("mesa");
464#endif
465    __glXScreenInit(&screen->base, pScreen);
466
467    __glXsetGetProcAddress(glXGetProcAddressARB);
468
469    LogMessage(X_INFO, "IGLX: Loaded and initialized %s\n", driverName);
470
471    return &screen->base;
472
473 handle_error:
474    if (screen->driver)
475        dlclose(screen->driver);
476
477    free(screen);
478
479    LogMessage(X_ERROR, "GLX: could not load software renderer\n");
480
481    return NULL;
482}
483
484__GLXprovider __glXDRISWRastProvider = {
485    __glXDRIscreenProbe,
486    "DRISWRAST",
487    NULL
488};
489