opengl32: If there's no glX context don't return a wgl context.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blob2dd59a8f2fe63c398ee84b70083d50fb189a1c81
1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
4 * Copyright (c) 2005 Raphael Junqueira
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
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"
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"
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
50 /** global glx object */
51 wine_glx_t wine_glx;
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
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 */
69 void (*wine_tsx11_lock_ptr)(void) = NULL;
70 void (*wine_tsx11_unlock_ptr)(void) = NULL;
72 static GLXContext default_cx = NULL;
73 static Display *default_display; /* display to use for default context */
75 static HMODULE opengl32_handle;
77 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
79 static char internal_gl_disabled_extensions[512];
80 static char* internal_gl_extensions = NULL;
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;
94 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
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;
102 void enter_gl(void)
104 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
106 if (curctx && curctx->do_escape)
108 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
109 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
112 wine_tsx11_lock_ptr();
113 return;
116 static inline void free_context(Wine_GLContext *context)
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;
122 HeapFree(GetProcessHeap(), 0, context);
125 static inline Wine_GLContext *alloc_context(void)
127 Wine_GLContext *ret;
129 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
131 ret->next = context_list;
132 if (context_list) context_list->prev = ret;
133 context_list = ret;
135 return ret;
138 inline static BOOL is_valid_context( Wine_GLContext *ctx )
140 Wine_GLContext *ptr;
141 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
142 return (ptr != NULL);
145 /* retrieve the X display to use on a given DC */
146 inline static Display *get_display( HDC hdc )
148 Display *display;
149 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
151 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
152 sizeof(display), (LPSTR)&display )) display = NULL;
153 return display;
157 /* retrieve the GLX drawable to use on a given DC */
158 inline static Drawable get_drawable( HDC hdc )
160 GLXDrawable drawable;
161 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
163 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
164 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
165 return drawable;
168 /** for use of wglGetCurrentReadDCARB */
169 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
171 Wine_GLContext *ret;
172 for (ret = context_list; ret; ret = ret->next) {
173 if (d == get_drawable( ret->hdc )) {
174 return ret->hdc;
177 return NULL;
180 /* retrieve the X font to use on a given DC */
181 inline static Font get_font( HDC hdc )
183 Font font;
184 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
186 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
187 sizeof(font), (LPSTR)&font )) font = 0;
188 return font;
192 /***********************************************************************
193 * wglCreateContext (OPENGL32.@)
195 HGLRC WINAPI wglCreateContext(HDC hdc)
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;
205 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
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);
212 if (vis == NULL) {
213 ERR("NULL visual !!!\n");
214 /* Need to set errors here */
215 return NULL;
217 if (0 >= hdcPF) {
218 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
219 return NULL;
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;
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;
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;
245 XFree(cfgs_fmt);
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);
258 TRACE(" creating context %p (GL context creation delayed)\n", ret);
259 return (HGLRC) ret;
262 /***********************************************************************
263 * wglCreateLayerContext (OPENGL32.@)
265 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
266 int iLayerPlane) {
267 TRACE("(%p,%d)\n", hdc, iLayerPlane);
269 if (iLayerPlane == 0) {
270 return wglCreateContext(hdc);
272 FIXME(" no handler for layer %d\n", iLayerPlane);
274 return NULL;
277 /***********************************************************************
278 * wglCopyContext (OPENGL32.@)
280 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
281 HGLRC hglrcDst,
282 UINT mask) {
283 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
285 return FALSE;
288 /***********************************************************************
289 * wglDeleteContext (OPENGL32.@)
291 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
293 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
294 BOOL ret = TRUE;
296 TRACE("(%p)\n", hglrc);
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 ))
303 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
304 free_context(ctx);
306 else
308 WARN("Error deleting context !\n");
309 SetLastError(ERROR_INVALID_HANDLE);
310 ret = FALSE;
312 LEAVE_GL();
314 return ret;
317 /***********************************************************************
318 * wglDescribeLayerPlane (OPENGL32.@)
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);
327 return FALSE;
330 /***********************************************************************
331 * wglGetCurrentContext (OPENGL32.@)
333 HGLRC WINAPI wglGetCurrentContext(void) {
334 GLXContext gl_ctx;
335 Wine_GLContext *ret;
337 TRACE("()\n");
339 ENTER_GL();
340 gl_ctx = glXGetCurrentContext();
341 ret = get_context_from_GLXContext(gl_ctx);
342 LEAVE_GL();
344 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
346 return (HGLRC)ret;
349 /***********************************************************************
350 * wglGetCurrentDC (OPENGL32.@)
352 HDC WINAPI wglGetCurrentDC(void) {
353 GLXContext gl_ctx;
354 Wine_GLContext *ret;
356 TRACE("()\n");
358 ENTER_GL();
359 gl_ctx = glXGetCurrentContext();
360 ret = get_context_from_GLXContext(gl_ctx);
361 LEAVE_GL();
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;
372 /***********************************************************************
373 * wglGetLayerPaletteEntries (OPENGL32.@)
375 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
376 int iLayerPlane,
377 int iStart,
378 int cEntries,
379 const COLORREF *pcr) {
380 FIXME("(): stub !\n");
382 return 0;
385 /***********************************************************************
386 * wglGetProcAddress (OPENGL32.@)
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);
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);
398 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
399 void *local_func;
400 OpenGL_extension ext;
401 const OpenGL_extension *ext_ret;
403 TRACE("(%s)\n", lpszProc);
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;
411 if (p_glXGetProcAddressARB == NULL) {
412 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
413 return NULL;
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);
421 if (ext_ret == NULL) {
422 WGL_extension wgl_ext, *wgl_ext_ret;
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);
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;
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;
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;
453 } else {
454 ret = wgl_ext_ret->func_address;
457 if (ret)
458 TRACE(" returning WGL function (%p)\n", ret);
459 return ret;
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();
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;
472 /* Remove the 3 last letters (EXT, ARB, ...).
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).
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);
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);
490 return ret;
491 } else {
492 TRACE(" returning function (%p)\n", ext_ret->func);
493 extension_funcs[ext_ret - extension_registry] = local_func;
495 return ext_ret->func;
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;
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;
518 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
519 /** glXQueryDrawable not available so returns not supported */
520 return -1;
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);
531 attribList[1] = tmp;
532 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
533 if (fbCfgs == NULL) {
534 return -1;
537 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
538 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
540 XFree(fbCfgs);
542 return tmp;
545 /***********************************************************************
546 * wglMakeCurrent (OPENGL32.@)
548 BOOL WINAPI wglMakeCurrent(HDC hdc,
549 HGLRC hglrc) {
550 BOOL ret;
551 DWORD type = GetObjectType(hdc);
553 TRACE("(%p,%p)\n", hdc, hglrc);
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);
569 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
571 * Inherits from root window so reuse desktop visual
573 XVisualInfo template;
574 XVisualInfo *vis;
575 int num;
576 template.visualid = visualid;
577 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
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);
585 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
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)
592 ctx->do_escape = TRUE;
593 glDrawBuffer(GL_FRONT_LEFT);
596 LEAVE_GL();
597 TRACE(" returning %s\n", (ret ? "True" : "False"));
598 return ret;
601 /***********************************************************************
602 * wglMakeContextCurrentARB (OPENGL32.@)
604 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
606 BOOL ret;
607 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
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 );
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);
624 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
627 LEAVE_GL();
629 TRACE(" returning %s\n", (ret ? "True" : "False"));
630 return ret;
633 /***********************************************************************
634 * wglGetCurrentReadDCARB (OPENGL32.@)
636 HDC WINAPI wglGetCurrentReadDCARB(void)
638 GLXDrawable gl_d;
639 HDC ret;
641 TRACE("()\n");
643 ENTER_GL();
644 gl_d = glXGetCurrentReadDrawable();
645 ret = get_hdc_from_Drawable(gl_d);
646 LEAVE_GL();
648 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
649 return ret;
654 /***********************************************************************
655 * wglRealizeLayerPalette (OPENGL32.@)
657 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
658 int iLayerPlane,
659 BOOL bRealize) {
660 FIXME("()\n");
662 return FALSE;
665 /***********************************************************************
666 * wglSetLayerPaletteEntries (OPENGL32.@)
668 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
669 int iLayerPlane,
670 int iStart,
671 int cEntries,
672 const COLORREF *pcr) {
673 FIXME("(): stub !\n");
675 return 0;
678 /***********************************************************************
679 * wglShareLists (OPENGL32.@)
681 BOOL WINAPI wglShareLists(HGLRC hglrc1,
682 HGLRC hglrc2) {
683 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
684 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
686 TRACE("(%p, %p)\n", org, dest);
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);
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;
709 return FALSE;
712 /***********************************************************************
713 * wglSwapLayerBuffers (OPENGL32.@)
715 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
716 UINT fuPlanes) {
717 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
719 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
720 if (!SwapBuffers(hdc)) return FALSE;
721 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
724 if (fuPlanes) {
725 WARN("Following layers unhandled : %08x\n", fuPlanes);
728 return TRUE;
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*))
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;
744 ENTER_GL();
745 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
746 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
747 LEAVE_GL();
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;
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);
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);
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;
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;
785 if (*bitmap_ & bitmask)
786 TRACE("*");
787 else
788 TRACE(" ");
790 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
791 TRACE("\n");
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.
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];
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);
821 glEndList();
822 LEAVE_GL();
825 ENTER_GL();
826 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
827 LEAVE_GL();
829 HeapFree(GetProcessHeap(), 0, bitmap);
830 HeapFree(GetProcessHeap(), 0, gl_bitmap);
831 return TRUE;
833 error:
834 ENTER_GL();
835 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
836 LEAVE_GL();
838 HeapFree(GetProcessHeap(), 0, bitmap);
839 HeapFree(GetProcessHeap(), 0, gl_bitmap);
840 return FALSE;
843 /***********************************************************************
844 * wglUseFontBitmapsA (OPENGL32.@)
846 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
847 DWORD first,
848 DWORD count,
849 DWORD listBase)
851 Font fid = get_font( hdc );
853 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
855 if (fid == 0) {
856 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
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;
866 /***********************************************************************
867 * wglUseFontBitmapsW (OPENGL32.@)
869 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
870 DWORD first,
871 DWORD count,
872 DWORD listBase)
874 Font fid = get_font( hdc );
876 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
878 if (fid == 0) {
879 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
882 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
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;
891 #ifdef HAVE_GL_GLU_H
893 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
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;
900 static void tess_callback_vertex(GLvoid *vertex)
902 GLdouble *dbl = vertex;
903 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
904 glVertex3dv(vertex);
907 static void tess_callback_begin(GLenum which)
909 TRACE("%d\n", which);
910 glBegin(which);
913 static void tess_callback_end(void)
915 TRACE("\n");
916 glEnd();
919 /***********************************************************************
920 * wglUseFontOutlines_common
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)
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;
940 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
941 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
944 ENTER_GL();
945 tess = gluNewTess();
946 if(tess)
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);
952 LEAVE_GL();
954 if(!tess) return FALSE;
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);
965 for (glyph = first; glyph < first + count; glyph++)
967 DWORD needed;
968 GLYPHMETRICS gm;
969 BYTE *buf;
970 TTPOLYGONHEADER *pph;
971 TTPOLYCURVE *ppc;
972 GLdouble *vertices;
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);
979 if(needed == GDI_ERROR)
980 goto error;
982 buf = HeapAlloc(GetProcessHeap(), 0, needed);
983 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
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);
990 TRACE("glyph %d\n", glyph);
992 if(lpgmf)
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++;
1005 ENTER_GL();
1006 glNewList(listBase++, GL_COMPILE);
1007 gluTessBeginPolygon(tess, NULL);
1009 pph = (TTPOLYGONHEADER*)buf;
1010 while((BYTE*)pph < buf + needed)
1012 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1014 gluTessBeginContour(tess);
1016 fixed_to_double(pph->pfxStart, em_size, vertices);
1017 gluTessVertex(tess, vertices, vertices);
1018 vertices += 3;
1020 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1021 while((char*)ppc < (char*)pph + pph->cb)
1023 int i;
1025 switch(ppc->wType) {
1026 case TT_PRIM_LINE:
1027 for(i = 0; i < ppc->cpfx; i++)
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;
1034 break;
1036 case TT_PRIM_QSPLINE:
1037 for(i = 0; i < ppc->cpfx/2; i++)
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;
1050 break;
1051 default:
1052 ERR("\t\tcurve type = %d\n", ppc->wType);
1053 gluTessEndContour(tess);
1054 goto error_in_list;
1057 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1058 (ppc->cpfx - 1) * sizeof(POINTFX));
1060 gluTessEndContour(tess);
1061 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1064 error_in_list:
1065 gluTessEndPolygon(tess);
1066 glEndList();
1067 LEAVE_GL();
1068 HeapFree(GetProcessHeap(), 0, buf);
1069 HeapFree(GetProcessHeap(), 0, vertices);
1072 error:
1073 DeleteObject(SelectObject(hdc, old_font));
1074 gluDeleteTess(tess);
1075 return TRUE;
1079 #else /* HAVE_GL_GLU_H */
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)
1091 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1092 return FALSE;
1095 #endif /* HAVE_GL_GLU_H */
1097 /***********************************************************************
1098 * wglUseFontOutlinesA (OPENGL32.@)
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)
1109 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1112 /***********************************************************************
1113 * wglUseFontOutlinesW (OPENGL32.@)
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)
1124 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1127 const GLubyte * internal_glGetString(GLenum name) {
1128 const char* GL_Extensions = NULL;
1130 if (GL_EXTENSIONS != name) {
1131 return glGetString(name);
1134 if (NULL == internal_gl_extensions) {
1135 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
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);
1145 while (*GL_Extensions != 0x00) {
1146 const char* Start = GL_Extensions;
1147 char ThisExtn[256];
1149 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1150 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1151 GL_Extensions++;
1153 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1154 TRACE("- %s:", ThisExtn);
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");
1165 if (*GL_Extensions == ' ') GL_Extensions++;
1169 return (const GLubyte *) internal_gl_extensions;
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
1183 if (NULL == ret && 24 == *params) {
1184 *params = 32;
1186 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
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;
1199 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1200 include all dependencies
1202 #ifndef SONAME_LIBGL
1203 #define SONAME_LIBGL "libGL.so"
1204 #endif
1206 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1208 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1209 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
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);
1216 memset(&wine_glx, 0, sizeof(wine_glx));
1218 if (!strcmp("1.2", server_glx_version)) {
1219 wine_glx.version = 2;
1220 } else {
1221 wine_glx.version = 3;
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");
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);
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");
1245 /* This is for brain-dead applications that use OpenGL functions before even
1246 creating a rendering context.... */
1247 static BOOL process_attach(void)
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;
1261 if (!root || !mod)
1263 ERR("X11DRV not loaded. Cannot create default context.\n");
1264 return FALSE;
1267 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1268 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1270 hdc = GetDC(0);
1271 default_display = get_display( hdc );
1272 ReleaseDC( 0, hdc );
1273 if (!default_display)
1275 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1276 return FALSE;
1279 ENTER_GL();
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 ))
1288 rootVisual = win_attr.visual;
1290 else
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) );
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();
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");
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);
1317 RegCloseKey(hkey);
1320 if (default_cx == NULL) {
1321 ERR("Could not create default context.\n");
1323 else
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);
1329 return TRUE;
1333 /**********************************************************************/
1335 static void process_detach(void)
1337 glXDestroyContext(default_display, default_cx);
1339 /* Do not leak memory... */
1340 wgl_ext_finalize_extensions();
1341 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1344 /***********************************************************************
1345 * OpenGL initialisation routine
1347 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1349 switch(reason)
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;
1359 return TRUE;