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
22 #include "wine/port.h"
37 #include "opengl_ext.h"
43 #include "wine/library.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
47 WINE_DECLARE_DEBUG_CHANNEL(opengl);
49 typedef struct wine_wgl_s {
50 HGLRC WINAPI (*p_wglCreateContext)(HDC hdc);
51 BOOL WINAPI (*p_wglDeleteContext)(HGLRC hglrc);
52 HGLRC WINAPI (*p_wglGetCurrentContext)(void);
53 HDC WINAPI (*p_wglGetCurrentDC)(void);
54 PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
55 BOOL WINAPI (*p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
56 BOOL WINAPI (*p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
57 BOOL WINAPI (*p_wglUseFontBitmapsA)(HDC hdc, DWORD first, DWORD count, DWORD listBase);
58 BOOL WINAPI (*p_wglUseFontBitmapsW)(HDC hdc, DWORD first, DWORD count, DWORD listBase);
60 void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
63 /** global wgl object */
64 static wine_wgl_t wine_wgl;
66 /* x11drv GDI escapes */
67 #define X11DRV_ESCAPE 6789
68 enum x11drv_escape_codes
70 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
71 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
72 X11DRV_GET_FONT, /* get current X font for a DC */
73 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
74 X11DRV_START_EXPOSURES, /* start graphics exposures */
75 X11DRV_END_EXPOSURES, /* end graphics exposures */
76 X11DRV_GET_DCE, /* get the DCE pointer */
77 X11DRV_SET_DCE, /* set the DCE pointer */
78 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
79 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
82 void (*wine_tsx11_lock_ptr)(void) = NULL;
83 void (*wine_tsx11_unlock_ptr)(void) = NULL;
85 static GLXContext default_cx = NULL;
86 static Display *default_display; /* display to use for default context */
88 static HMODULE opengl32_handle;
90 static void* (*p_glXGetProcAddressARB)(const GLubyte *);
92 static char internal_gl_disabled_extensions[512];
93 static char* internal_gl_extensions = NULL;
95 typedef struct wine_glcontext {
102 struct wine_glcontext *next;
103 struct wine_glcontext *prev;
108 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
110 if (curctx && curctx->do_escape)
112 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
113 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
116 wine_tsx11_lock_ptr();
120 /* retrieve the X display to use on a given DC */
121 inline static Display *get_display( HDC hdc )
124 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
126 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
127 sizeof(display), (LPSTR)&display )) display = NULL;
131 /***********************************************************************
132 * wglCreateContext (OPENGL32.@)
134 HGLRC WINAPI wglCreateContext(HDC hdc)
136 TRACE("(%p)\n", hdc);
137 return wine_wgl.p_wglCreateContext(hdc);
140 /***********************************************************************
141 * wglCreateLayerContext (OPENGL32.@)
143 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
145 TRACE("(%p,%d)\n", hdc, iLayerPlane);
147 if (iLayerPlane == 0) {
148 return wglCreateContext(hdc);
150 FIXME(" no handler for layer %d\n", iLayerPlane);
155 /***********************************************************************
156 * wglCopyContext (OPENGL32.@)
158 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
161 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
166 /***********************************************************************
167 * wglDeleteContext (OPENGL32.@)
169 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
171 TRACE("(%p)\n", hglrc);
172 return wine_wgl.p_wglDeleteContext(hglrc);
175 /***********************************************************************
176 * wglDescribeLayerPlane (OPENGL32.@)
178 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
182 LPLAYERPLANEDESCRIPTOR plpd) {
183 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
188 /***********************************************************************
189 * wglGetCurrentContext (OPENGL32.@)
191 HGLRC WINAPI wglGetCurrentContext(void) {
193 return wine_wgl.p_wglGetCurrentContext();
196 /***********************************************************************
197 * wglGetCurrentDC (OPENGL32.@)
199 HDC WINAPI wglGetCurrentDC(void) {
201 return wine_wgl.p_wglGetCurrentDC();
204 /***********************************************************************
205 * wglGetLayerPaletteEntries (OPENGL32.@)
207 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
211 const COLORREF *pcr) {
212 FIXME("(): stub !\n");
217 /***********************************************************************
218 * wglGetProcAddress (OPENGL32.@)
220 static int compar(const void *elt_a, const void *elt_b) {
221 return strcmp(((const OpenGL_extension *) elt_a)->name,
222 ((const OpenGL_extension *) elt_b)->name);
225 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
227 OpenGL_extension ext;
228 const OpenGL_extension *ext_ret;
230 TRACE("(%s)\n", lpszProc);
232 /* First, look if it's not already defined in the 'standard' OpenGL functions */
233 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
234 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
238 if (p_glXGetProcAddressARB == NULL) {
239 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
243 /* After that, search in the thunks to find the real name of the extension */
245 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
246 extension_registry_size, sizeof(OpenGL_extension), compar);
248 /* If nothing was found, we are looking for a WGL extension */
249 if (ext_ret == NULL) {
250 return wine_wgl.p_wglGetProcAddress(lpszProc);
251 } else { /* We are looking for an OpenGL extension */
252 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
254 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
257 /* After that, look at the extensions defined in the Linux OpenGL library */
258 if (local_func == NULL) {
262 /* Remove the 3 last letters (EXT, ARB, ...).
264 I know that some extensions have more than 3 letters (MESA, NV,
265 INTEL, ...), but this is only a stop-gap measure to fix buggy
266 OpenGL drivers (moreover, it is only useful for old 1.0 apps
267 that query the glBindTextureEXT extension).
269 memcpy(buf, glx_name, strlen(glx_name) - 3);
270 buf[strlen(glx_name) - 3] = '\0';
271 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
273 ret = GetProcAddress(opengl32_handle, buf);
275 TRACE(" found function in main OpenGL library (%p) !\n", ret);
277 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
282 TRACE(" returning function (%p)\n", ext_ret->func);
283 extension_funcs[ext_ret - extension_registry] = local_func;
285 return ext_ret->func;
290 /***********************************************************************
291 * wglMakeCurrent (OPENGL32.@)
293 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc) {
294 TRACE("hdc: (%p), hglrc: (%p)\n", hdc, hglrc);
295 return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
298 /***********************************************************************
299 * wglRealizeLayerPalette (OPENGL32.@)
301 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
309 /***********************************************************************
310 * wglSetLayerPaletteEntries (OPENGL32.@)
312 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
316 const COLORREF *pcr) {
317 FIXME("(): stub !\n");
322 /***********************************************************************
323 * wglShareLists (OPENGL32.@)
325 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
326 TRACE("(%p, %p)\n", hglrc1, hglrc2);
327 return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
330 /***********************************************************************
331 * wglSwapLayerBuffers (OPENGL32.@)
333 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
335 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
337 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
338 if (!SwapBuffers(hdc)) return FALSE;
339 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
343 WARN("Following layers unhandled : %08x\n", fuPlanes);
349 /***********************************************************************
350 * wglUseFontBitmapsA (OPENGL32.@)
352 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
357 TRACE("(%p, %ld, %ld, %ld)\n", hdc, first, count, listBase);
358 return wine_wgl.p_wglUseFontBitmapsA(hdc, first, count, listBase);
361 /***********************************************************************
362 * wglUseFontBitmapsW (OPENGL32.@)
364 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
369 TRACE("(%p, %ld, %ld, %ld)\n", hdc, first, count, listBase);
370 return wine_wgl.p_wglUseFontBitmapsW(hdc, first, count, listBase);
375 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
377 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
378 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
382 static void tess_callback_vertex(GLvoid *vertex)
384 GLdouble *dbl = vertex;
385 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
389 static void tess_callback_begin(GLenum which)
391 TRACE("%d\n", which);
395 static void tess_callback_end(void)
401 /***********************************************************************
402 * wglUseFontOutlines_common
404 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
411 LPGLYPHMETRICSFLOAT lpgmf,
415 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
418 HFONT old_font, unscaled_font;
422 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
423 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
430 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
431 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
432 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
436 if(!tess) return FALSE;
438 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
439 rc.left = rc.right = rc.bottom = 0;
441 DPtoLP(hdc, (POINT*)&rc, 2);
442 lf.lfHeight = -abs(rc.top - rc.bottom);
443 lf.lfOrientation = lf.lfEscapement = 0;
444 unscaled_font = CreateFontIndirectW(&lf);
445 old_font = SelectObject(hdc, unscaled_font);
447 for (glyph = first; glyph < first + count; glyph++)
452 TTPOLYGONHEADER *pph;
457 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
459 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
461 if(needed == GDI_ERROR)
464 buf = HeapAlloc(GetProcessHeap(), 0, needed);
465 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
468 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
470 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
472 TRACE("glyph %d\n", glyph);
476 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
477 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
478 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
479 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
480 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
481 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
483 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
484 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
489 glNewList(listBase++, GL_COMPILE);
490 gluTessBeginPolygon(tess, NULL);
492 pph = (TTPOLYGONHEADER*)buf;
493 while((BYTE*)pph < buf + needed)
495 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
497 gluTessBeginContour(tess);
499 fixed_to_double(pph->pfxStart, em_size, vertices);
500 gluTessVertex(tess, vertices, vertices);
503 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
504 while((char*)ppc < (char*)pph + pph->cb)
510 for(i = 0; i < ppc->cpfx; i++)
512 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
513 fixed_to_double(ppc->apfx[i], em_size, vertices);
514 gluTessVertex(tess, vertices, vertices);
519 case TT_PRIM_QSPLINE:
520 for(i = 0; i < ppc->cpfx/2; i++)
522 /* FIXME just connecting the control points for now */
523 TRACE("\t\tcurve %d,%d %d,%d\n",
524 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
525 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
526 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
527 gluTessVertex(tess, vertices, vertices);
529 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
530 gluTessVertex(tess, vertices, vertices);
535 ERR("\t\tcurve type = %d\n", ppc->wType);
536 gluTessEndContour(tess);
540 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
541 (ppc->cpfx - 1) * sizeof(POINTFX));
543 gluTessEndContour(tess);
544 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
548 gluTessEndPolygon(tess);
549 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
552 HeapFree(GetProcessHeap(), 0, buf);
553 HeapFree(GetProcessHeap(), 0, vertices);
557 DeleteObject(SelectObject(hdc, old_font));
563 #else /* HAVE_GL_GLU_H */
565 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
572 LPGLYPHMETRICSFLOAT lpgmf,
575 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
579 #endif /* HAVE_GL_GLU_H */
581 /***********************************************************************
582 * wglUseFontOutlinesA (OPENGL32.@)
584 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
591 LPGLYPHMETRICSFLOAT lpgmf)
593 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
596 /***********************************************************************
597 * wglUseFontOutlinesW (OPENGL32.@)
599 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
606 LPGLYPHMETRICSFLOAT lpgmf)
608 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
611 const GLubyte * internal_glGetString(GLenum name) {
612 const char* GL_Extensions = NULL;
614 if (GL_EXTENSIONS != name) {
615 return glGetString(name);
618 if (NULL == internal_gl_extensions) {
619 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
621 TRACE("GL_EXTENSIONS reported:\n");
622 if (NULL == GL_Extensions) {
623 ERR("GL_EXTENSIONS returns NULL\n");
626 size_t len = strlen(GL_Extensions);
627 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
629 while (*GL_Extensions != 0x00) {
630 const char* Start = GL_Extensions;
633 memset(ThisExtn, 0x00, sizeof(ThisExtn));
634 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
637 memcpy(ThisExtn, Start, (GL_Extensions - Start));
638 TRACE("- %s:", ThisExtn);
640 /* test if supported API is disabled by config */
641 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
642 strcat(internal_gl_extensions, " ");
643 strcat(internal_gl_extensions, ThisExtn);
646 TRACE(" deactived (by config)\n");
649 if (*GL_Extensions == ' ') GL_Extensions++;
653 return (const GLubyte *) internal_gl_extensions;
656 void internal_glGetIntegerv(GLenum pname, GLint* params) {
657 TRACE("pname: 0x%x, params %p\n", pname, params);
658 glGetIntegerv(pname, params);
659 /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
660 wine_wgl.p_wglGetIntegerv(pname, params);
664 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
665 include all dependencies
668 #define SONAME_LIBGL "libGL.so"
671 /* This is for brain-dead applications that use OpenGL functions before even
672 creating a rendering context.... */
673 static BOOL process_attach(void)
675 XWindowAttributes win_attr;
678 XVisualInfo template;
680 XVisualInfo *vis = NULL;
681 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
682 HMODULE mod = GetModuleHandleA( "winex11.drv" );
684 DWORD size = sizeof(internal_gl_disabled_extensions);
689 ERR("X11DRV not loaded. Cannot create default context.\n");
693 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
694 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
696 /* Load WGL function pointers from winex11.drv */
697 wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod, "wglCreateContext");
698 wine_wgl.p_wglDeleteContext = (void *)GetProcAddress(mod, "wglDeleteContext");
699 wine_wgl.p_wglGetCurrentContext = (void *)GetProcAddress(mod, "wglGetCurrentContext");
700 wine_wgl.p_wglGetCurrentDC = (void *)GetProcAddress(mod, "wglGetCurrentDC");
701 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
702 wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod, "wglMakeCurrent");
703 wine_wgl.p_wglShareLists = (void *)GetProcAddress(mod, "wglShareLists");
704 wine_wgl.p_wglUseFontBitmapsA = (void*)GetProcAddress(mod, "wglUseFontBitmapsA");
705 wine_wgl.p_wglUseFontBitmapsW = (void*)GetProcAddress(mod, "wglUseFontBitmapsW");
707 /* Interal WGL function */
708 wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
711 default_display = get_display( hdc );
713 if (!default_display)
715 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
721 /* Try to get the visual from the Root Window. We can't use the standard (presumably
722 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
723 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
724 with mismatched visuals. Note that the Root Window visual may not be double
725 buffered, so apps actually attempting to render this way may flicker */
726 if (XGetWindowAttributes( default_display, root, &win_attr ))
728 rootVisual = win_attr.visual;
732 /* Get the default visual, since we can't seem to get the attributes from the
733 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
734 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
737 template.visualid = XVisualIDFromVisual(rootVisual);
738 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
739 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
740 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
744 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
745 if (opengl_handle != NULL) {
746 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
747 wine_dlclose(opengl_handle, NULL, 0);
748 if (p_glXGetProcAddressARB == NULL)
749 TRACE("could not find glXGetProcAddressARB in libGL.\n");
752 internal_gl_disabled_extensions[0] = 0;
753 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
754 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
755 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
760 if (default_cx == NULL) {
761 ERR("Could not create default context.\n");
767 /**********************************************************************/
769 static void process_detach(void)
771 glXDestroyContext(default_display, default_cx);
773 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
776 /***********************************************************************
777 * OpenGL initialisation routine
779 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
783 case DLL_PROCESS_ATTACH:
784 opengl32_handle = hinst;
785 DisableThreadLibraryCalls(hinst);
786 return process_attach();
787 case DLL_PROCESS_DETACH: