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 char internal_gl_disabled_extensions[512];
83 static char* internal_gl_extensions = NULL;
85 typedef struct wine_glcontext {
92 struct wine_glcontext *next;
93 struct wine_glcontext *prev;
98 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
100 if (curctx && curctx->do_escape)
102 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
103 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
106 wine_tsx11_lock_ptr();
110 /* retrieve the X display to use on a given DC */
111 inline static Display *get_display( HDC hdc )
114 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
116 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
117 sizeof(display), (LPSTR)&display )) display = NULL;
121 /***********************************************************************
122 * wglCreateLayerContext (OPENGL32.@)
124 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
126 TRACE("(%p,%d)\n", hdc, iLayerPlane);
128 if (iLayerPlane == 0) {
129 return wglCreateContext(hdc);
131 FIXME(" no handler for layer %d\n", iLayerPlane);
136 /***********************************************************************
137 * wglCopyContext (OPENGL32.@)
139 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
142 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
147 /***********************************************************************
148 * wglDescribeLayerPlane (OPENGL32.@)
150 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
154 LPLAYERPLANEDESCRIPTOR plpd) {
155 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
160 /***********************************************************************
161 * wglGetLayerPaletteEntries (OPENGL32.@)
163 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
167 const COLORREF *pcr) {
168 FIXME("(): stub !\n");
173 /***********************************************************************
174 * wglGetProcAddress (OPENGL32.@)
176 static int compar(const void *elt_a, const void *elt_b) {
177 return strcmp(((const OpenGL_extension *) elt_a)->name,
178 ((const OpenGL_extension *) elt_b)->name);
181 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
183 OpenGL_extension ext;
184 const OpenGL_extension *ext_ret;
186 TRACE("(%s)\n", lpszProc);
188 /* First, look if it's not already defined in the 'standard' OpenGL functions */
189 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
190 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
194 /* After that, search in the thunks to find the real name of the extension */
196 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
197 extension_registry_size, sizeof(OpenGL_extension), compar);
199 /* If nothing was found, we are looking for a WGL extension */
200 if (ext_ret == NULL) {
201 WARN("Extension '%s' not defined in opengl32.dll's function table!\n", lpszProc);
202 return wine_wgl.p_wglGetProcAddress(lpszProc);
203 } else { /* We are looking for an OpenGL extension */
204 local_func = wine_wgl.p_wglGetProcAddress(ext_ret->name);
206 /* After that, look at the extensions defined in the Linux OpenGL library */
207 if (local_func == NULL) {
211 /* Remove the 3 last letters (EXT, ARB, ...).
213 I know that some extensions have more than 3 letters (MESA, NV,
214 INTEL, ...), but this is only a stop-gap measure to fix buggy
215 OpenGL drivers (moreover, it is only useful for old 1.0 apps
216 that query the glBindTextureEXT extension).
218 memcpy(buf, ext_ret->name, strlen(ext_ret->name) - 3);
219 buf[strlen(ext_ret->name) - 3] = '\0';
220 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
222 ret = GetProcAddress(opengl32_handle, buf);
224 TRACE(" found function in main OpenGL library (%p) !\n", ret);
226 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->name);
231 TRACE(" returning function (%p)\n", ext_ret->func);
232 extension_funcs[ext_ret - extension_registry] = local_func;
234 return ext_ret->func;
239 /***********************************************************************
240 * wglRealizeLayerPalette (OPENGL32.@)
242 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
250 /***********************************************************************
251 * wglSetLayerPaletteEntries (OPENGL32.@)
253 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
257 const COLORREF *pcr) {
258 FIXME("(): stub !\n");
263 /***********************************************************************
264 * wglSwapLayerBuffers (OPENGL32.@)
266 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
268 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
270 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
271 if (!SwapBuffers(hdc)) return FALSE;
272 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
276 WARN("Following layers unhandled : %08x\n", fuPlanes);
284 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
286 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
287 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
291 static void tess_callback_vertex(GLvoid *vertex)
293 GLdouble *dbl = vertex;
294 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
298 static void tess_callback_begin(GLenum which)
300 TRACE("%d\n", which);
304 static void tess_callback_end(void)
310 /***********************************************************************
311 * wglUseFontOutlines_common
313 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
320 LPGLYPHMETRICSFLOAT lpgmf,
324 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
327 HFONT old_font, unscaled_font;
331 TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
332 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
339 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
340 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
341 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
345 if(!tess) return FALSE;
347 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
348 rc.left = rc.right = rc.bottom = 0;
350 DPtoLP(hdc, (POINT*)&rc, 2);
351 lf.lfHeight = -abs(rc.top - rc.bottom);
352 lf.lfOrientation = lf.lfEscapement = 0;
353 unscaled_font = CreateFontIndirectW(&lf);
354 old_font = SelectObject(hdc, unscaled_font);
356 for (glyph = first; glyph < first + count; glyph++)
361 TTPOLYGONHEADER *pph;
366 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
368 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
370 if(needed == GDI_ERROR)
373 buf = HeapAlloc(GetProcessHeap(), 0, needed);
374 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
377 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
379 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
381 TRACE("glyph %d\n", glyph);
385 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
386 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
387 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
388 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
389 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
390 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
392 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
393 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
398 glNewList(listBase++, GL_COMPILE);
399 gluTessBeginPolygon(tess, NULL);
401 pph = (TTPOLYGONHEADER*)buf;
402 while((BYTE*)pph < buf + needed)
404 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
406 gluTessBeginContour(tess);
408 fixed_to_double(pph->pfxStart, em_size, vertices);
409 gluTessVertex(tess, vertices, vertices);
412 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
413 while((char*)ppc < (char*)pph + pph->cb)
419 for(i = 0; i < ppc->cpfx; i++)
421 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
422 fixed_to_double(ppc->apfx[i], em_size, vertices);
423 gluTessVertex(tess, vertices, vertices);
428 case TT_PRIM_QSPLINE:
429 for(i = 0; i < ppc->cpfx/2; i++)
431 /* FIXME just connecting the control points for now */
432 TRACE("\t\tcurve %d,%d %d,%d\n",
433 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
434 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
435 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
436 gluTessVertex(tess, vertices, vertices);
438 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
439 gluTessVertex(tess, vertices, vertices);
444 ERR("\t\tcurve type = %d\n", ppc->wType);
445 gluTessEndContour(tess);
449 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
450 (ppc->cpfx - 1) * sizeof(POINTFX));
452 gluTessEndContour(tess);
453 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
457 gluTessEndPolygon(tess);
458 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
461 HeapFree(GetProcessHeap(), 0, buf);
462 HeapFree(GetProcessHeap(), 0, vertices);
466 DeleteObject(SelectObject(hdc, old_font));
472 #else /* HAVE_GL_GLU_H */
474 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
481 LPGLYPHMETRICSFLOAT lpgmf,
484 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
488 #endif /* HAVE_GL_GLU_H */
490 /***********************************************************************
491 * wglUseFontOutlinesA (OPENGL32.@)
493 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
500 LPGLYPHMETRICSFLOAT lpgmf)
502 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
505 /***********************************************************************
506 * wglUseFontOutlinesW (OPENGL32.@)
508 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
515 LPGLYPHMETRICSFLOAT lpgmf)
517 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
520 const GLubyte * internal_glGetString(GLenum name) {
521 const char* GL_Extensions = NULL;
523 if (GL_EXTENSIONS != name) {
524 return glGetString(name);
527 if (NULL == internal_gl_extensions) {
528 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
530 TRACE("GL_EXTENSIONS reported:\n");
531 if (NULL == GL_Extensions) {
532 ERR("GL_EXTENSIONS returns NULL\n");
535 size_t len = strlen(GL_Extensions);
536 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
538 while (*GL_Extensions != 0x00) {
539 const char* Start = GL_Extensions;
542 memset(ThisExtn, 0x00, sizeof(ThisExtn));
543 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
546 memcpy(ThisExtn, Start, (GL_Extensions - Start));
547 TRACE("- %s:", ThisExtn);
549 /* test if supported API is disabled by config */
550 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
551 strcat(internal_gl_extensions, " ");
552 strcat(internal_gl_extensions, ThisExtn);
555 TRACE(" deactived (by config)\n");
558 if (*GL_Extensions == ' ') GL_Extensions++;
562 return (const GLubyte *) internal_gl_extensions;
565 void internal_glGetIntegerv(GLenum pname, GLint* params) {
566 TRACE("pname: 0x%x, params %p\n", pname, params);
567 glGetIntegerv(pname, params);
568 /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
569 wine_wgl.p_wglGetIntegerv(pname, params);
573 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
574 include all dependencies
577 #define SONAME_LIBGL "libGL.so"
580 /* This is for brain-dead applications that use OpenGL functions before even
581 creating a rendering context.... */
582 static BOOL process_attach(void)
584 XWindowAttributes win_attr;
587 XVisualInfo template;
589 XVisualInfo *vis = NULL;
590 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
591 HMODULE mod = GetModuleHandleA( "winex11.drv" );
592 HMODULE mod_gdi32 = GetModuleHandleA( "gdi32.dll" );
593 DWORD size = sizeof(internal_gl_disabled_extensions);
596 if (!root || !mod || !mod_gdi32)
598 ERR("X11DRV or GDI32 not loaded. Cannot create default context.\n");
602 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
603 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
605 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
607 /* Interal WGL function */
608 wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
611 default_display = get_display( hdc );
613 if (!default_display)
615 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
621 /* Try to get the visual from the Root Window. We can't use the standard (presumably
622 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
623 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
624 with mismatched visuals. Note that the Root Window visual may not be double
625 buffered, so apps actually attempting to render this way may flicker */
626 if (XGetWindowAttributes( default_display, root, &win_attr ))
628 rootVisual = win_attr.visual;
632 /* Get the default visual, since we can't seem to get the attributes from the
633 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
634 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
637 template.visualid = XVisualIDFromVisual(rootVisual);
638 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
639 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
640 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
644 internal_gl_disabled_extensions[0] = 0;
645 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
646 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
647 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
652 if (default_cx == NULL) {
653 ERR("Could not create default context.\n");
659 /**********************************************************************/
661 static void process_detach(void)
663 glXDestroyContext(default_display, default_cx);
665 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
668 /***********************************************************************
669 * OpenGL initialisation routine
671 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
675 case DLL_PROCESS_ATTACH:
676 opengl32_handle = hinst;
677 DisableThreadLibraryCalls(hinst);
678 return process_attach();
679 case DLL_PROCESS_DETACH: