Free the debug info when making a critical section global.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29
30 #include "wgl.h"
31 #include "opengl_ext.h"
32 #include "wine/debug.h"
33 #include "wine/port.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
36
37 /* x11drv GDI escapes */
38 #define X11DRV_ESCAPE 6789
39 enum x11drv_escape_codes
40 {
41     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
42     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
43     X11DRV_GET_FONT,      /* get current X font for a DC */
44 };
45
46 void (*wine_tsx11_lock_ptr)(void) = NULL;
47 void (*wine_tsx11_unlock_ptr)(void) = NULL;
48
49 static GLXContext default_cx = NULL;
50 static Display *default_display;  /* display to use for default context */
51
52 static void *(*p_glXGetProcAddressARB)(const GLubyte *);
53
54 typedef struct wine_glcontext {
55   HDC hdc;
56   Display *display;
57   GLXContext ctx;
58   XVisualInfo *vis;
59   struct wine_glcontext *next;
60   struct wine_glcontext *prev;
61 } Wine_GLContext;
62 static Wine_GLContext *context_list;
63
64 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
65 {
66     Wine_GLContext *ret;
67     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
68     return ret;
69 }
70
71 static inline void free_context(Wine_GLContext *context)
72 {
73   if (context->next != NULL) context->next->prev = context->prev;
74   if (context->prev != NULL) context->prev->next = context->next;
75   else context_list = context->next;
76
77   HeapFree(GetProcessHeap(), 0, context);
78 }
79
80 static inline Wine_GLContext *alloc_context(void)
81 {
82   Wine_GLContext *ret;
83
84   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
85   {
86       ret->next = context_list;
87       if (context_list) context_list->prev = ret;
88       context_list = ret;
89   }
90   return ret;
91 }
92
93 inline static BOOL is_valid_context( Wine_GLContext *ctx )
94 {
95     Wine_GLContext *ptr;
96     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
97     return (ptr != NULL);
98 }
99
100 /* retrieve the X display to use on a given DC */
101 inline static Display *get_display( HDC hdc )
102 {
103     Display *display;
104     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
105
106     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
107                     sizeof(display), (LPSTR)&display )) display = NULL;
108     return display;
109 }
110
111
112 /* retrieve the X drawable to use on a given DC */
113 inline static Drawable get_drawable( HDC hdc )
114 {
115     Drawable drawable;
116     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
117
118     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
119                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
120     return drawable;
121 }
122
123
124 /* retrieve the X drawable to use on a given DC */
125 inline static Font get_font( HDC hdc )
126 {
127     Font font;
128     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
129
130     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
131                     sizeof(font), (LPSTR)&font )) font = 0;
132     return font;
133 }
134
135
136 /***********************************************************************
137  *              wglCreateContext (OPENGL32.@)
138  */
139 HGLRC WINAPI wglCreateContext(HDC hdc)
140 {
141   XVisualInfo *vis;
142   Wine_GLContext *ret;
143   int num;
144   XVisualInfo template;
145   Display *display = get_display( hdc );
146
147   TRACE("(%p)\n", hdc);
148
149   /* First, get the visual in use by the X11DRV */
150   if (!display) return 0;
151   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
152   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
153
154   if (vis == NULL) {
155     ERR("NULL visual !!!\n");
156     /* Need to set errors here */
157     return NULL;
158   }
159
160   /* The context will be allocated in the wglMakeCurrent call */
161   ENTER_GL();
162   ret = alloc_context();
163   LEAVE_GL();
164   ret->hdc = hdc;
165   ret->display = display;
166   ret->vis = vis;
167
168   TRACE(" creating context %p (GL context creation delayed)\n", ret);
169   return (HGLRC) ret;
170 }
171
172 /***********************************************************************
173  *              wglCreateLayerContext (OPENGL32.@)
174  */
175 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
176                                    int iLayerPlane) {
177   TRACE("(%p,%d)\n", hdc, iLayerPlane);
178
179   if (iLayerPlane == 0) {
180       return wglCreateContext(hdc);
181   }
182   FIXME(" no handler for layer %d\n", iLayerPlane);
183
184   return NULL;
185 }
186
187 /***********************************************************************
188  *              wglCopyContext (OPENGL32.@)
189  */
190 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
191                            HGLRC hglrcDst,
192                            UINT mask) {
193   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
194
195   return FALSE;
196 }
197
198 /***********************************************************************
199  *              wglDeleteContext (OPENGL32.@)
200  */
201 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
202 {
203   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
204   BOOL ret = TRUE;
205
206   TRACE("(%p)\n", hglrc);
207
208   ENTER_GL();
209   /* A game (Half Life not to name it) deletes twice the same context,
210    * so make sure it is valid first */
211   if (is_valid_context( ctx ))
212   {
213       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
214       free_context(ctx);
215   }
216   else
217   {
218     WARN("Error deleting context !\n");
219     SetLastError(ERROR_INVALID_HANDLE);
220     ret = FALSE;
221   }
222   LEAVE_GL();
223
224   return ret;
225 }
226
227 /***********************************************************************
228  *              wglDescribeLayerPlane (OPENGL32.@)
229  */
230 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
231                                   int iPixelFormat,
232                                   int iLayerPlane,
233                                   UINT nBytes,
234                                   LPLAYERPLANEDESCRIPTOR plpd) {
235   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
236
237   return FALSE;
238 }
239
240 /***********************************************************************
241  *              wglGetCurrentContext (OPENGL32.@)
242  */
243 HGLRC WINAPI wglGetCurrentContext(void) {
244   GLXContext gl_ctx;
245   Wine_GLContext *ret;
246
247   TRACE("()\n");
248
249   ENTER_GL();
250   gl_ctx = glXGetCurrentContext();
251   ret = get_context_from_GLXContext(gl_ctx);
252   LEAVE_GL();
253
254   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
255
256   return ret;
257 }
258
259 /***********************************************************************
260  *              wglGetCurrentDC (OPENGL32.@)
261  */
262 HDC WINAPI wglGetCurrentDC(void) {
263   GLXContext gl_ctx;
264   Wine_GLContext *ret;
265
266   TRACE("()\n");
267
268   ENTER_GL();
269   gl_ctx = glXGetCurrentContext();
270   ret = get_context_from_GLXContext(gl_ctx);
271   LEAVE_GL();
272
273   if (ret) {
274     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
275     return ret->hdc;
276   } else {
277     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
278     return 0;
279   }
280 }
281
282 /***********************************************************************
283  *              wglGetLayerPaletteEntries (OPENGL32.@)
284  */
285 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
286                                      int iLayerPlane,
287                                      int iStart,
288                                      int cEntries,
289                                      const COLORREF *pcr) {
290   FIXME("(): stub !\n");
291
292   return 0;
293 }
294
295 /***********************************************************************
296  *              wglGetProcAddress (OPENGL32.@)
297  */
298 static int compar(const void *elt_a, const void *elt_b) {
299   return strcmp(((OpenGL_extension *) elt_a)->name,
300                 ((OpenGL_extension *) elt_b)->name);
301 }
302
303 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
304   void *local_func;
305   static HMODULE hm = 0;
306   OpenGL_extension  ext;
307   OpenGL_extension *ext_ret;
308
309
310   TRACE("(%s)\n", lpszProc);
311
312   if (hm == 0)
313       hm = GetModuleHandleA("opengl32");
314
315   /* First, look if it's not already defined in the 'standard' OpenGL functions */
316   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
317     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
318     return local_func;
319   }
320
321   if (p_glXGetProcAddressARB == NULL) {
322     ERR("Warning : dynamic GL extension loading not supported by native GL library.");
323     return NULL;
324   }
325   
326   /* After that, search in the thunks to find the real name of the extension */
327   ext.name = (char *) lpszProc;
328   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
329                                          extension_registry_size, sizeof(OpenGL_extension), compar);
330
331   if (ext_ret == NULL) {
332     /* Some sanity checks :-) */
333     ENTER_GL();
334     local_func = p_glXGetProcAddressARB(lpszProc);
335     LEAVE_GL();
336     if (local_func != NULL) {
337       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
338       return NULL;
339     }
340
341     WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
342     return NULL;
343   } else {
344     ENTER_GL();
345     local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
346     LEAVE_GL();
347     
348     /* After that, look at the extensions defined in the Linux OpenGL library */
349     if (local_func == NULL) {
350       char buf[256];
351       void *ret = NULL;
352
353       /* Remove the 3 last letters (EXT, ARB, ...).
354
355          I know that some extensions have more than 3 letters (MESA, NV,
356          INTEL, ...), but this is only a stop-gap measure to fix buggy
357          OpenGL drivers (moreover, it is only useful for old 1.0 apps
358          that query the glBindTextureEXT extension).
359       */
360       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
361       buf[strlen(ext_ret->glx_name) - 3] = '\0';
362       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
363
364       ret = GetProcAddress(hm, buf);
365       if (ret != NULL) {
366         TRACE(" found function in main OpenGL library (%p) !\n", ret);
367       } else {
368         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
369       }
370
371       return ret;
372     } else {
373       TRACE(" returning function  (%p)\n", ext_ret->func);
374       *(ext_ret->func_ptr) = local_func;
375
376       return ext_ret->func;
377     }
378   }
379 }
380
381 /***********************************************************************
382  *              wglMakeCurrent (OPENGL32.@)
383  */
384 BOOL WINAPI wglMakeCurrent(HDC hdc,
385                            HGLRC hglrc) {
386   BOOL ret;
387
388   TRACE("(%p,%p)\n", hdc, hglrc);
389
390   ENTER_GL();
391   if (hglrc == NULL) {
392       ret = glXMakeCurrent(default_display, None, NULL);
393   } else {
394       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
395       Drawable drawable = get_drawable( hdc );
396
397       if (ctx->ctx == NULL) {
398         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
399         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
400       }
401       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
402   }
403   LEAVE_GL();
404   TRACE(" returning %s\n", (ret ? "True" : "False"));
405   return ret;
406 }
407
408 /***********************************************************************
409  *              wglRealizeLayerPalette (OPENGL32.@)
410  */
411 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
412                                    int iLayerPlane,
413                                    BOOL bRealize) {
414   FIXME("()\n");
415
416   return FALSE;
417 }
418
419 /***********************************************************************
420  *              wglSetLayerPaletteEntries (OPENGL32.@)
421  */
422 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
423                                      int iLayerPlane,
424                                      int iStart,
425                                      int cEntries,
426                                      const COLORREF *pcr) {
427   FIXME("(): stub !\n");
428
429   return 0;
430 }
431
432 /***********************************************************************
433  *              wglShareLists (OPENGL32.@)
434  */
435 BOOL WINAPI wglShareLists(HGLRC hglrc1,
436                           HGLRC hglrc2) {
437   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
438   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
439
440   TRACE("(%p, %p)\n", org, dest);
441
442   if (dest->ctx != NULL) {
443     ERR("Could not share display lists, context already created !\n");
444     return FALSE;
445   } else {
446     if (org->ctx == NULL) {
447       ENTER_GL();
448       org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
449       LEAVE_GL();
450       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
451     }
452
453     ENTER_GL();
454     /* Create the destination context with display lists shared */
455     dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
456     LEAVE_GL();
457     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
458   }
459
460   return TRUE;
461 }
462
463 /***********************************************************************
464  *              wglSwapLayerBuffers (OPENGL32.@)
465  */
466 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
467                                 UINT fuPlanes) {
468   TRACE("(%p, %08x)\n", hdc, fuPlanes);
469
470   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
471     if (!SwapBuffers(hdc)) return FALSE;
472     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
473   }
474
475   if (fuPlanes) {
476     WARN("Following layers unhandled : %08x\n", fuPlanes);
477   }
478
479   return TRUE;
480 }
481
482 /***********************************************************************
483  *              wglUseFontBitmapsA (OPENGL32.@)
484  */
485 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
486                                DWORD first,
487                                DWORD count,
488                                DWORD listBase)
489 {
490   Font fid = get_font( hdc );
491
492   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
493
494   if (fid == 0) {
495     /* We are running using client-side rendering fonts... */
496     GLYPHMETRICS gm;
497     static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
498     int glyph;
499     int size = 0;
500     void *bitmap = NULL, *gl_bitmap = NULL;
501     int org_alignment;
502
503     ENTER_GL();
504     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
505     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
506     LEAVE_GL();
507
508     for (glyph = first; glyph < first + count; glyph++) {
509       int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
510       int height, width_int;
511
512       if (needed_size == GDI_ERROR) goto error;
513       if (needed_size > size) {
514         size = needed_size;
515         if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
516         if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
517         bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
518         gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
519       }
520       if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
521       if (TRACE_ON(opengl)) {
522         unsigned int height, width, bitmask;
523         unsigned char *bitmap_ = (unsigned char *) bitmap;
524
525         DPRINTF("Glyph : %d\n", glyph);
526         DPRINTF("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
527         DPRINTF("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
528         DPRINTF("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
529         DPRINTF("  - size : %d\n", needed_size);
530         DPRINTF("  - bitmap : \n");
531         for (height = 0; height < gm.gmBlackBoxY; height++) {
532           DPRINTF("      ");
533           for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
534             if (bitmask == 0) {
535               bitmap_ += 1;
536               bitmask = 0x80;
537             }
538             if (*bitmap_ & bitmask)
539               DPRINTF("*");
540             else
541               DPRINTF(" ");
542           }
543           bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
544           DPRINTF("\n");
545         }
546       }
547
548       /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
549          As Wine does not seem to support the MAT2 field, I need to do it myself.... */
550       width_int = (gm.gmBlackBoxX + 31) / 32;
551       for (height = 0; height < gm.gmBlackBoxY; height++) {
552         int width;
553         for (width = 0; width < width_int; width++) {
554           ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
555             ((int *) bitmap)[height * width_int + width];
556         }
557       }
558
559       ENTER_GL();
560       glNewList(listBase++, GL_COMPILE);
561       glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
562       glEndList();
563       LEAVE_GL();
564     }
565
566     ENTER_GL();
567     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
568     LEAVE_GL();
569
570     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
571     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
572     return TRUE;
573
574   error:
575     ENTER_GL();
576     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
577     LEAVE_GL();
578
579     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
580     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
581     return FALSE;
582   }
583
584   ENTER_GL();
585   /* I assume that the glyphs are at the same position for X and for Windows */
586   glXUseXFont(fid, first, count, listBase);
587   LEAVE_GL();
588   return TRUE;
589 }
590
591 /***********************************************************************
592  *              wglUseFontOutlinesA (OPENGL32.@)
593  */
594 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
595                                 DWORD first,
596                                 DWORD count,
597                                 DWORD listBase,
598                                 FLOAT deviation,
599                                 FLOAT extrusion,
600                                 int format,
601                                 LPGLYPHMETRICSFLOAT lpgmf) {
602   FIXME("(): stub !\n");
603
604   return FALSE;
605 }
606
607 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
608    include all dependencies
609 */
610 #ifndef SONAME_LIBGL
611 #define SONAME_LIBGL "libGL.so"
612 #endif
613
614 /* This is for brain-dead applications that use OpenGL functions before even
615    creating a rendering context.... */
616 static BOOL process_attach(void)
617 {
618   XWindowAttributes win_attr;
619   Visual *rootVisual;
620   int num;
621   XVisualInfo template;
622   HDC hdc;
623   XVisualInfo *vis = NULL;
624   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
625   HMODULE mod = GetModuleHandleA( "x11drv.dll" );
626   void *opengl_handle;
627   const char *extensions = NULL;
628   
629   if (!root || !mod)
630   {
631       ERR("X11DRV not loaded. Cannot create default context.\n");
632       return FALSE;
633   }
634
635   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
636   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
637
638   hdc = GetDC(0);
639   default_display = get_display( hdc );
640   ReleaseDC( 0, hdc );
641   if (!default_display)
642   {
643       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
644       return FALSE;
645   }
646
647   ENTER_GL();
648
649   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
650      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
651      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
652      with mismatched visuals.  Note that the Root Window visual may not be double
653      buffered, so apps actually attempting to render this way may flicker */
654   if (XGetWindowAttributes( default_display, root, &win_attr ))
655   {
656     rootVisual = win_attr.visual;
657   }
658   else
659   {
660     /* Get the default visual, since we can't seem to get the attributes from the
661        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
662     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
663   }
664
665   template.visualid = XVisualIDFromVisual(rootVisual);
666   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
667   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
668   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
669   extensions = glXQueryExtensionsString(default_display, DefaultScreen(default_display));
670   XFree(vis);
671   LEAVE_GL();
672
673   if ((extensions != NULL) && (strstr(extensions, "GLX_ARB_get_proc_address"))) {
674     opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
675     if (opengl_handle != NULL) {
676       p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
677       wine_dlclose(opengl_handle, NULL, 0);
678     }
679   }
680   
681   if (default_cx == NULL) {
682     ERR("Could not create default context.\n");
683   }
684   return TRUE;
685 }
686
687 /**********************************************************************/
688
689 /* Some WGL extensions... */
690 static const char *WGL_extensions = "WGL_ARB_extensions_string WGL_EXT_extensions_string";
691
692 /**********************************************************************/
693
694 const char * WINAPI wglGetExtensionsStringEXT(void) {
695     TRACE("() returning \"%s\"\n", WGL_extensions);
696
697     return WGL_extensions;
698 }
699
700 /**********************************************************************/
701
702 static void process_detach(void)
703 {
704   glXDestroyContext(default_display, default_cx);
705 }
706
707 /***********************************************************************
708  *              wglGetExtensionsStringARB(OPENGL32.@)
709  */
710 const char * WINAPI wglGetExtensionsStringARB(HDC hdc) {
711
712   return wglGetExtensionsStringEXT();
713 }
714
715
716 /***********************************************************************
717  *           OpenGL initialisation routine
718  */
719 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
720 {
721     switch(reason)
722     {
723     case DLL_PROCESS_ATTACH:
724         DisableThreadLibraryCalls(hinst);
725         return process_attach();
726     case DLL_PROCESS_DETACH:
727         process_detach();
728         break;
729     }
730     return TRUE;
731 }