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