advpack: Forward GetVersionFromFileA/ExA to their Unicode counterparts.
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  * Copyright (c) 2005 Raphael Junqueira
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
36
37 #include "wgl_ext.h"
38 #include "opengl_ext.h"
39 #ifdef HAVE_GL_GLU_H
40 #undef far
41 #undef near
42 #include <GL/glu.h>
43 #endif
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
48
49 /** global glx object */
50 wine_glx_t wine_glx;
51
52 /* x11drv GDI escapes */
53 #define X11DRV_ESCAPE 6789
54 enum x11drv_escape_codes
55 {
56     X11DRV_GET_DISPLAY,         /* get X11 display for a DC */
57     X11DRV_GET_DRAWABLE,        /* get current drawable for a DC */
58     X11DRV_GET_FONT,            /* get current X font for a DC */
59     X11DRV_SET_DRAWABLE,        /* set current drawable for a DC */
60     X11DRV_START_EXPOSURES,     /* start graphics exposures */
61     X11DRV_END_EXPOSURES,       /* end graphics exposures */
62     X11DRV_GET_DCE,             /* get the DCE pointer */
63     X11DRV_SET_DCE,             /* set the DCE pointer */
64     X11DRV_GET_GLX_DRAWABLE,    /* get current glx drawable for a DC */
65     X11DRV_SYNC_PIXMAP          /* sync the dibsection to its pixmap */
66 };
67
68 void (*wine_tsx11_lock_ptr)(void) = NULL;
69 void (*wine_tsx11_unlock_ptr)(void) = NULL;
70
71 static GLXContext default_cx = NULL;
72 static Display *default_display;  /* display to use for default context */
73
74 static HMODULE opengl32_handle;
75
76 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
77
78 static char  internal_gl_disabled_extensions[512];
79 static char* internal_gl_extensions = NULL;
80
81 typedef struct wine_glcontext {
82   HDC hdc;
83   Display *display;
84   XVisualInfo *vis;
85   GLXFBConfig fb_conf;
86   GLXContext ctx;
87   BOOL do_escape;
88   struct wine_glcontext *next;
89   struct wine_glcontext *prev;
90 } Wine_GLContext;
91 static Wine_GLContext *context_list;
92
93 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
94 {
95     Wine_GLContext *ret;
96     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
97     return ret;
98 }
99
100 void enter_gl(void)
101 {
102     Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
103     
104     if (curctx && curctx->do_escape)
105     {
106         enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
107         ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
108     }
109
110     wine_tsx11_lock_ptr();
111     return;
112 }
113
114 static inline void free_context(Wine_GLContext *context)
115 {
116   if (context->next != NULL) context->next->prev = context->prev;
117   if (context->prev != NULL) context->prev->next = context->next;
118   else context_list = context->next;
119
120   HeapFree(GetProcessHeap(), 0, context);
121 }
122
123 static inline Wine_GLContext *alloc_context(void)
124 {
125   Wine_GLContext *ret;
126
127   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
128   {
129       ret->next = context_list;
130       if (context_list) context_list->prev = ret;
131       context_list = ret;
132   }
133   return ret;
134 }
135
136 inline static BOOL is_valid_context( Wine_GLContext *ctx )
137 {
138     Wine_GLContext *ptr;
139     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
140     return (ptr != NULL);
141 }
142
143 /* retrieve the X display to use on a given DC */
144 inline static Display *get_display( HDC hdc )
145 {
146     Display *display;
147     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
148
149     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
150                     sizeof(display), (LPSTR)&display )) display = NULL;
151     return display;
152 }
153
154
155 /* retrieve the GLX drawable to use on a given DC */
156 inline static Drawable get_drawable( HDC hdc )
157 {
158     GLXDrawable drawable;
159     enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
160
161     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
162                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
163     return drawable;
164 }
165
166 /** for use of wglGetCurrentReadDCARB */
167 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
168 {
169   Wine_GLContext *ret;
170   for (ret = context_list; ret; ret = ret->next) {  
171     if (d == get_drawable( ret->hdc )) {
172       return ret->hdc;
173     }
174   }
175   return NULL;
176 }
177
178 /* retrieve the X font to use on a given DC */
179 inline static Font get_font( HDC hdc )
180 {
181     Font font;
182     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
183
184     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
185                     sizeof(font), (LPSTR)&font )) font = 0;
186     return font;
187 }
188
189
190 /***********************************************************************
191  *              wglCreateContext (OPENGL32.@)
192  */
193 HGLRC WINAPI wglCreateContext(HDC hdc)
194 {
195   Wine_GLContext *ret;
196   int num;
197   XVisualInfo template;
198   XVisualInfo *vis = NULL;
199   Display *display = get_display( hdc );
200   int hdcPF = GetPixelFormat(hdc);
201   GLXFBConfig cur_cfg;
202
203   TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
204
205   /* First, get the visual in use by the X11DRV */
206   if (!display) return 0;
207   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
208   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
209
210   if (vis == NULL) {
211     ERR("NULL visual !!!\n");
212     /* Need to set errors here */
213     return NULL;
214   }
215   if (0 >= hdcPF) {
216     SetLastError(ERROR_INVALID_PIXEL_FORMAT);
217     return NULL;
218   }
219
220   {
221     int nCfgs_fmt = 0;
222     GLXFBConfig* cfgs_fmt = NULL;
223     int value;
224     int gl_test = 0;
225     cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
226     if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
227       ERR("Cannot get FB Configs, expect problems.\n");
228       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
229       return NULL;
230     }
231     if (nCfgs_fmt < hdcPF) {
232       ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
233       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
234       return NULL;
235     }
236     cur_cfg = cfgs_fmt[hdcPF - 1];
237     gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
238     if (gl_test) {
239       ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
240       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
241       return NULL;
242     }
243     XFree(cfgs_fmt);
244   }
245
246   /* The context will be allocated in the wglMakeCurrent call */
247   ENTER_GL();
248   ret = alloc_context();
249   LEAVE_GL();
250   ret->hdc = hdc;
251   ret->display = display;
252   ret->fb_conf = cur_cfg;
253   /*ret->vis = vis;*/
254   ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
255
256   TRACE(" creating context %p (GL context creation delayed)\n", ret);
257   return (HGLRC) ret;
258 }
259
260 /***********************************************************************
261  *              wglCreateLayerContext (OPENGL32.@)
262  */
263 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
264                                    int iLayerPlane) {
265   TRACE("(%p,%d)\n", hdc, iLayerPlane);
266
267   if (iLayerPlane == 0) {
268       return wglCreateContext(hdc);
269   }
270   FIXME(" no handler for layer %d\n", iLayerPlane);
271
272   return NULL;
273 }
274
275 /***********************************************************************
276  *              wglCopyContext (OPENGL32.@)
277  */
278 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
279                            HGLRC hglrcDst,
280                            UINT mask) {
281   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
282
283   return FALSE;
284 }
285
286 /***********************************************************************
287  *              wglDeleteContext (OPENGL32.@)
288  */
289 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
290 {
291   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
292   BOOL ret = TRUE;
293
294   TRACE("(%p)\n", hglrc);
295
296   ENTER_GL();
297   /* A game (Half Life not to name it) deletes twice the same context,
298    * so make sure it is valid first */
299   if (is_valid_context( ctx ))
300   {
301       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
302       free_context(ctx);
303   }
304   else
305   {
306     WARN("Error deleting context !\n");
307     SetLastError(ERROR_INVALID_HANDLE);
308     ret = FALSE;
309   }
310   LEAVE_GL();
311
312   return ret;
313 }
314
315 /***********************************************************************
316  *              wglDescribeLayerPlane (OPENGL32.@)
317  */
318 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
319                                   int iPixelFormat,
320                                   int iLayerPlane,
321                                   UINT nBytes,
322                                   LPLAYERPLANEDESCRIPTOR plpd) {
323   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
324
325   return FALSE;
326 }
327
328 /***********************************************************************
329  *              wglGetCurrentContext (OPENGL32.@)
330  */
331 HGLRC WINAPI wglGetCurrentContext(void) {
332   GLXContext gl_ctx;
333   Wine_GLContext *ret;
334
335   TRACE("()\n");
336
337   ENTER_GL();
338   gl_ctx = glXGetCurrentContext();
339   ret = get_context_from_GLXContext(gl_ctx);
340   LEAVE_GL();
341
342   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
343
344   return (HGLRC)ret;
345 }
346
347 /***********************************************************************
348  *              wglGetCurrentDC (OPENGL32.@)
349  */
350 HDC WINAPI wglGetCurrentDC(void) {
351   GLXContext gl_ctx;
352   Wine_GLContext *ret;
353
354   TRACE("()\n");
355
356   ENTER_GL();
357   gl_ctx = glXGetCurrentContext();
358   ret = get_context_from_GLXContext(gl_ctx);
359   LEAVE_GL();
360
361   if (ret) {
362     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
363     return ret->hdc;
364   } else {
365     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
366     return 0;
367   }
368 }
369
370 /***********************************************************************
371  *              wglGetLayerPaletteEntries (OPENGL32.@)
372  */
373 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
374                                      int iLayerPlane,
375                                      int iStart,
376                                      int cEntries,
377                                      const COLORREF *pcr) {
378   FIXME("(): stub !\n");
379
380   return 0;
381 }
382
383 /***********************************************************************
384  *              wglGetProcAddress (OPENGL32.@)
385  */
386 static int compar(const void *elt_a, const void *elt_b) {
387   return strcmp(((const OpenGL_extension *) elt_a)->name,
388                 ((const OpenGL_extension *) elt_b)->name);
389 }
390
391 static int wgl_compar(const void *elt_a, const void *elt_b) {
392   return strcmp(((const WGL_extension *) elt_a)->func_name,
393                 ((const WGL_extension *) elt_b)->func_name);
394 }
395
396 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
397   void *local_func;
398   OpenGL_extension  ext;
399   OpenGL_extension *ext_ret;
400
401   TRACE("(%s)\n", lpszProc);
402
403   /* First, look if it's not already defined in the 'standard' OpenGL functions */
404   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
405     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
406     return local_func;
407   }
408
409   if (p_glXGetProcAddressARB == NULL) {
410     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
411     return NULL;
412   }
413   
414   /* After that, search in the thunks to find the real name of the extension */
415   ext.name = (char *) lpszProc;
416   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
417                                          extension_registry_size, sizeof(OpenGL_extension), compar);
418
419   if (ext_ret == NULL) {
420     WGL_extension wgl_ext, *wgl_ext_ret;
421
422     /* Try to find the function in the WGL extensions ... */
423     wgl_ext.func_name = (char *) lpszProc;
424     wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
425                                             wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
426
427     if (wgl_ext_ret == NULL) {
428       /* Some sanity checks :-) */
429       ENTER_GL();
430       local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
431       LEAVE_GL();
432       if (local_func != NULL) {
433         WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
434         return NULL;
435       }
436       
437       WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
438       return NULL;
439     } else {
440         void *ret = NULL;
441
442         if (wgl_ext_ret->func_init != NULL) {
443             const char *err_msg;
444             if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
445                                                   wgl_ext_ret->context)) == NULL) {
446                 ret = wgl_ext_ret->func_address;
447             } else {
448                 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
449                 return NULL;
450             }
451         } else {
452           ret = wgl_ext_ret->func_address;
453         }
454
455         if (ret)
456             TRACE(" returning WGL function  (%p)\n", ret);
457         return ret;
458     }
459   } else {
460     ENTER_GL();
461     local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
462     LEAVE_GL();
463     
464     /* After that, look at the extensions defined in the Linux OpenGL library */
465     if (local_func == NULL) {
466       char buf[256];
467       void *ret = NULL;
468
469       /* Remove the 3 last letters (EXT, ARB, ...).
470
471          I know that some extensions have more than 3 letters (MESA, NV,
472          INTEL, ...), but this is only a stop-gap measure to fix buggy
473          OpenGL drivers (moreover, it is only useful for old 1.0 apps
474          that query the glBindTextureEXT extension).
475       */
476       memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
477       buf[strlen(ext_ret->glx_name) - 3] = '\0';
478       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
479
480       ret = GetProcAddress(opengl32_handle, buf);
481       if (ret != NULL) {
482         TRACE(" found function in main OpenGL library (%p) !\n", ret);
483       } else {
484         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
485       }
486
487       return ret;
488     } else {
489       TRACE(" returning function  (%p)\n", ext_ret->func);
490       *(ext_ret->func_ptr) = local_func;
491
492       return ext_ret->func;
493     }
494   }
495 }
496
497 static int describeContext(Wine_GLContext* ctx) {
498   int tmp;
499   int ctx_vis_id;
500   TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
501   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
502   TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
503   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
504   TRACE(" - VISUAL_ID 0x%x\n", tmp);
505   ctx_vis_id = tmp;
506   return ctx_vis_id;
507 }
508
509 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
510   int tmp;
511   int draw_vis_id;
512   if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable)  {
513     /** glXQueryDrawable not available so returns not supported */
514     return -1;
515   }
516   TRACE(" Drawable %p have :\n", (void*) drawable);
517   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
518   TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
519   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
520   TRACE(" - VISUAL_ID as 0x%x\n", tmp);
521   draw_vis_id = tmp;
522   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
523   TRACE(" - WIDTH as %d\n", tmp);
524   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
525   TRACE(" - HEIGHT as %d\n", tmp);
526   return draw_vis_id;
527 }
528
529 /***********************************************************************
530  *              wglMakeCurrent (OPENGL32.@)
531  */
532 BOOL WINAPI wglMakeCurrent(HDC hdc,
533                            HGLRC hglrc) {
534   BOOL ret;
535   DWORD type = GetObjectType(hdc);
536
537   TRACE("(%p,%p)\n", hdc, hglrc);
538
539   ENTER_GL();
540   if (hglrc == NULL) {
541       ret = glXMakeCurrent(default_display, None, NULL);
542       NtCurrentTeb()->glContext = NULL;
543   } else {
544       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
545       Drawable drawable = get_drawable( hdc );
546       if (ctx->ctx == NULL) {
547         int draw_vis_id, ctx_vis_id;
548         VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
549         TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
550         draw_vis_id = describeDrawable(ctx, drawable);
551         ctx_vis_id = describeContext(ctx);
552
553         if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
554           /**
555            * Inherits from root window so reuse desktop visual
556            */
557           XVisualInfo template;
558           XVisualInfo *vis;
559           int num;
560           template.visualid = visualid;
561           vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
562
563           TRACE(" Creating GLX Context\n");
564           ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
565         } else {
566           TRACE(" Creating GLX Context\n");
567           ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
568         }
569         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
570       }
571       TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
572       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
573       NtCurrentTeb()->glContext = ctx;
574       if(ret && type == OBJ_MEMDC)
575       {
576           ctx->do_escape = TRUE;
577           glDrawBuffer(GL_FRONT_LEFT);
578       }
579   }
580   LEAVE_GL();
581   TRACE(" returning %s\n", (ret ? "True" : "False"));
582   return ret;
583 }
584
585 /***********************************************************************
586  *              wglMakeContextCurrentARB (OPENGL32.@)
587  */
588 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc) 
589 {
590   BOOL ret;
591   TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
592
593   ENTER_GL();
594   if (hglrc == NULL) {
595     ret = glXMakeCurrent(default_display, None, NULL);
596   } else {
597     if (NULL == wine_glx.p_glXMakeContextCurrent) {
598       ret = FALSE;
599     } else {
600       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
601       Drawable d_draw = get_drawable( hDrawDC );
602       Drawable d_read = get_drawable( hReadDC );
603       
604       if (ctx->ctx == NULL) {
605         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
606         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
607       }
608       ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
609     }
610   }
611   LEAVE_GL();
612   
613   TRACE(" returning %s\n", (ret ? "True" : "False"));
614   return ret;
615 }
616
617 /***********************************************************************
618  *              wglGetCurrentReadDCARB (OPENGL32.@)
619  */
620 HDC WINAPI wglGetCurrentReadDCARB(void) 
621 {
622   GLXDrawable gl_d;
623   HDC ret;
624
625   TRACE("()\n");
626
627   ENTER_GL();
628   gl_d = glXGetCurrentReadDrawable();
629   ret = get_hdc_from_Drawable(gl_d);
630   LEAVE_GL();
631
632   TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
633   return ret;
634 }
635
636
637
638 /***********************************************************************
639  *              wglRealizeLayerPalette (OPENGL32.@)
640  */
641 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
642                                    int iLayerPlane,
643                                    BOOL bRealize) {
644   FIXME("()\n");
645
646   return FALSE;
647 }
648
649 /***********************************************************************
650  *              wglSetLayerPaletteEntries (OPENGL32.@)
651  */
652 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
653                                      int iLayerPlane,
654                                      int iStart,
655                                      int cEntries,
656                                      const COLORREF *pcr) {
657   FIXME("(): stub !\n");
658
659   return 0;
660 }
661
662 /***********************************************************************
663  *              wglShareLists (OPENGL32.@)
664  */
665 BOOL WINAPI wglShareLists(HGLRC hglrc1,
666                           HGLRC hglrc2) {
667   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
668   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
669
670   TRACE("(%p, %p)\n", org, dest);
671
672   if (NULL != dest && dest->ctx != NULL) {
673     ERR("Could not share display lists, context already created !\n");
674     return FALSE;
675   } else {
676     if (org->ctx == NULL) {
677       ENTER_GL();
678       describeContext(org);
679       org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
680       LEAVE_GL();
681       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
682     }
683     if (NULL != dest) {
684       ENTER_GL();
685       describeContext(dest);
686       /* Create the destination context with display lists shared */
687       dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
688       LEAVE_GL();
689       TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
690       return TRUE;
691     }
692   }
693   return FALSE;
694 }
695
696 /***********************************************************************
697  *              wglSwapLayerBuffers (OPENGL32.@)
698  */
699 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
700                                 UINT fuPlanes) {
701   TRACE("(%p, %08x)\n", hdc, fuPlanes);
702
703   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
704     if (!SwapBuffers(hdc)) return FALSE;
705     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
706   }
707
708   if (fuPlanes) {
709     WARN("Following layers unhandled : %08x\n", fuPlanes);
710   }
711
712   return TRUE;
713 }
714
715 static BOOL internal_wglUseFontBitmaps(HDC hdc,
716                                        DWORD first,
717                                        DWORD count,
718                                        DWORD listBase,
719                                        DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
720 {
721     /* We are running using client-side rendering fonts... */
722     GLYPHMETRICS gm;
723     unsigned int glyph;
724     int size = 0;
725     void *bitmap = NULL, *gl_bitmap = NULL;
726     int org_alignment;
727
728     ENTER_GL();
729     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
730     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
731     LEAVE_GL();
732
733     for (glyph = first; glyph < first + count; glyph++) {
734         unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
735         int height, width_int;
736
737         TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
738         if (needed_size == GDI_ERROR) {
739             TRACE("  - needed size : %d (GDI_ERROR)\n", needed_size);
740             goto error;
741         } else {
742             TRACE("  - needed size : %d\n", needed_size);
743         }
744
745         if (needed_size > size) {
746             size = needed_size;
747             HeapFree(GetProcessHeap(), 0, bitmap);
748             HeapFree(GetProcessHeap(), 0, gl_bitmap);
749             bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
750             gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
751         }
752         if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
753         if (TRACE_ON(opengl)) {
754             unsigned int height, width, bitmask;
755             unsigned char *bitmap_ = (unsigned char *) bitmap;
756             
757             TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
758             TRACE("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
759             TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
760             if (needed_size != 0) {
761                 TRACE("  - bitmap :\n");
762                 for (height = 0; height < gm.gmBlackBoxY; height++) {
763                     TRACE("      ");
764                     for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
765                         if (bitmask == 0) {
766                             bitmap_ += 1;
767                             bitmask = 0x80;
768                         }
769                         if (*bitmap_ & bitmask)
770                             TRACE("*");
771                         else
772                             TRACE(" ");
773                     }
774                     bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
775                     TRACE("\n");
776                 }
777             }
778         }
779         
780         /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
781          * glyph for it to be drawn properly.
782          */
783         if (needed_size != 0) {
784             width_int = (gm.gmBlackBoxX + 31) / 32;
785             for (height = 0; height < gm.gmBlackBoxY; height++) {
786                 int width;
787                 for (width = 0; width < width_int; width++) {
788                     ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
789                         ((int *) bitmap)[height * width_int + width];
790                 }
791             }
792         }
793         
794         ENTER_GL();
795         glNewList(listBase++, GL_COMPILE);
796         if (needed_size != 0) {
797             glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
798                      0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
799                      gm.gmCellIncX, gm.gmCellIncY,
800                      gl_bitmap);
801         } else {
802             /* This is the case of 'empty' glyphs like the space character */
803             glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
804         }
805         glEndList();
806         LEAVE_GL();
807     }
808     
809     ENTER_GL();
810     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
811     LEAVE_GL();
812     
813     HeapFree(GetProcessHeap(), 0, bitmap);
814     HeapFree(GetProcessHeap(), 0, gl_bitmap);
815     return TRUE;
816
817   error:
818     ENTER_GL();
819     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
820     LEAVE_GL();
821
822     HeapFree(GetProcessHeap(), 0, bitmap);
823     HeapFree(GetProcessHeap(), 0, gl_bitmap);
824     return FALSE;    
825 }
826
827 /***********************************************************************
828  *              wglUseFontBitmapsA (OPENGL32.@)
829  */
830 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
831                                DWORD first,
832                                DWORD count,
833                                DWORD listBase)
834 {
835   Font fid = get_font( hdc );
836
837   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
838
839   if (fid == 0) {
840       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
841   }
842
843   ENTER_GL();
844   /* I assume that the glyphs are at the same position for X and for Windows */
845   glXUseXFont(fid, first, count, listBase);
846   LEAVE_GL();
847   return TRUE;
848 }
849
850 /***********************************************************************
851  *              wglUseFontBitmapsW (OPENGL32.@)
852  */
853 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
854                                DWORD first,
855                                DWORD count,
856                                DWORD listBase)
857 {
858   Font fid = get_font( hdc );
859
860   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
861
862   if (fid == 0) {
863       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
864   }
865
866   WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
867   
868   ENTER_GL();
869   /* I assume that the glyphs are at the same position for X and for Windows */
870   glXUseXFont(fid, first, count, listBase);
871   LEAVE_GL();
872   return TRUE;
873 }
874
875 #ifdef HAVE_GL_GLU_H
876
877 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
878 {
879     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
880     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
881     vertex[2] = 0.0;
882 }
883
884 static void tess_callback_vertex(GLvoid *vertex)
885 {
886     GLdouble *dbl = vertex;
887     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
888     glVertex3dv(vertex);
889 }
890
891 static void tess_callback_begin(GLenum which)
892 {
893     TRACE("%d\n", which);
894     glBegin(which);
895 }
896
897 static void tess_callback_end(void)
898 {
899     TRACE("\n");
900     glEnd();
901 }
902
903 /***********************************************************************
904  *              wglUseFontOutlines_common
905  */
906 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
907                                       DWORD first,
908                                       DWORD count,
909                                       DWORD listBase,
910                                       FLOAT deviation,
911                                       FLOAT extrusion,
912                                       int format,
913                                       LPGLYPHMETRICSFLOAT lpgmf,
914                                       BOOL unicode)
915 {
916     UINT glyph;
917     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
918     GLUtesselator *tess;
919     LOGFONTW lf;
920     HFONT old_font, unscaled_font;
921     UINT em_size = 1024;
922     RECT rc;
923
924     TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
925           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
926
927
928     ENTER_GL();
929     tess = gluNewTess();
930     if(tess)
931     {
932         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
933         gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
934         gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
935     }
936     LEAVE_GL();
937
938     if(!tess) return FALSE;
939
940     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
941     rc.left = rc.right = rc.bottom = 0;
942     rc.top = em_size;
943     DPtoLP(hdc, (POINT*)&rc, 2);
944     lf.lfHeight = -abs(rc.top - rc.bottom);
945     lf.lfOrientation = lf.lfEscapement = 0;
946     unscaled_font = CreateFontIndirectW(&lf);
947     old_font = SelectObject(hdc, unscaled_font);
948
949     for (glyph = first; glyph < first + count; glyph++)
950     {
951         DWORD needed;
952         GLYPHMETRICS gm;
953         BYTE *buf;
954         TTPOLYGONHEADER *pph;
955         TTPOLYCURVE *ppc;
956         GLdouble *vertices;
957
958         if(unicode)
959             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
960         else
961             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
962
963         if(needed == GDI_ERROR)
964             goto error;
965
966         buf = HeapAlloc(GetProcessHeap(), 0, needed);
967         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
968
969         if(unicode)
970             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
971         else
972             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
973
974         TRACE("glyph %d\n", glyph);
975
976         if(lpgmf)
977         {
978             lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
979             lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
980             lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
981             lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
982             lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
983             lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
984             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
985                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
986             lpgmf++;
987         }
988
989         ENTER_GL();
990         glNewList(listBase++, GL_COMPILE);
991         gluTessBeginPolygon(tess, NULL);
992
993         pph = (TTPOLYGONHEADER*)buf;
994         while((BYTE*)pph < buf + needed)
995         {
996             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
997
998             gluTessBeginContour(tess);
999
1000             fixed_to_double(pph->pfxStart, em_size, vertices);
1001             gluTessVertex(tess, vertices, vertices);
1002             vertices += 3;
1003
1004             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1005             while((char*)ppc < (char*)pph + pph->cb)
1006             {
1007                 int i;
1008
1009                 switch(ppc->wType) {
1010                 case TT_PRIM_LINE:
1011                     for(i = 0; i < ppc->cpfx; i++)
1012                     {
1013                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1014                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
1015                         gluTessVertex(tess, vertices, vertices);
1016                         vertices += 3;
1017                     }
1018                     break;
1019
1020                 case TT_PRIM_QSPLINE:
1021                     for(i = 0; i < ppc->cpfx/2; i++)
1022                     {
1023                         /* FIXME just connecting the control points for now */
1024                         TRACE("\t\tcurve  %d,%d %d,%d\n",
1025                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
1026                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1027                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
1028                         gluTessVertex(tess, vertices, vertices);
1029                         vertices += 3;
1030                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
1031                         gluTessVertex(tess, vertices, vertices);
1032                         vertices += 3;
1033                     }
1034                     break;
1035                 default:
1036                     ERR("\t\tcurve type = %d\n", ppc->wType);
1037                     gluTessEndContour(tess);
1038                     goto error_in_list;
1039                 }
1040
1041                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1042                                      (ppc->cpfx - 1) * sizeof(POINTFX));
1043             }
1044             gluTessEndContour(tess);
1045             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1046         }
1047
1048 error_in_list:
1049         gluTessEndPolygon(tess);
1050         glEndList();
1051         LEAVE_GL();
1052         HeapFree(GetProcessHeap(), 0, buf);
1053         HeapFree(GetProcessHeap(), 0, vertices);
1054     }
1055
1056  error:
1057     DeleteObject(SelectObject(hdc, old_font));
1058     gluDeleteTess(tess);
1059     return TRUE;
1060
1061 }
1062
1063 #else /* HAVE_GL_GLU_H */
1064
1065 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1066                                       DWORD first,
1067                                       DWORD count,
1068                                       DWORD listBase,
1069                                       FLOAT deviation,
1070                                       FLOAT extrusion,
1071                                       int format,
1072                                       LPGLYPHMETRICSFLOAT lpgmf,
1073                                       BOOL unicode)
1074 {
1075     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1076     return FALSE;
1077 }
1078
1079 #endif /* HAVE_GL_GLU_H */
1080
1081 /***********************************************************************
1082  *              wglUseFontOutlinesA (OPENGL32.@)
1083  */
1084 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1085                                 DWORD first,
1086                                 DWORD count,
1087                                 DWORD listBase,
1088                                 FLOAT deviation,
1089                                 FLOAT extrusion,
1090                                 int format,
1091                                 LPGLYPHMETRICSFLOAT lpgmf)
1092 {
1093     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1094 }
1095
1096 /***********************************************************************
1097  *              wglUseFontOutlinesW (OPENGL32.@)
1098  */
1099 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1100                                 DWORD first,
1101                                 DWORD count,
1102                                 DWORD listBase,
1103                                 FLOAT deviation,
1104                                 FLOAT extrusion,
1105                                 int format,
1106                                 LPGLYPHMETRICSFLOAT lpgmf)
1107 {
1108     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1109 }
1110
1111 const GLubyte * internal_glGetString(GLenum name) {
1112   const char* GL_Extensions = NULL;
1113   
1114   if (GL_EXTENSIONS != name) {
1115     return glGetString(name);
1116   }
1117
1118   if (NULL == internal_gl_extensions) {
1119     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1120
1121     TRACE("GL_EXTENSIONS reported:\n");  
1122     if (NULL == GL_Extensions) {
1123       ERR("GL_EXTENSIONS returns NULL\n");      
1124       return NULL;
1125     } else {
1126       size_t len = strlen(GL_Extensions);
1127       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1128
1129       while (*GL_Extensions != 0x00) {
1130         const char* Start = GL_Extensions;
1131         char        ThisExtn[256];
1132          
1133         memset(ThisExtn, 0x00, sizeof(ThisExtn));
1134         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1135           GL_Extensions++;
1136         }
1137         memcpy(ThisExtn, Start, (GL_Extensions - Start));
1138         TRACE("- %s:", ThisExtn);
1139         
1140         /* test if supported API is disabled by config */
1141         if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1142           strcat(internal_gl_extensions, " ");
1143           strcat(internal_gl_extensions, ThisExtn);
1144           TRACE(" active\n");
1145         } else {
1146           TRACE(" deactived (by config)\n");
1147         }
1148
1149         if (*GL_Extensions == ' ') GL_Extensions++;
1150       }
1151     }
1152   }
1153   return (const GLubyte *) internal_gl_extensions;
1154 }
1155
1156 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1157   glGetIntegerv(pname, params);
1158   if (pname == GL_DEPTH_BITS) { 
1159     GLXContext gl_ctx = glXGetCurrentContext();
1160     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1161     /*TRACE("returns Wine Ctx as %p\n", ret);*/
1162     /** 
1163      * if we cannot find a Wine Context
1164      * we only have the default wine desktop context, 
1165      * so if we have only a 24 depth say we have 32
1166      */
1167     if (NULL == ret && 24 == *params) { 
1168       *params = 32;
1169     }
1170     TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1171   }
1172   if (pname == GL_ALPHA_BITS) {
1173     GLint tmp;
1174     GLXContext gl_ctx = glXGetCurrentContext();
1175     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1176     glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1177     TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1178     *params = tmp;
1179   }
1180 }
1181
1182
1183 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1184    include all dependencies
1185 */
1186 #ifndef SONAME_LIBGL
1187 #define SONAME_LIBGL "libGL.so"
1188 #endif
1189
1190 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc) 
1191 {
1192   const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1193   const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1194   /*
1195   const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1196   const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1197   const char *glx_extensions = glXQueryExtensionsString(display, screen);
1198   */
1199
1200   memset(&wine_glx, 0, sizeof(wine_glx));
1201
1202   if (!strcmp("1.2", server_glx_version)) {
1203     wine_glx.version = 2;
1204   } else {
1205     wine_glx.version = 3;
1206   }
1207
1208   if (2 < wine_glx.version) {
1209     wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1210     wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1211     wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1212
1213     /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1214     wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1215   } else {
1216     if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1217       wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1218       wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1219       wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1220     } else {
1221       ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1222     }
1223   }
1224   /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1225   wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1226   wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1227 }
1228
1229 /* This is for brain-dead applications that use OpenGL functions before even
1230    creating a rendering context.... */
1231 static BOOL process_attach(void)
1232 {
1233   XWindowAttributes win_attr;
1234   Visual *rootVisual;
1235   int num;
1236   XVisualInfo template;
1237   HDC hdc;
1238   XVisualInfo *vis = NULL;
1239   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1240   HMODULE mod = GetModuleHandleA( "winex11.drv" );
1241   void *opengl_handle;
1242   DWORD size = sizeof(internal_gl_disabled_extensions);
1243   HKEY hkey = 0;
1244
1245   if (!root || !mod)
1246   {
1247       ERR("X11DRV not loaded. Cannot create default context.\n");
1248       return FALSE;
1249   }
1250
1251   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1252   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1253
1254   hdc = GetDC(0);
1255   default_display = get_display( hdc );
1256   ReleaseDC( 0, hdc );
1257   if (!default_display)
1258   {
1259       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1260       return FALSE;
1261   }
1262
1263   ENTER_GL();
1264
1265   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
1266      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1267      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1268      with mismatched visuals.  Note that the Root Window visual may not be double
1269      buffered, so apps actually attempting to render this way may flicker */
1270   if (XGetWindowAttributes( default_display, root, &win_attr ))
1271   {
1272     rootVisual = win_attr.visual;
1273   }
1274   else
1275   {
1276     /* Get the default visual, since we can't seem to get the attributes from the
1277        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
1278     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1279   }
1280
1281   template.visualid = XVisualIDFromVisual(rootVisual);
1282   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1283   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1284   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1285   XFree(vis);
1286   LEAVE_GL();
1287
1288   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1289   if (opengl_handle != NULL) {
1290    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1291    wine_dlclose(opengl_handle, NULL, 0);
1292    if (p_glXGetProcAddressARB == NULL)
1293            TRACE("could not find glXGetProcAddressARB in libGL.\n");
1294   }
1295
1296   internal_gl_disabled_extensions[0] = 0;
1297   if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1298     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1299       TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1300     }
1301     RegCloseKey(hkey);
1302   }
1303
1304   if (default_cx == NULL) {
1305     ERR("Could not create default context.\n");
1306   }
1307   else
1308   {
1309     /* After context initialize also the list of supported WGL extensions. */
1310     wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1311     wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1312   }
1313   return TRUE;
1314 }
1315
1316
1317 /**********************************************************************/
1318
1319 static void process_detach(void)
1320 {
1321   glXDestroyContext(default_display, default_cx);
1322
1323   /* Do not leak memory... */
1324   wgl_ext_finalize_extensions();
1325   if (NULL != internal_gl_extensions) {
1326     HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1327   }
1328 }
1329
1330 /***********************************************************************
1331  *           OpenGL initialisation routine
1332  */
1333 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1334 {
1335     switch(reason)
1336     {
1337     case DLL_PROCESS_ATTACH:
1338         opengl32_handle = hinst;
1339         DisableThreadLibraryCalls(hinst);
1340         return process_attach();
1341     case DLL_PROCESS_DETACH:
1342         process_detach();
1343         break;
1344     }
1345     return TRUE;
1346 }