advpack: Rewrite get_parameter to be able to handle an empty parameter.
[wine/testsucceed.git] / dlls / opengl32 / wgl.c
blobc7d3147c5b64c239cc22d7d5246cbfb55cb87365
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
98 return ret;
101 void enter_gl(void)
103 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
105 if (curctx && curctx->do_escape)
107 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
108 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
111 wine_tsx11_lock_ptr();
112 return;
115 static inline void free_context(Wine_GLContext *context)
117 if (context->next != NULL) context->next->prev = context->prev;
118 if (context->prev != NULL) context->prev->next = context->next;
119 else context_list = context->next;
121 HeapFree(GetProcessHeap(), 0, context);
124 static inline Wine_GLContext *alloc_context(void)
126 Wine_GLContext *ret;
128 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
130 ret->next = context_list;
131 if (context_list) context_list->prev = ret;
132 context_list = ret;
134 return ret;
137 inline static BOOL is_valid_context( Wine_GLContext *ctx )
139 Wine_GLContext *ptr;
140 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
141 return (ptr != NULL);
144 /* retrieve the X display to use on a given DC */
145 inline static Display *get_display( HDC hdc )
147 Display *display;
148 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
150 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
151 sizeof(display), (LPSTR)&display )) display = NULL;
152 return display;
156 /* retrieve the GLX drawable to use on a given DC */
157 inline static Drawable get_drawable( HDC hdc )
159 GLXDrawable drawable;
160 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
162 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
163 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
164 return drawable;
167 /** for use of wglGetCurrentReadDCARB */
168 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
170 Wine_GLContext *ret;
171 for (ret = context_list; ret; ret = ret->next) {
172 if (d == get_drawable( ret->hdc )) {
173 return ret->hdc;
176 return NULL;
179 /* retrieve the X font to use on a given DC */
180 inline static Font get_font( HDC hdc )
182 Font font;
183 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
185 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
186 sizeof(font), (LPSTR)&font )) font = 0;
187 return font;
191 /***********************************************************************
192 * wglCreateContext (OPENGL32.@)
194 HGLRC WINAPI wglCreateContext(HDC hdc)
196 Wine_GLContext *ret;
197 int num;
198 XVisualInfo template;
199 XVisualInfo *vis = NULL;
200 Display *display = get_display( hdc );
201 int hdcPF = GetPixelFormat(hdc);
202 GLXFBConfig cur_cfg;
204 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
206 /* First, get the visual in use by the X11DRV */
207 if (!display) return 0;
208 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
209 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
211 if (vis == NULL) {
212 ERR("NULL visual !!!\n");
213 /* Need to set errors here */
214 return NULL;
216 if (0 >= hdcPF) {
217 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
218 return NULL;
222 int nCfgs_fmt = 0;
223 GLXFBConfig* cfgs_fmt = NULL;
224 int value;
225 int gl_test = 0;
226 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
227 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
228 ERR("Cannot get FB Configs, expect problems.\n");
229 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
230 return NULL;
232 if (nCfgs_fmt < hdcPF) {
233 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
234 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
235 return NULL;
237 cur_cfg = cfgs_fmt[hdcPF - 1];
238 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
239 if (gl_test) {
240 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
241 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
242 return NULL;
244 XFree(cfgs_fmt);
247 /* The context will be allocated in the wglMakeCurrent call */
248 ENTER_GL();
249 ret = alloc_context();
250 LEAVE_GL();
251 ret->hdc = hdc;
252 ret->display = display;
253 ret->fb_conf = cur_cfg;
254 /*ret->vis = vis;*/
255 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
257 TRACE(" creating context %p (GL context creation delayed)\n", ret);
258 return (HGLRC) ret;
261 /***********************************************************************
262 * wglCreateLayerContext (OPENGL32.@)
264 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
265 int iLayerPlane) {
266 TRACE("(%p,%d)\n", hdc, iLayerPlane);
268 if (iLayerPlane == 0) {
269 return wglCreateContext(hdc);
271 FIXME(" no handler for layer %d\n", iLayerPlane);
273 return NULL;
276 /***********************************************************************
277 * wglCopyContext (OPENGL32.@)
279 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
280 HGLRC hglrcDst,
281 UINT mask) {
282 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
284 return FALSE;
287 /***********************************************************************
288 * wglDeleteContext (OPENGL32.@)
290 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
292 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
293 BOOL ret = TRUE;
295 TRACE("(%p)\n", hglrc);
297 ENTER_GL();
298 /* A game (Half Life not to name it) deletes twice the same context,
299 * so make sure it is valid first */
300 if (is_valid_context( ctx ))
302 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
303 free_context(ctx);
305 else
307 WARN("Error deleting context !\n");
308 SetLastError(ERROR_INVALID_HANDLE);
309 ret = FALSE;
311 LEAVE_GL();
313 return ret;
316 /***********************************************************************
317 * wglDescribeLayerPlane (OPENGL32.@)
319 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
320 int iPixelFormat,
321 int iLayerPlane,
322 UINT nBytes,
323 LPLAYERPLANEDESCRIPTOR plpd) {
324 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
326 return FALSE;
329 /***********************************************************************
330 * wglGetCurrentContext (OPENGL32.@)
332 HGLRC WINAPI wglGetCurrentContext(void) {
333 GLXContext gl_ctx;
334 Wine_GLContext *ret;
336 TRACE("()\n");
338 ENTER_GL();
339 gl_ctx = glXGetCurrentContext();
340 ret = get_context_from_GLXContext(gl_ctx);
341 LEAVE_GL();
343 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
345 return (HGLRC)ret;
348 /***********************************************************************
349 * wglGetCurrentDC (OPENGL32.@)
351 HDC WINAPI wglGetCurrentDC(void) {
352 GLXContext gl_ctx;
353 Wine_GLContext *ret;
355 TRACE("()\n");
357 ENTER_GL();
358 gl_ctx = glXGetCurrentContext();
359 ret = get_context_from_GLXContext(gl_ctx);
360 LEAVE_GL();
362 if (ret) {
363 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
364 return ret->hdc;
365 } else {
366 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
367 return 0;
371 /***********************************************************************
372 * wglGetLayerPaletteEntries (OPENGL32.@)
374 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
375 int iLayerPlane,
376 int iStart,
377 int cEntries,
378 const COLORREF *pcr) {
379 FIXME("(): stub !\n");
381 return 0;
384 /***********************************************************************
385 * wglGetProcAddress (OPENGL32.@)
387 static int compar(const void *elt_a, const void *elt_b) {
388 return strcmp(((const OpenGL_extension *) elt_a)->name,
389 ((const OpenGL_extension *) elt_b)->name);
392 static int wgl_compar(const void *elt_a, const void *elt_b) {
393 return strcmp(((const WGL_extension *) elt_a)->func_name,
394 ((const WGL_extension *) elt_b)->func_name);
397 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
398 void *local_func;
399 OpenGL_extension ext;
400 OpenGL_extension *ext_ret;
402 TRACE("(%s)\n", lpszProc);
404 /* First, look if it's not already defined in the 'standard' OpenGL functions */
405 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
406 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
407 return local_func;
410 if (p_glXGetProcAddressARB == NULL) {
411 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
412 return NULL;
415 /* After that, search in the thunks to find the real name of the extension */
416 ext.name = (char *) lpszProc;
417 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
418 extension_registry_size, sizeof(OpenGL_extension), compar);
420 if (ext_ret == NULL) {
421 WGL_extension wgl_ext, *wgl_ext_ret;
423 /* Try to find the function in the WGL extensions ... */
424 wgl_ext.func_name = (char *) lpszProc;
425 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
426 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
428 if (wgl_ext_ret == NULL) {
429 /* Some sanity checks :-) */
430 ENTER_GL();
431 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
432 LEAVE_GL();
433 if (local_func != NULL) {
434 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
435 return NULL;
438 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
439 return NULL;
440 } else {
441 void *ret = NULL;
443 if (wgl_ext_ret->func_init != NULL) {
444 const char *err_msg;
445 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
446 wgl_ext_ret->context)) == NULL) {
447 ret = wgl_ext_ret->func_address;
448 } else {
449 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
450 return NULL;
452 } else {
453 ret = wgl_ext_ret->func_address;
456 if (ret)
457 TRACE(" returning WGL function (%p)\n", ret);
458 return ret;
460 } else {
461 ENTER_GL();
462 local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
463 LEAVE_GL();
465 /* After that, look at the extensions defined in the Linux OpenGL library */
466 if (local_func == NULL) {
467 char buf[256];
468 void *ret = NULL;
470 /* Remove the 3 last letters (EXT, ARB, ...).
472 I know that some extensions have more than 3 letters (MESA, NV,
473 INTEL, ...), but this is only a stop-gap measure to fix buggy
474 OpenGL drivers (moreover, it is only useful for old 1.0 apps
475 that query the glBindTextureEXT extension).
477 memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
478 buf[strlen(ext_ret->glx_name) - 3] = '\0';
479 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
481 ret = GetProcAddress(opengl32_handle, buf);
482 if (ret != NULL) {
483 TRACE(" found function in main OpenGL library (%p) !\n", ret);
484 } else {
485 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
488 return ret;
489 } else {
490 TRACE(" returning function (%p)\n", ext_ret->func);
491 *(ext_ret->func_ptr) = local_func;
493 return ext_ret->func;
498 static int describeContext(Wine_GLContext* ctx) {
499 int tmp;
500 int ctx_vis_id;
501 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
502 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
503 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
504 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
505 TRACE(" - VISUAL_ID 0x%x\n", tmp);
506 ctx_vis_id = tmp;
507 return ctx_vis_id;
510 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
511 int tmp;
512 int draw_vis_id;
513 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
514 /** glXQueryDrawable not available so returns not supported */
515 return -1;
517 TRACE(" Drawable %p have :\n", (void*) drawable);
518 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
519 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
520 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
521 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
522 draw_vis_id = tmp;
523 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
524 TRACE(" - WIDTH as %d\n", tmp);
525 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
526 TRACE(" - HEIGHT as %d\n", tmp);
527 return draw_vis_id;
530 /***********************************************************************
531 * wglMakeCurrent (OPENGL32.@)
533 BOOL WINAPI wglMakeCurrent(HDC hdc,
534 HGLRC hglrc) {
535 BOOL ret;
536 DWORD type = GetObjectType(hdc);
538 TRACE("(%p,%p)\n", hdc, hglrc);
540 ENTER_GL();
541 if (hglrc == NULL) {
542 ret = glXMakeCurrent(default_display, None, NULL);
543 NtCurrentTeb()->glContext = NULL;
544 } else {
545 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
546 Drawable drawable = get_drawable( hdc );
547 if (ctx->ctx == NULL) {
548 int draw_vis_id, ctx_vis_id;
549 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
550 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
551 draw_vis_id = describeDrawable(ctx, drawable);
552 ctx_vis_id = describeContext(ctx);
554 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
556 * Inherits from root window so reuse desktop visual
558 XVisualInfo template;
559 XVisualInfo *vis;
560 int num;
561 template.visualid = visualid;
562 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
564 TRACE(" Creating GLX Context\n");
565 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
566 } else {
567 TRACE(" Creating GLX Context\n");
568 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
570 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
572 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
573 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
574 NtCurrentTeb()->glContext = ctx;
575 if(ret && type == OBJ_MEMDC)
577 ctx->do_escape = TRUE;
578 glDrawBuffer(GL_FRONT_LEFT);
581 LEAVE_GL();
582 TRACE(" returning %s\n", (ret ? "True" : "False"));
583 return ret;
586 /***********************************************************************
587 * wglMakeContextCurrentARB (OPENGL32.@)
589 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
591 BOOL ret;
592 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
594 ENTER_GL();
595 if (hglrc == NULL) {
596 ret = glXMakeCurrent(default_display, None, NULL);
597 } else {
598 if (NULL == wine_glx.p_glXMakeContextCurrent) {
599 ret = FALSE;
600 } else {
601 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
602 Drawable d_draw = get_drawable( hDrawDC );
603 Drawable d_read = get_drawable( hReadDC );
605 if (ctx->ctx == NULL) {
606 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
607 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
609 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
612 LEAVE_GL();
614 TRACE(" returning %s\n", (ret ? "True" : "False"));
615 return ret;
618 /***********************************************************************
619 * wglGetCurrentReadDCARB (OPENGL32.@)
621 HDC WINAPI wglGetCurrentReadDCARB(void)
623 GLXDrawable gl_d;
624 HDC ret;
626 TRACE("()\n");
628 ENTER_GL();
629 gl_d = glXGetCurrentReadDrawable();
630 ret = get_hdc_from_Drawable(gl_d);
631 LEAVE_GL();
633 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
634 return ret;
639 /***********************************************************************
640 * wglRealizeLayerPalette (OPENGL32.@)
642 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
643 int iLayerPlane,
644 BOOL bRealize) {
645 FIXME("()\n");
647 return FALSE;
650 /***********************************************************************
651 * wglSetLayerPaletteEntries (OPENGL32.@)
653 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
654 int iLayerPlane,
655 int iStart,
656 int cEntries,
657 const COLORREF *pcr) {
658 FIXME("(): stub !\n");
660 return 0;
663 /***********************************************************************
664 * wglShareLists (OPENGL32.@)
666 BOOL WINAPI wglShareLists(HGLRC hglrc1,
667 HGLRC hglrc2) {
668 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
669 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
671 TRACE("(%p, %p)\n", org, dest);
673 if (NULL != dest && dest->ctx != NULL) {
674 ERR("Could not share display lists, context already created !\n");
675 return FALSE;
676 } else {
677 if (org->ctx == NULL) {
678 ENTER_GL();
679 describeContext(org);
680 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
681 LEAVE_GL();
682 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
684 if (NULL != dest) {
685 ENTER_GL();
686 describeContext(dest);
687 /* Create the destination context with display lists shared */
688 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
689 LEAVE_GL();
690 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
691 return TRUE;
694 return FALSE;
697 /***********************************************************************
698 * wglSwapLayerBuffers (OPENGL32.@)
700 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
701 UINT fuPlanes) {
702 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
704 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
705 if (!SwapBuffers(hdc)) return FALSE;
706 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
709 if (fuPlanes) {
710 WARN("Following layers unhandled : %08x\n", fuPlanes);
713 return TRUE;
716 static BOOL internal_wglUseFontBitmaps(HDC hdc,
717 DWORD first,
718 DWORD count,
719 DWORD listBase,
720 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
722 /* We are running using client-side rendering fonts... */
723 GLYPHMETRICS gm;
724 unsigned int glyph;
725 int size = 0;
726 void *bitmap = NULL, *gl_bitmap = NULL;
727 int org_alignment;
729 ENTER_GL();
730 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
731 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
732 LEAVE_GL();
734 for (glyph = first; glyph < first + count; glyph++) {
735 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
736 int height, width_int;
738 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
739 if (needed_size == GDI_ERROR) {
740 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
741 goto error;
742 } else {
743 TRACE(" - needed size : %d\n", needed_size);
746 if (needed_size > size) {
747 size = needed_size;
748 HeapFree(GetProcessHeap(), 0, bitmap);
749 HeapFree(GetProcessHeap(), 0, gl_bitmap);
750 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
751 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
753 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
754 if (TRACE_ON(opengl)) {
755 unsigned int height, width, bitmask;
756 unsigned char *bitmap_ = (unsigned char *) bitmap;
758 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
759 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
760 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
761 if (needed_size != 0) {
762 TRACE(" - bitmap :\n");
763 for (height = 0; height < gm.gmBlackBoxY; height++) {
764 TRACE(" ");
765 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
766 if (bitmask == 0) {
767 bitmap_ += 1;
768 bitmask = 0x80;
770 if (*bitmap_ & bitmask)
771 TRACE("*");
772 else
773 TRACE(" ");
775 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
776 TRACE("\n");
781 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
782 * glyph for it to be drawn properly.
784 if (needed_size != 0) {
785 width_int = (gm.gmBlackBoxX + 31) / 32;
786 for (height = 0; height < gm.gmBlackBoxY; height++) {
787 int width;
788 for (width = 0; width < width_int; width++) {
789 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
790 ((int *) bitmap)[height * width_int + width];
795 ENTER_GL();
796 glNewList(listBase++, GL_COMPILE);
797 if (needed_size != 0) {
798 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
799 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
800 gm.gmCellIncX, gm.gmCellIncY,
801 gl_bitmap);
802 } else {
803 /* This is the case of 'empty' glyphs like the space character */
804 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
806 glEndList();
807 LEAVE_GL();
810 ENTER_GL();
811 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
812 LEAVE_GL();
814 HeapFree(GetProcessHeap(), 0, bitmap);
815 HeapFree(GetProcessHeap(), 0, gl_bitmap);
816 return TRUE;
818 error:
819 ENTER_GL();
820 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
821 LEAVE_GL();
823 HeapFree(GetProcessHeap(), 0, bitmap);
824 HeapFree(GetProcessHeap(), 0, gl_bitmap);
825 return FALSE;
828 /***********************************************************************
829 * wglUseFontBitmapsA (OPENGL32.@)
831 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
832 DWORD first,
833 DWORD count,
834 DWORD listBase)
836 Font fid = get_font( hdc );
838 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
840 if (fid == 0) {
841 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
844 ENTER_GL();
845 /* I assume that the glyphs are at the same position for X and for Windows */
846 glXUseXFont(fid, first, count, listBase);
847 LEAVE_GL();
848 return TRUE;
851 /***********************************************************************
852 * wglUseFontBitmapsW (OPENGL32.@)
854 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
855 DWORD first,
856 DWORD count,
857 DWORD listBase)
859 Font fid = get_font( hdc );
861 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
863 if (fid == 0) {
864 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
867 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
869 ENTER_GL();
870 /* I assume that the glyphs are at the same position for X and for Windows */
871 glXUseXFont(fid, first, count, listBase);
872 LEAVE_GL();
873 return TRUE;
876 #ifdef HAVE_GL_GLU_H
878 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
880 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
881 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
882 vertex[2] = 0.0;
885 static void tess_callback_vertex(GLvoid *vertex)
887 GLdouble *dbl = vertex;
888 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
889 glVertex3dv(vertex);
892 static void tess_callback_begin(GLenum which)
894 TRACE("%d\n", which);
895 glBegin(which);
898 static void tess_callback_end(void)
900 TRACE("\n");
901 glEnd();
904 /***********************************************************************
905 * wglUseFontOutlines_common
907 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
908 DWORD first,
909 DWORD count,
910 DWORD listBase,
911 FLOAT deviation,
912 FLOAT extrusion,
913 int format,
914 LPGLYPHMETRICSFLOAT lpgmf,
915 BOOL unicode)
917 UINT glyph;
918 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
919 GLUtesselator *tess;
920 LOGFONTW lf;
921 HFONT old_font, unscaled_font;
922 UINT em_size = 1024;
923 RECT rc;
925 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
926 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
929 ENTER_GL();
930 tess = gluNewTess();
931 if(tess)
933 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
934 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
935 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
937 LEAVE_GL();
939 if(!tess) return FALSE;
941 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
942 rc.left = rc.right = rc.bottom = 0;
943 rc.top = em_size;
944 DPtoLP(hdc, (POINT*)&rc, 2);
945 lf.lfHeight = -abs(rc.top - rc.bottom);
946 lf.lfOrientation = lf.lfEscapement = 0;
947 unscaled_font = CreateFontIndirectW(&lf);
948 old_font = SelectObject(hdc, unscaled_font);
950 for (glyph = first; glyph < first + count; glyph++)
952 DWORD needed;
953 GLYPHMETRICS gm;
954 BYTE *buf;
955 TTPOLYGONHEADER *pph;
956 TTPOLYCURVE *ppc;
957 GLdouble *vertices;
959 if(unicode)
960 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
961 else
962 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
964 if(needed == GDI_ERROR)
965 goto error;
967 buf = HeapAlloc(GetProcessHeap(), 0, needed);
968 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
970 if(unicode)
971 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
972 else
973 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
975 TRACE("glyph %d\n", glyph);
977 if(lpgmf)
979 lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
980 lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
981 lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
982 lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
983 lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
984 lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
985 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
986 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
987 lpgmf++;
990 ENTER_GL();
991 glNewList(listBase++, GL_COMPILE);
992 gluTessBeginPolygon(tess, NULL);
994 pph = (TTPOLYGONHEADER*)buf;
995 while((BYTE*)pph < buf + needed)
997 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
999 gluTessBeginContour(tess);
1001 fixed_to_double(pph->pfxStart, em_size, vertices);
1002 gluTessVertex(tess, vertices, vertices);
1003 vertices += 3;
1005 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1006 while((char*)ppc < (char*)pph + pph->cb)
1008 int i;
1010 switch(ppc->wType) {
1011 case TT_PRIM_LINE:
1012 for(i = 0; i < ppc->cpfx; i++)
1014 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1015 fixed_to_double(ppc->apfx[i], em_size, vertices);
1016 gluTessVertex(tess, vertices, vertices);
1017 vertices += 3;
1019 break;
1021 case TT_PRIM_QSPLINE:
1022 for(i = 0; i < ppc->cpfx/2; i++)
1024 /* FIXME just connecting the control points for now */
1025 TRACE("\t\tcurve %d,%d %d,%d\n",
1026 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1027 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1028 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1029 gluTessVertex(tess, vertices, vertices);
1030 vertices += 3;
1031 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1032 gluTessVertex(tess, vertices, vertices);
1033 vertices += 3;
1035 break;
1036 default:
1037 ERR("\t\tcurve type = %d\n", ppc->wType);
1038 gluTessEndContour(tess);
1039 goto error_in_list;
1042 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1043 (ppc->cpfx - 1) * sizeof(POINTFX));
1045 gluTessEndContour(tess);
1046 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1049 error_in_list:
1050 gluTessEndPolygon(tess);
1051 glEndList();
1052 LEAVE_GL();
1053 HeapFree(GetProcessHeap(), 0, buf);
1054 HeapFree(GetProcessHeap(), 0, vertices);
1057 error:
1058 DeleteObject(SelectObject(hdc, old_font));
1059 gluDeleteTess(tess);
1060 return TRUE;
1064 #else /* HAVE_GL_GLU_H */
1066 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1067 DWORD first,
1068 DWORD count,
1069 DWORD listBase,
1070 FLOAT deviation,
1071 FLOAT extrusion,
1072 int format,
1073 LPGLYPHMETRICSFLOAT lpgmf,
1074 BOOL unicode)
1076 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1077 return FALSE;
1080 #endif /* HAVE_GL_GLU_H */
1082 /***********************************************************************
1083 * wglUseFontOutlinesA (OPENGL32.@)
1085 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1086 DWORD first,
1087 DWORD count,
1088 DWORD listBase,
1089 FLOAT deviation,
1090 FLOAT extrusion,
1091 int format,
1092 LPGLYPHMETRICSFLOAT lpgmf)
1094 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1097 /***********************************************************************
1098 * wglUseFontOutlinesW (OPENGL32.@)
1100 BOOL WINAPI wglUseFontOutlinesW(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, TRUE);
1112 const GLubyte * internal_glGetString(GLenum name) {
1113 const char* GL_Extensions = NULL;
1115 if (GL_EXTENSIONS != name) {
1116 return glGetString(name);
1119 if (NULL == internal_gl_extensions) {
1120 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1122 TRACE("GL_EXTENSIONS reported:\n");
1123 if (NULL == GL_Extensions) {
1124 ERR("GL_EXTENSIONS returns NULL\n");
1125 return NULL;
1126 } else {
1127 size_t len = strlen(GL_Extensions);
1128 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1130 while (*GL_Extensions != 0x00) {
1131 const char* Start = GL_Extensions;
1132 char ThisExtn[256];
1134 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1135 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1136 GL_Extensions++;
1138 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1139 TRACE("- %s:", ThisExtn);
1141 /* test if supported API is disabled by config */
1142 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1143 strcat(internal_gl_extensions, " ");
1144 strcat(internal_gl_extensions, ThisExtn);
1145 TRACE(" active\n");
1146 } else {
1147 TRACE(" deactived (by config)\n");
1150 if (*GL_Extensions == ' ') GL_Extensions++;
1154 return (const GLubyte *) internal_gl_extensions;
1157 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1158 glGetIntegerv(pname, params);
1159 if (pname == GL_DEPTH_BITS) {
1160 GLXContext gl_ctx = glXGetCurrentContext();
1161 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1162 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1163 /**
1164 * if we cannot find a Wine Context
1165 * we only have the default wine desktop context,
1166 * so if we have only a 24 depth say we have 32
1168 if (NULL == ret && 24 == *params) {
1169 *params = 32;
1171 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1173 if (pname == GL_ALPHA_BITS) {
1174 GLint tmp;
1175 GLXContext gl_ctx = glXGetCurrentContext();
1176 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1177 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1178 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1179 *params = tmp;
1184 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1185 include all dependencies
1187 #ifndef SONAME_LIBGL
1188 #define SONAME_LIBGL "libGL.so"
1189 #endif
1191 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1193 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1194 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1196 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1197 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1198 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1201 memset(&wine_glx, 0, sizeof(wine_glx));
1203 if (!strcmp("1.2", server_glx_version)) {
1204 wine_glx.version = 2;
1205 } else {
1206 wine_glx.version = 3;
1209 if (2 < wine_glx.version) {
1210 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1211 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1212 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1214 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1215 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1216 } else {
1217 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1218 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1219 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1220 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1221 } else {
1222 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1225 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1226 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1227 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1230 /* This is for brain-dead applications that use OpenGL functions before even
1231 creating a rendering context.... */
1232 static BOOL process_attach(void)
1234 XWindowAttributes win_attr;
1235 Visual *rootVisual;
1236 int num;
1237 XVisualInfo template;
1238 HDC hdc;
1239 XVisualInfo *vis = NULL;
1240 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1241 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1242 void *opengl_handle;
1243 DWORD size = sizeof(internal_gl_disabled_extensions);
1244 HKEY hkey = 0;
1246 if (!root || !mod)
1248 ERR("X11DRV not loaded. Cannot create default context.\n");
1249 return FALSE;
1252 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1253 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1255 hdc = GetDC(0);
1256 default_display = get_display( hdc );
1257 ReleaseDC( 0, hdc );
1258 if (!default_display)
1260 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1261 return FALSE;
1264 ENTER_GL();
1266 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1267 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1268 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1269 with mismatched visuals. Note that the Root Window visual may not be double
1270 buffered, so apps actually attempting to render this way may flicker */
1271 if (XGetWindowAttributes( default_display, root, &win_attr ))
1273 rootVisual = win_attr.visual;
1275 else
1277 /* Get the default visual, since we can't seem to get the attributes from the
1278 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1279 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1282 template.visualid = XVisualIDFromVisual(rootVisual);
1283 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1284 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1285 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1286 XFree(vis);
1287 LEAVE_GL();
1289 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1290 if (opengl_handle != NULL) {
1291 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1292 wine_dlclose(opengl_handle, NULL, 0);
1293 if (p_glXGetProcAddressARB == NULL)
1294 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1297 internal_gl_disabled_extensions[0] = 0;
1298 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1299 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1300 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1302 RegCloseKey(hkey);
1305 if (default_cx == NULL) {
1306 ERR("Could not create default context.\n");
1308 else
1310 /* After context initialize also the list of supported WGL extensions. */
1311 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1312 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1314 return TRUE;
1318 /**********************************************************************/
1320 static void process_detach(void)
1322 glXDestroyContext(default_display, default_cx);
1324 /* Do not leak memory... */
1325 wgl_ext_finalize_extensions();
1326 if (NULL != internal_gl_extensions) {
1327 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1331 /***********************************************************************
1332 * OpenGL initialisation routine
1334 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1336 switch(reason)
1338 case DLL_PROCESS_ATTACH:
1339 opengl32_handle = hinst;
1340 DisableThreadLibraryCalls(hinst);
1341 return process_attach();
1342 case DLL_PROCESS_DETACH:
1343 process_detach();
1344 break;
1346 return TRUE;