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 PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
52 void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
55 /** global wgl object */
56 static wine_wgl_t wine_wgl;
58 /* x11drv GDI escapes */
59 #define X11DRV_ESCAPE 6789
60 enum x11drv_escape_codes
62 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
63 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
64 X11DRV_GET_FONT, /* get current X font for a DC */
65 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
66 X11DRV_START_EXPOSURES, /* start graphics exposures */
67 X11DRV_END_EXPOSURES, /* end graphics exposures */
68 X11DRV_GET_DCE, /* get the DCE pointer */
69 X11DRV_SET_DCE, /* set the DCE pointer */
70 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
71 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
74 void (*wine_tsx11_lock_ptr)(void) = NULL;
75 void (*wine_tsx11_unlock_ptr)(void) = NULL;
77 static GLXContext default_cx = NULL;
78 static Display *default_display; /* display to use for default context */
80 static HMODULE opengl32_handle;
82 static void* (*p_glXGetProcAddressARB)(const GLubyte *);
84 static char internal_gl_disabled_extensions[512];
85 static char* internal_gl_extensions = NULL;
87 typedef struct wine_glcontext {
94 struct wine_glcontext *next;
95 struct wine_glcontext *prev;
100 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
102 if (curctx && curctx->do_escape)
104 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
105 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
108 wine_tsx11_lock_ptr();
112 /* retrieve the X display to use on a given DC */
113 inline static Display *get_display( HDC hdc )
116 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
118 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
119 sizeof(display), (LPSTR)&display )) display = NULL;
123 /***********************************************************************
124 * wglCreateLayerContext (OPENGL32.@)
126 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
128 TRACE("(%p,%d)\n", hdc, iLayerPlane);
130 if (iLayerPlane == 0) {
131 return wglCreateContext(hdc);
133 FIXME(" no handler for layer %d\n", iLayerPlane);
138 /***********************************************************************
139 * wglCopyContext (OPENGL32.@)
141 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
144 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
149 /***********************************************************************
150 * wglDescribeLayerPlane (OPENGL32.@)
152 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
156 LPLAYERPLANEDESCRIPTOR plpd) {
157 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
162 /***********************************************************************
163 * wglGetLayerPaletteEntries (OPENGL32.@)
165 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
169 const COLORREF *pcr) {
170 FIXME("(): stub !\n");
175 /***********************************************************************
176 * wglGetProcAddress (OPENGL32.@)
178 static int compar(const void *elt_a, const void *elt_b) {
179 return strcmp(((const OpenGL_extension *) elt_a)->name,
180 ((const OpenGL_extension *) elt_b)->name);
183 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
185 OpenGL_extension ext;
186 const OpenGL_extension *ext_ret;
188 TRACE("(%s)\n", lpszProc);
190 /* First, look if it's not already defined in the 'standard' OpenGL functions */
191 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
192 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
196 if (p_glXGetProcAddressARB == NULL) {
197 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
201 /* After that, search in the thunks to find the real name of the extension */
203 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
204 extension_registry_size, sizeof(OpenGL_extension), compar);
206 /* If nothing was found, we are looking for a WGL extension */
207 if (ext_ret == NULL) {
208 return wine_wgl.p_wglGetProcAddress(lpszProc);
209 } else { /* We are looking for an OpenGL extension */
210 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
212 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
215 /* After that, look at the extensions defined in the Linux OpenGL library */
216 if (local_func == NULL) {
220 /* Remove the 3 last letters (EXT, ARB, ...).
222 I know that some extensions have more than 3 letters (MESA, NV,
223 INTEL, ...), but this is only a stop-gap measure to fix buggy
224 OpenGL drivers (moreover, it is only useful for old 1.0 apps
225 that query the glBindTextureEXT extension).
227 memcpy(buf, glx_name, strlen(glx_name) - 3);
228 buf[strlen(glx_name) - 3] = '\0';
229 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
231 ret = GetProcAddress(opengl32_handle, buf);
233 TRACE(" found function in main OpenGL library (%p) !\n", ret);
235 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
240 TRACE(" returning function (%p)\n", ext_ret->func);
241 extension_funcs[ext_ret - extension_registry] = local_func;
243 return ext_ret->func;
248 /***********************************************************************
249 * wglRealizeLayerPalette (OPENGL32.@)
251 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
259 /***********************************************************************
260 * wglSetLayerPaletteEntries (OPENGL32.@)
262 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
266 const COLORREF *pcr) {
267 FIXME("(): stub !\n");
272 /***********************************************************************
273 * wglSwapLayerBuffers (OPENGL32.@)
275 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
277 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
279 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
280 if (!SwapBuffers(hdc)) return FALSE;
281 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
285 WARN("Following layers unhandled : %08x\n", fuPlanes);
293 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
295 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
296 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
300 static void tess_callback_vertex(GLvoid *vertex)
302 GLdouble *dbl = vertex;
303 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
307 static void tess_callback_begin(GLenum which)
309 TRACE("%d\n", which);
313 static void tess_callback_end(void)
319 /***********************************************************************
320 * wglUseFontOutlines_common
322 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
329 LPGLYPHMETRICSFLOAT lpgmf,
333 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
336 HFONT old_font, unscaled_font;
340 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
341 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
348 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
349 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
350 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
354 if(!tess) return FALSE;
356 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
357 rc.left = rc.right = rc.bottom = 0;
359 DPtoLP(hdc, (POINT*)&rc, 2);
360 lf.lfHeight = -abs(rc.top - rc.bottom);
361 lf.lfOrientation = lf.lfEscapement = 0;
362 unscaled_font = CreateFontIndirectW(&lf);
363 old_font = SelectObject(hdc, unscaled_font);
365 for (glyph = first; glyph < first + count; glyph++)
370 TTPOLYGONHEADER *pph;
375 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
377 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
379 if(needed == GDI_ERROR)
382 buf = HeapAlloc(GetProcessHeap(), 0, needed);
383 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
386 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
388 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
390 TRACE("glyph %d\n", glyph);
394 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
395 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
396 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
397 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
398 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
399 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
401 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
402 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
407 glNewList(listBase++, GL_COMPILE);
408 gluTessBeginPolygon(tess, NULL);
410 pph = (TTPOLYGONHEADER*)buf;
411 while((BYTE*)pph < buf + needed)
413 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
415 gluTessBeginContour(tess);
417 fixed_to_double(pph->pfxStart, em_size, vertices);
418 gluTessVertex(tess, vertices, vertices);
421 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
422 while((char*)ppc < (char*)pph + pph->cb)
428 for(i = 0; i < ppc->cpfx; i++)
430 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
431 fixed_to_double(ppc->apfx[i], em_size, vertices);
432 gluTessVertex(tess, vertices, vertices);
437 case TT_PRIM_QSPLINE:
438 for(i = 0; i < ppc->cpfx/2; i++)
440 /* FIXME just connecting the control points for now */
441 TRACE("\t\tcurve %d,%d %d,%d\n",
442 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
443 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
444 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
445 gluTessVertex(tess, vertices, vertices);
447 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
448 gluTessVertex(tess, vertices, vertices);
453 ERR("\t\tcurve type = %d\n", ppc->wType);
454 gluTessEndContour(tess);
458 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
459 (ppc->cpfx - 1) * sizeof(POINTFX));
461 gluTessEndContour(tess);
462 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
466 gluTessEndPolygon(tess);
467 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
470 HeapFree(GetProcessHeap(), 0, buf);
471 HeapFree(GetProcessHeap(), 0, vertices);
475 DeleteObject(SelectObject(hdc, old_font));
481 #else /* HAVE_GL_GLU_H */
483 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
490 LPGLYPHMETRICSFLOAT lpgmf,
493 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
497 #endif /* HAVE_GL_GLU_H */
499 /***********************************************************************
500 * wglUseFontOutlinesA (OPENGL32.@)
502 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
509 LPGLYPHMETRICSFLOAT lpgmf)
511 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
514 /***********************************************************************
515 * wglUseFontOutlinesW (OPENGL32.@)
517 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
524 LPGLYPHMETRICSFLOAT lpgmf)
526 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
529 const GLubyte * internal_glGetString(GLenum name) {
530 const char* GL_Extensions = NULL;
532 if (GL_EXTENSIONS != name) {
533 return glGetString(name);
536 if (NULL == internal_gl_extensions) {
537 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
539 TRACE("GL_EXTENSIONS reported:\n");
540 if (NULL == GL_Extensions) {
541 ERR("GL_EXTENSIONS returns NULL\n");
544 size_t len = strlen(GL_Extensions);
545 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
547 while (*GL_Extensions != 0x00) {
548 const char* Start = GL_Extensions;
551 memset(ThisExtn, 0x00, sizeof(ThisExtn));
552 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
555 memcpy(ThisExtn, Start, (GL_Extensions - Start));
556 TRACE("- %s:", ThisExtn);
558 /* test if supported API is disabled by config */
559 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
560 strcat(internal_gl_extensions, " ");
561 strcat(internal_gl_extensions, ThisExtn);
564 TRACE(" deactived (by config)\n");
567 if (*GL_Extensions == ' ') GL_Extensions++;
571 return (const GLubyte *) internal_gl_extensions;
574 void internal_glGetIntegerv(GLenum pname, GLint* params) {
575 TRACE("pname: 0x%x, params %p\n", pname, params);
576 glGetIntegerv(pname, params);
577 /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
578 wine_wgl.p_wglGetIntegerv(pname, params);
582 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
583 include all dependencies
586 #define SONAME_LIBGL "libGL.so"
589 /* This is for brain-dead applications that use OpenGL functions before even
590 creating a rendering context.... */
591 static BOOL process_attach(void)
593 XWindowAttributes win_attr;
596 XVisualInfo template;
598 XVisualInfo *vis = NULL;
599 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
600 HMODULE mod = GetModuleHandleA( "winex11.drv" );
602 DWORD size = sizeof(internal_gl_disabled_extensions);
607 ERR("X11DRV not loaded. Cannot create default context.\n");
611 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
612 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
614 /* Load WGL function pointers from winex11.drv */
615 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
617 /* Interal WGL function */
618 wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
621 default_display = get_display( hdc );
623 if (!default_display)
625 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
631 /* Try to get the visual from the Root Window. We can't use the standard (presumably
632 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
633 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
634 with mismatched visuals. Note that the Root Window visual may not be double
635 buffered, so apps actually attempting to render this way may flicker */
636 if (XGetWindowAttributes( default_display, root, &win_attr ))
638 rootVisual = win_attr.visual;
642 /* Get the default visual, since we can't seem to get the attributes from the
643 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
644 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
647 template.visualid = XVisualIDFromVisual(rootVisual);
648 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
649 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
650 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
654 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
655 if (opengl_handle != NULL) {
656 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
657 wine_dlclose(opengl_handle, NULL, 0);
658 if (p_glXGetProcAddressARB == NULL)
659 TRACE("could not find glXGetProcAddressARB in libGL.\n");
662 internal_gl_disabled_extensions[0] = 0;
663 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
664 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
665 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
670 if (default_cx == NULL) {
671 ERR("Could not create default context.\n");
677 /**********************************************************************/
679 static void process_detach(void)
681 glXDestroyContext(default_display, default_cx);
683 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
686 /***********************************************************************
687 * OpenGL initialisation routine
689 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
693 case DLL_PROCESS_ATTACH:
694 opengl32_handle = hinst;
695 DisableThreadLibraryCalls(hinst);
696 return process_attach();
697 case DLL_PROCESS_DETACH: