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