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