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 
60 typedef struct __GLXDRIscreen __GLXDRIscreen;
61 typedef struct __GLXDRIcontext __GLXDRIcontext;
62 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
63 
64 struct __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 
76 struct __GLXDRIcontext {
77     __GLXcontext base;
78     __DRIcontext *driContext;
79 };
80 
81 struct __GLXDRIdrawable {
82     __GLXdrawable base;
83     __DRIdrawable *driDrawable;
84     __GLXDRIscreen *screen;
85 };
86 
87 /* white lie */
88 extern glx_func_ptr glXGetProcAddressARB(const char *);
89 
90 static void
__glXDRIdrawableDestroy(__GLXdrawable * drawable)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 
103 static GLboolean
__glXDRIdrawableSwapBuffers(ClientPtr client,__GLXdrawable * drawable)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 
114 static void
__glXDRIdrawableCopySubBuffer(__GLXdrawable * basePrivate,int x,int y,int w,int h)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 
126 static void
__glXDRIcontextDestroy(__GLXcontext * baseContext)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 
137 static int
__glXDRIcontextMakeCurrent(__GLXcontext * baseContext)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 
149 static int
__glXDRIcontextLoseCurrent(__GLXcontext * baseContext)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 
158 static int
__glXDRIcontextCopy(__GLXcontext * baseDst,__GLXcontext * baseSrc,unsigned long mask)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 
170 static int
__glXDRIbindTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * glxPixmap)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 
195 static int
__glXDRIreleaseTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * pixmap)196 __glXDRIreleaseTexImage(__GLXcontext * baseContext,
197                         int buffer, __GLXdrawable * pixmap)
198 {
199     /* FIXME: Just unbind the texture? */
200     return Success;
201 }
202 
203 static __GLXcontext *
__glXDRIscreenCreateContext(__GLXscreen * baseScreen,__GLXconfig * glxConfig,__GLXcontext * baseShareContext,unsigned num_attribs,const uint32_t * attribs,int * error)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 
250 static __GLXdrawable *
__glXDRIscreenCreateDrawable(ClientPtr client,__GLXscreen * screen,DrawablePtr pDraw,XID drawId,int type,XID glxDrawId,__GLXconfig * glxConfig)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 
283 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)284 swrastGetDrawableInfo(__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 
296 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)297 swrastPutImage(__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 
318 static void
swrastGetImage(__DRIdrawable * draw,int x,int y,int w,int h,char * data,void * loaderPrivate)319 swrastGetImage(__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 
335 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
336     {__DRI_SWRAST_LOADER, 1},
337     swrastGetDrawableInfo,
338     swrastPutImage,
339     swrastGetImage
340 };
341 
342 static const __DRIextension *loader_extensions[] = {
343     &swrastLoaderExtension.base,
344     NULL
345 };
346 
347 static void
initializeExtensions(__GLXscreen * screen)348 initializeExtensions(__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 
398 static void
__glXDRIscreenDestroy(__GLXscreen * baseScreen)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 
420 static __GLXscreen *
__glXDRIscreenProbe(ScreenPtr pScreen)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