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 BOOL WINAPI (*p_wglDeleteContext)(HGLRC hglrc);
51 HGLRC WINAPI (*p_wglGetCurrentContext)(void);
52 HDC WINAPI (*p_wglGetCurrentDC)(void);
53 PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
54 BOOL WINAPI (*p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
56 void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
59 /** global wgl object */
60 static wine_wgl_t wine_wgl;
62 /* x11drv GDI escapes */
63 #define X11DRV_ESCAPE 6789
64 enum x11drv_escape_codes
66 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
67 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
68 X11DRV_GET_FONT, /* get current X font for a DC */
69 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
70 X11DRV_START_EXPOSURES, /* start graphics exposures */
71 X11DRV_END_EXPOSURES, /* end graphics exposures */
72 X11DRV_GET_DCE, /* get the DCE pointer */
73 X11DRV_SET_DCE, /* set the DCE pointer */
74 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
75 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
78 void (*wine_tsx11_lock_ptr)(void) = NULL;
79 void (*wine_tsx11_unlock_ptr)(void) = NULL;
81 static GLXContext default_cx = NULL;
82 static Display *default_display; /* display to use for default context */
84 static HMODULE opengl32_handle;
86 static void* (*p_glXGetProcAddressARB)(const GLubyte *);
88 static char internal_gl_disabled_extensions[512];
89 static char* internal_gl_extensions = NULL;
91 typedef struct wine_glcontext {
98 struct wine_glcontext *next;
99 struct wine_glcontext *prev;
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();
116 /* retrieve the X display to use on a given DC */
117 inline static Display *get_display( HDC hdc )
120 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
122 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
123 sizeof(display), (LPSTR)&display )) display = NULL;
127 /***********************************************************************
128 * wglCreateLayerContext (OPENGL32.@)
130 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
132 TRACE("(%p,%d)\n", hdc, iLayerPlane);
134 if (iLayerPlane == 0) {
135 return wglCreateContext(hdc);
137 FIXME(" no handler for layer %d\n", iLayerPlane);
142 /***********************************************************************
143 * wglCopyContext (OPENGL32.@)
145 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
148 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
153 /***********************************************************************
154 * wglDeleteContext (OPENGL32.@)
156 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
158 TRACE("(%p)\n", hglrc);
159 return wine_wgl.p_wglDeleteContext(hglrc);
162 /***********************************************************************
163 * wglDescribeLayerPlane (OPENGL32.@)
165 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
169 LPLAYERPLANEDESCRIPTOR plpd) {
170 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
175 /***********************************************************************
176 * wglGetCurrentContext (OPENGL32.@)
178 HGLRC WINAPI wglGetCurrentContext(void) {
180 return wine_wgl.p_wglGetCurrentContext();
183 /***********************************************************************
184 * wglGetCurrentDC (OPENGL32.@)
186 HDC WINAPI wglGetCurrentDC(void) {
188 return wine_wgl.p_wglGetCurrentDC();
191 /***********************************************************************
192 * wglGetLayerPaletteEntries (OPENGL32.@)
194 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
198 const COLORREF *pcr) {
199 FIXME("(): stub !\n");
204 /***********************************************************************
205 * wglGetProcAddress (OPENGL32.@)
207 static int compar(const void *elt_a, const void *elt_b) {
208 return strcmp(((const OpenGL_extension *) elt_a)->name,
209 ((const OpenGL_extension *) elt_b)->name);
212 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
214 OpenGL_extension ext;
215 const OpenGL_extension *ext_ret;
217 TRACE("(%s)\n", lpszProc);
219 /* First, look if it's not already defined in the 'standard' OpenGL functions */
220 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
221 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
225 if (p_glXGetProcAddressARB == NULL) {
226 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
230 /* After that, search in the thunks to find the real name of the extension */
232 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
233 extension_registry_size, sizeof(OpenGL_extension), compar);
235 /* If nothing was found, we are looking for a WGL extension */
236 if (ext_ret == NULL) {
237 return wine_wgl.p_wglGetProcAddress(lpszProc);
238 } else { /* We are looking for an OpenGL extension */
239 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
241 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
244 /* After that, look at the extensions defined in the Linux OpenGL library */
245 if (local_func == NULL) {
249 /* Remove the 3 last letters (EXT, ARB, ...).
251 I know that some extensions have more than 3 letters (MESA, NV,
252 INTEL, ...), but this is only a stop-gap measure to fix buggy
253 OpenGL drivers (moreover, it is only useful for old 1.0 apps
254 that query the glBindTextureEXT extension).
256 memcpy(buf, glx_name, strlen(glx_name) - 3);
257 buf[strlen(glx_name) - 3] = '\0';
258 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
260 ret = GetProcAddress(opengl32_handle, buf);
262 TRACE(" found function in main OpenGL library (%p) !\n", ret);
264 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
269 TRACE(" returning function (%p)\n", ext_ret->func);
270 extension_funcs[ext_ret - extension_registry] = local_func;
272 return ext_ret->func;
277 /***********************************************************************
278 * wglRealizeLayerPalette (OPENGL32.@)
280 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
288 /***********************************************************************
289 * wglSetLayerPaletteEntries (OPENGL32.@)
291 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
295 const COLORREF *pcr) {
296 FIXME("(): stub !\n");
301 /***********************************************************************
302 * wglShareLists (OPENGL32.@)
304 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
305 TRACE("(%p, %p)\n", hglrc1, hglrc2);
306 return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
309 /***********************************************************************
310 * wglSwapLayerBuffers (OPENGL32.@)
312 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
314 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
316 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
317 if (!SwapBuffers(hdc)) return FALSE;
318 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
322 WARN("Following layers unhandled : %08x\n", fuPlanes);
330 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
332 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
333 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
337 static void tess_callback_vertex(GLvoid *vertex)
339 GLdouble *dbl = vertex;
340 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
344 static void tess_callback_begin(GLenum which)
346 TRACE("%d\n", which);
350 static void tess_callback_end(void)
356 /***********************************************************************
357 * wglUseFontOutlines_common
359 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
366 LPGLYPHMETRICSFLOAT lpgmf,
370 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
373 HFONT old_font, unscaled_font;
377 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
378 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
385 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
386 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
387 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
391 if(!tess) return FALSE;
393 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
394 rc.left = rc.right = rc.bottom = 0;
396 DPtoLP(hdc, (POINT*)&rc, 2);
397 lf.lfHeight = -abs(rc.top - rc.bottom);
398 lf.lfOrientation = lf.lfEscapement = 0;
399 unscaled_font = CreateFontIndirectW(&lf);
400 old_font = SelectObject(hdc, unscaled_font);
402 for (glyph = first; glyph < first + count; glyph++)
407 TTPOLYGONHEADER *pph;
412 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
414 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
416 if(needed == GDI_ERROR)
419 buf = HeapAlloc(GetProcessHeap(), 0, needed);
420 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
423 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
425 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
427 TRACE("glyph %d\n", glyph);
431 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
432 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
433 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
434 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
435 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
436 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
438 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
439 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
444 glNewList(listBase++, GL_COMPILE);
445 gluTessBeginPolygon(tess, NULL);
447 pph = (TTPOLYGONHEADER*)buf;
448 while((BYTE*)pph < buf + needed)
450 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
452 gluTessBeginContour(tess);
454 fixed_to_double(pph->pfxStart, em_size, vertices);
455 gluTessVertex(tess, vertices, vertices);
458 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
459 while((char*)ppc < (char*)pph + pph->cb)
465 for(i = 0; i < ppc->cpfx; i++)
467 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
468 fixed_to_double(ppc->apfx[i], em_size, vertices);
469 gluTessVertex(tess, vertices, vertices);
474 case TT_PRIM_QSPLINE:
475 for(i = 0; i < ppc->cpfx/2; i++)
477 /* FIXME just connecting the control points for now */
478 TRACE("\t\tcurve %d,%d %d,%d\n",
479 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
480 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
481 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
482 gluTessVertex(tess, vertices, vertices);
484 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
485 gluTessVertex(tess, vertices, vertices);
490 ERR("\t\tcurve type = %d\n", ppc->wType);
491 gluTessEndContour(tess);
495 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
496 (ppc->cpfx - 1) * sizeof(POINTFX));
498 gluTessEndContour(tess);
499 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
503 gluTessEndPolygon(tess);
504 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
507 HeapFree(GetProcessHeap(), 0, buf);
508 HeapFree(GetProcessHeap(), 0, vertices);
512 DeleteObject(SelectObject(hdc, old_font));
518 #else /* HAVE_GL_GLU_H */
520 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
527 LPGLYPHMETRICSFLOAT lpgmf,
530 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
534 #endif /* HAVE_GL_GLU_H */
536 /***********************************************************************
537 * wglUseFontOutlinesA (OPENGL32.@)
539 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
546 LPGLYPHMETRICSFLOAT lpgmf)
548 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
551 /***********************************************************************
552 * wglUseFontOutlinesW (OPENGL32.@)
554 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
561 LPGLYPHMETRICSFLOAT lpgmf)
563 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
566 const GLubyte * internal_glGetString(GLenum name) {
567 const char* GL_Extensions = NULL;
569 if (GL_EXTENSIONS != name) {
570 return glGetString(name);
573 if (NULL == internal_gl_extensions) {
574 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
576 TRACE("GL_EXTENSIONS reported:\n");
577 if (NULL == GL_Extensions) {
578 ERR("GL_EXTENSIONS returns NULL\n");
581 size_t len = strlen(GL_Extensions);
582 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
584 while (*GL_Extensions != 0x00) {
585 const char* Start = GL_Extensions;
588 memset(ThisExtn, 0x00, sizeof(ThisExtn));
589 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
592 memcpy(ThisExtn, Start, (GL_Extensions - Start));
593 TRACE("- %s:", ThisExtn);
595 /* test if supported API is disabled by config */
596 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
597 strcat(internal_gl_extensions, " ");
598 strcat(internal_gl_extensions, ThisExtn);
601 TRACE(" deactived (by config)\n");
604 if (*GL_Extensions == ' ') GL_Extensions++;
608 return (const GLubyte *) internal_gl_extensions;
611 void internal_glGetIntegerv(GLenum pname, GLint* params) {
612 TRACE("pname: 0x%x, params %p\n", pname, params);
613 glGetIntegerv(pname, params);
614 /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
615 wine_wgl.p_wglGetIntegerv(pname, params);
619 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
620 include all dependencies
623 #define SONAME_LIBGL "libGL.so"
626 /* This is for brain-dead applications that use OpenGL functions before even
627 creating a rendering context.... */
628 static BOOL process_attach(void)
630 XWindowAttributes win_attr;
633 XVisualInfo template;
635 XVisualInfo *vis = NULL;
636 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
637 HMODULE mod = GetModuleHandleA( "winex11.drv" );
639 DWORD size = sizeof(internal_gl_disabled_extensions);
644 ERR("X11DRV not loaded. Cannot create default context.\n");
648 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
649 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
651 /* Load WGL function pointers from winex11.drv */
652 wine_wgl.p_wglDeleteContext = (void *)GetProcAddress(mod, "wglDeleteContext");
653 wine_wgl.p_wglGetCurrentContext = (void *)GetProcAddress(mod, "wglGetCurrentContext");
654 wine_wgl.p_wglGetCurrentDC = (void *)GetProcAddress(mod, "wglGetCurrentDC");
655 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
656 wine_wgl.p_wglShareLists = (void *)GetProcAddress(mod, "wglShareLists");
658 /* Interal WGL function */
659 wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
662 default_display = get_display( hdc );
664 if (!default_display)
666 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
672 /* Try to get the visual from the Root Window. We can't use the standard (presumably
673 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
674 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
675 with mismatched visuals. Note that the Root Window visual may not be double
676 buffered, so apps actually attempting to render this way may flicker */
677 if (XGetWindowAttributes( default_display, root, &win_attr ))
679 rootVisual = win_attr.visual;
683 /* Get the default visual, since we can't seem to get the attributes from the
684 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
685 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
688 template.visualid = XVisualIDFromVisual(rootVisual);
689 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
690 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
691 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
695 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
696 if (opengl_handle != NULL) {
697 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
698 wine_dlclose(opengl_handle, NULL, 0);
699 if (p_glXGetProcAddressARB == NULL)
700 TRACE("could not find glXGetProcAddressARB in libGL.\n");
703 internal_gl_disabled_extensions[0] = 0;
704 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
705 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
706 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
711 if (default_cx == NULL) {
712 ERR("Could not create default context.\n");
718 /**********************************************************************/
720 static void process_detach(void)
722 glXDestroyContext(default_display, default_cx);
724 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
727 /***********************************************************************
728 * OpenGL initialisation routine
730 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
734 case DLL_PROCESS_ATTACH:
735 opengl32_handle = hinst;
736 DisableThreadLibraryCalls(hinst);
737 return process_attach();
738 case DLL_PROCESS_DETACH: