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"
38 #include "opengl_ext.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
50 typedef struct wine_glx_s {
53 GLXFBConfig* (*p_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
54 int (*p_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
55 XVisualInfo* (*p_glXGetVisualFromFBConfig) (Display *dpy, GLXFBConfig config);
57 GLXFBConfig* (*p_glXGetFBConfigs) (Display *dpy, int screen, int *nelements);
58 void (*p_glXQueryDrawable) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
59 Bool (*p_glXMakeContextCurrent) (Display *, GLXDrawable, GLXDrawable, GLXContext);
62 typedef struct wine_wgl_s {
63 HGLRC WINAPI (*p_wglCreateContext)(HDC hdc);
64 BOOL WINAPI (*p_wglDeleteContext)(HGLRC hglrc);
65 HGLRC WINAPI (*p_wglGetCurrentContext)(void);
66 HDC WINAPI (*p_wglGetCurrentDC)(void);
67 HDC WINAPI (*p_wglGetCurrentReadDCARB)(void);
68 PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
69 BOOL WINAPI (*p_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
70 BOOL WINAPI (*p_wglMakeContextCurrentARB)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
71 BOOL WINAPI (*p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
73 void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
76 /** global glx object */
77 static wine_glx_t wine_glx;
78 /** global wgl object */
79 static wine_wgl_t wine_wgl;
81 /* x11drv GDI escapes */
82 #define X11DRV_ESCAPE 6789
83 enum x11drv_escape_codes
85 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
86 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
87 X11DRV_GET_FONT, /* get current X font for a DC */
88 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
89 X11DRV_START_EXPOSURES, /* start graphics exposures */
90 X11DRV_END_EXPOSURES, /* end graphics exposures */
91 X11DRV_GET_DCE, /* get the DCE pointer */
92 X11DRV_SET_DCE, /* set the DCE pointer */
93 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
94 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
97 void (*wine_tsx11_lock_ptr)(void) = NULL;
98 void (*wine_tsx11_unlock_ptr)(void) = NULL;
100 static GLXContext default_cx = NULL;
101 static Display *default_display; /* display to use for default context */
103 static HMODULE opengl32_handle;
105 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
107 static char internal_gl_disabled_extensions[512];
108 static char* internal_gl_extensions = NULL;
110 typedef struct wine_glcontext {
117 struct wine_glcontext *next;
118 struct wine_glcontext *prev;
123 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
125 if (curctx && curctx->do_escape)
127 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
128 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
131 wine_tsx11_lock_ptr();
135 /* retrieve the X display to use on a given DC */
136 inline static Display *get_display( HDC hdc )
139 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
141 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
142 sizeof(display), (LPSTR)&display )) display = NULL;
146 /* retrieve the X font to use on a given DC */
147 inline static Font get_font( HDC hdc )
150 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
152 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
153 sizeof(font), (LPSTR)&font )) font = 0;
157 /* GLX can advertise dozens of different pixelformats including offscreen and onscreen ones.
158 * In our WGL implementation we only support a subset of these formats namely the format of
159 * Wine's main visual and offscreen formats (if they are available).
160 * This function converts a WGL format to its corresponding GLX one. It returns the index (zero-based)
161 * into the GLX FB config table and it returns the number of supported WGL formats in fmt_count.
163 BOOL ConvertPixelFormatWGLtoGLX(Display *display, int iPixelFormat, int *fmt_index, int *fmt_count)
167 GLXFBConfig* cfgs = NULL;
171 int nFormats = 1; /* Start at 1 as we always have a main visual */
172 VisualID visualid = 0;
174 /* Request to look up the format of the main visual when iPixelFormat = 1 */
175 if(iPixelFormat == 1) visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
177 /* As mentioned in various parts of the code only the format of the main visual can be used for onscreen rendering.
178 * Next to this format there are also so called offscreen rendering formats (used for pbuffers) which can be supported
179 * because they don't need a visual. Below we use glXGetFBConfigs instead of glXChooseFBConfig to enumerate the fb configurations
180 * bas this call lists both types of formats instead of only onscreen ones. */
181 cfgs = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs);
182 if (NULL == cfgs || 0 == nCfgs) {
183 ERR("glXChooseFBConfig returns NULL\n");
184 if(cfgs != NULL) XFree(cfgs);
188 /* Find the requested offscreen format and count the number of offscreen formats */
189 for(i=0; i<nCfgs; i++) {
190 wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &tmp_vis_id);
191 wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_FBCONFIG_ID, &tmp_fmt_id);
193 /* We are looking up the GLX index of our main visual and have found it :) */
194 if(iPixelFormat == 1 && visualid == tmp_vis_id) {
196 TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", tmp_fmt_id, *fmt_index, tmp_vis_id);
199 /* We found an offscreen rendering format :) */
200 else if(tmp_vis_id == 0) {
202 TRACE("Checking offscreen format FBCONFIG_ID 0x%x at index %d\n", tmp_fmt_id, i);
204 if(iPixelFormat == nFormats) {
206 TRACE("Found offscreen format FBCONFIG_ID 0x%x corresponding to iPixelFormat %d at GLX index %d\n", tmp_fmt_id, iPixelFormat, i);
211 *fmt_count = nFormats;
212 TRACE("Number of offscreen formats: %d; returning index: %d\n", *fmt_count, *fmt_index);
214 if(cfgs != NULL) XFree(cfgs);
219 /***********************************************************************
220 * wglCreateContext (OPENGL32.@)
222 HGLRC WINAPI wglCreateContext(HDC hdc)
224 TRACE("(%p)\n", hdc);
225 return wine_wgl.p_wglCreateContext(hdc);
228 /***********************************************************************
229 * wglCreateLayerContext (OPENGL32.@)
231 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
233 TRACE("(%p,%d)\n", hdc, iLayerPlane);
235 if (iLayerPlane == 0) {
236 return wglCreateContext(hdc);
238 FIXME(" no handler for layer %d\n", iLayerPlane);
243 /***********************************************************************
244 * wglCopyContext (OPENGL32.@)
246 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
249 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
254 /***********************************************************************
255 * wglDeleteContext (OPENGL32.@)
257 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
259 TRACE("(%p)\n", hglrc);
260 return wine_wgl.p_wglDeleteContext(hglrc);
263 /***********************************************************************
264 * wglDescribeLayerPlane (OPENGL32.@)
266 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
270 LPLAYERPLANEDESCRIPTOR plpd) {
271 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
276 /***********************************************************************
277 * wglGetCurrentContext (OPENGL32.@)
279 HGLRC WINAPI wglGetCurrentContext(void) {
281 return wine_wgl.p_wglGetCurrentContext();
284 /***********************************************************************
285 * wglGetCurrentDC (OPENGL32.@)
287 HDC WINAPI wglGetCurrentDC(void) {
289 return wine_wgl.p_wglGetCurrentDC();
292 /***********************************************************************
293 * wglGetLayerPaletteEntries (OPENGL32.@)
295 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
299 const COLORREF *pcr) {
300 FIXME("(): stub !\n");
305 /***********************************************************************
306 * wglGetProcAddress (OPENGL32.@)
308 static int compar(const void *elt_a, const void *elt_b) {
309 return strcmp(((const OpenGL_extension *) elt_a)->name,
310 ((const OpenGL_extension *) elt_b)->name);
313 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
315 OpenGL_extension ext;
316 const OpenGL_extension *ext_ret;
318 TRACE("(%s)\n", lpszProc);
320 /* First, look if it's not already defined in the 'standard' OpenGL functions */
321 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
322 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
326 if (p_glXGetProcAddressARB == NULL) {
327 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
331 /* After that, search in the thunks to find the real name of the extension */
333 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
334 extension_registry_size, sizeof(OpenGL_extension), compar);
336 /* If nothing was found, we are looking for a WGL extension */
337 if (ext_ret == NULL) {
338 return wine_wgl.p_wglGetProcAddress(lpszProc);
339 } else { /* We are looking for an OpenGL extension */
340 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
342 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
345 /* After that, look at the extensions defined in the Linux OpenGL library */
346 if (local_func == NULL) {
350 /* Remove the 3 last letters (EXT, ARB, ...).
352 I know that some extensions have more than 3 letters (MESA, NV,
353 INTEL, ...), but this is only a stop-gap measure to fix buggy
354 OpenGL drivers (moreover, it is only useful for old 1.0 apps
355 that query the glBindTextureEXT extension).
357 memcpy(buf, glx_name, strlen(glx_name) - 3);
358 buf[strlen(glx_name) - 3] = '\0';
359 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
361 ret = GetProcAddress(opengl32_handle, buf);
363 TRACE(" found function in main OpenGL library (%p) !\n", ret);
365 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
370 TRACE(" returning function (%p)\n", ext_ret->func);
371 extension_funcs[ext_ret - extension_registry] = local_func;
373 return ext_ret->func;
378 /***********************************************************************
379 * wglMakeCurrent (OPENGL32.@)
381 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc) {
382 TRACE("hdc: (%p), hglrc: (%p)\n", hdc, hglrc);
383 return wine_wgl.p_wglMakeCurrent(hdc, hglrc);
386 /***********************************************************************
387 * wglMakeContextCurrentARB (OPENGL32.@)
389 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
391 TRACE("hDrawDC: (%p), hReadDC: (%p), hglrc: (%p)\n", hDrawDC, hReadDC, hglrc);
392 return wine_wgl.p_wglMakeContextCurrentARB(hDrawDC, hReadDC, hglrc);
395 /***********************************************************************
396 * wglGetCurrentReadDCARB (OPENGL32.@)
398 HDC WINAPI wglGetCurrentReadDCARB(void)
401 return wine_wgl.p_wglGetCurrentReadDCARB();
404 /***********************************************************************
405 * wglRealizeLayerPalette (OPENGL32.@)
407 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
415 /***********************************************************************
416 * wglSetLayerPaletteEntries (OPENGL32.@)
418 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
422 const COLORREF *pcr) {
423 FIXME("(): stub !\n");
428 /***********************************************************************
429 * wglShareLists (OPENGL32.@)
431 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
432 TRACE("(%p, %p)\n", hglrc1, hglrc2);
433 return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
436 /***********************************************************************
437 * wglSwapLayerBuffers (OPENGL32.@)
439 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
441 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
443 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
444 if (!SwapBuffers(hdc)) return FALSE;
445 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
449 WARN("Following layers unhandled : %08x\n", fuPlanes);
455 static BOOL internal_wglUseFontBitmaps(HDC hdc,
459 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
461 /* We are running using client-side rendering fonts... */
465 void *bitmap = NULL, *gl_bitmap = NULL;
469 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
470 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
473 for (glyph = first; glyph < first + count; glyph++) {
474 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
475 int height, width_int;
477 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
478 if (needed_size == GDI_ERROR) {
479 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
482 TRACE(" - needed size : %d\n", needed_size);
485 if (needed_size > size) {
487 HeapFree(GetProcessHeap(), 0, bitmap);
488 HeapFree(GetProcessHeap(), 0, gl_bitmap);
489 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
490 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
492 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
493 if (TRACE_ON(opengl)) {
494 unsigned int height, width, bitmask;
495 unsigned char *bitmap_ = (unsigned char *) bitmap;
497 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
498 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
499 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
500 if (needed_size != 0) {
501 TRACE(" - bitmap :\n");
502 for (height = 0; height < gm.gmBlackBoxY; height++) {
504 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
509 if (*bitmap_ & bitmask)
514 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
520 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
521 * glyph for it to be drawn properly.
523 if (needed_size != 0) {
524 width_int = (gm.gmBlackBoxX + 31) / 32;
525 for (height = 0; height < gm.gmBlackBoxY; height++) {
527 for (width = 0; width < width_int; width++) {
528 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
529 ((int *) bitmap)[height * width_int + width];
535 glNewList(listBase++, GL_COMPILE);
536 if (needed_size != 0) {
537 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
538 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
539 gm.gmCellIncX, gm.gmCellIncY,
542 /* This is the case of 'empty' glyphs like the space character */
543 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
550 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
553 HeapFree(GetProcessHeap(), 0, bitmap);
554 HeapFree(GetProcessHeap(), 0, gl_bitmap);
559 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
562 HeapFree(GetProcessHeap(), 0, bitmap);
563 HeapFree(GetProcessHeap(), 0, gl_bitmap);
567 /***********************************************************************
568 * wglUseFontBitmapsA (OPENGL32.@)
570 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
575 Font fid = get_font( hdc );
577 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
580 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
584 /* I assume that the glyphs are at the same position for X and for Windows */
585 glXUseXFont(fid, first, count, listBase);
590 /***********************************************************************
591 * wglUseFontBitmapsW (OPENGL32.@)
593 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
598 Font fid = get_font( hdc );
600 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
603 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
606 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
609 /* I assume that the glyphs are at the same position for X and for Windows */
610 glXUseXFont(fid, first, count, listBase);
617 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
619 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
620 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
624 static void tess_callback_vertex(GLvoid *vertex)
626 GLdouble *dbl = vertex;
627 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
631 static void tess_callback_begin(GLenum which)
633 TRACE("%d\n", which);
637 static void tess_callback_end(void)
643 /***********************************************************************
644 * wglUseFontOutlines_common
646 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
653 LPGLYPHMETRICSFLOAT lpgmf,
657 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
660 HFONT old_font, unscaled_font;
664 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
665 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
672 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
673 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
674 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
678 if(!tess) return FALSE;
680 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
681 rc.left = rc.right = rc.bottom = 0;
683 DPtoLP(hdc, (POINT*)&rc, 2);
684 lf.lfHeight = -abs(rc.top - rc.bottom);
685 lf.lfOrientation = lf.lfEscapement = 0;
686 unscaled_font = CreateFontIndirectW(&lf);
687 old_font = SelectObject(hdc, unscaled_font);
689 for (glyph = first; glyph < first + count; glyph++)
694 TTPOLYGONHEADER *pph;
699 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
701 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
703 if(needed == GDI_ERROR)
706 buf = HeapAlloc(GetProcessHeap(), 0, needed);
707 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
710 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
712 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
714 TRACE("glyph %d\n", glyph);
718 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
719 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
720 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
721 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
722 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
723 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
725 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
726 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
731 glNewList(listBase++, GL_COMPILE);
732 gluTessBeginPolygon(tess, NULL);
734 pph = (TTPOLYGONHEADER*)buf;
735 while((BYTE*)pph < buf + needed)
737 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
739 gluTessBeginContour(tess);
741 fixed_to_double(pph->pfxStart, em_size, vertices);
742 gluTessVertex(tess, vertices, vertices);
745 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
746 while((char*)ppc < (char*)pph + pph->cb)
752 for(i = 0; i < ppc->cpfx; i++)
754 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
755 fixed_to_double(ppc->apfx[i], em_size, vertices);
756 gluTessVertex(tess, vertices, vertices);
761 case TT_PRIM_QSPLINE:
762 for(i = 0; i < ppc->cpfx/2; i++)
764 /* FIXME just connecting the control points for now */
765 TRACE("\t\tcurve %d,%d %d,%d\n",
766 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
767 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
768 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
769 gluTessVertex(tess, vertices, vertices);
771 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
772 gluTessVertex(tess, vertices, vertices);
777 ERR("\t\tcurve type = %d\n", ppc->wType);
778 gluTessEndContour(tess);
782 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
783 (ppc->cpfx - 1) * sizeof(POINTFX));
785 gluTessEndContour(tess);
786 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
790 gluTessEndPolygon(tess);
791 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
794 HeapFree(GetProcessHeap(), 0, buf);
795 HeapFree(GetProcessHeap(), 0, vertices);
799 DeleteObject(SelectObject(hdc, old_font));
805 #else /* HAVE_GL_GLU_H */
807 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
814 LPGLYPHMETRICSFLOAT lpgmf,
817 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
821 #endif /* HAVE_GL_GLU_H */
823 /***********************************************************************
824 * wglUseFontOutlinesA (OPENGL32.@)
826 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
833 LPGLYPHMETRICSFLOAT lpgmf)
835 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
838 /***********************************************************************
839 * wglUseFontOutlinesW (OPENGL32.@)
841 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
848 LPGLYPHMETRICSFLOAT lpgmf)
850 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
853 const GLubyte * internal_glGetString(GLenum name) {
854 const char* GL_Extensions = NULL;
856 if (GL_EXTENSIONS != name) {
857 return glGetString(name);
860 if (NULL == internal_gl_extensions) {
861 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
863 TRACE("GL_EXTENSIONS reported:\n");
864 if (NULL == GL_Extensions) {
865 ERR("GL_EXTENSIONS returns NULL\n");
868 size_t len = strlen(GL_Extensions);
869 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
871 while (*GL_Extensions != 0x00) {
872 const char* Start = GL_Extensions;
875 memset(ThisExtn, 0x00, sizeof(ThisExtn));
876 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
879 memcpy(ThisExtn, Start, (GL_Extensions - Start));
880 TRACE("- %s:", ThisExtn);
882 /* test if supported API is disabled by config */
883 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
884 strcat(internal_gl_extensions, " ");
885 strcat(internal_gl_extensions, ThisExtn);
888 TRACE(" deactived (by config)\n");
891 if (*GL_Extensions == ' ') GL_Extensions++;
895 return (const GLubyte *) internal_gl_extensions;
898 void internal_glGetIntegerv(GLenum pname, GLint* params) {
899 TRACE("pname: 0x%x, params %p\n", pname, params);
900 glGetIntegerv(pname, params);
901 /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
902 wine_wgl.p_wglGetIntegerv(pname, params);
906 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
907 include all dependencies
910 #define SONAME_LIBGL "libGL.so"
913 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
915 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
916 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
917 const char *glx_extensions = NULL;
918 BOOL glx_direct = glXIsDirect(display, default_cx);
920 memset(&wine_glx, 0, sizeof(wine_glx));
922 /* In case of GLX you have direct and indirect rendering. Most of the time direct rendering is used
923 * as in general only that is hardware accelerated. In some cases like in case of remote X indirect
926 * The main problem for our OpenGL code is that we need certain GLX calls but their presence
927 * depends on the reported GLX client / server version and on the client / server extension list.
928 * Those don't have to be the same.
930 * In general the server GLX information should be used in case of indirect rendering. When direct
931 * rendering is used, the OpenGL client library is responsible for which GLX calls are available.
932 * Nvidia's OpenGL drivers are the best in terms of GLX features. At the moment of writing their
933 * 8762 drivers support 1.3 for the server and 1.4 for the client and they support lots of extensions.
934 * Unfortunately it is much more complicated for Mesa/DRI-based drivers and ATI's drivers.
935 * Both sets of drivers report a server version of 1.2 and the client version can be 1.3 or 1.4.
936 * Further in case of at least ATI's drivers one crucial extension needed for our pixel format code
937 * is only available in the list of server extensions and not in the client list.
939 * The version checks below try to take into account the comments from above.
942 TRACE("Server GLX version: %s\n", server_glx_version);
943 TRACE("Client GLX version: %s\n", client_glx_version);
944 TRACE("Direct rendering eanbled: %s\n", glx_direct ? "True" : "False");
946 /* Based on the default opengl context we decide whether direct or indirect rendering is used.
947 * In case of indirect rendering we check if the GLX version of the server is 1.2 and else
948 * the client version is checked.
950 if ( (!glx_direct && !strcmp("1.2", server_glx_version)) || (glx_direct && !strcmp("1.2", client_glx_version)) ) {
951 wine_glx.version = 2;
953 wine_glx.version = 3;
956 /* Depending on the use of direct or indirect rendering we need either the list of extensions
957 * exported by the client or by the server.
960 glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
962 glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
964 if (2 < wine_glx.version) {
965 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
966 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
967 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
969 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
971 if (NULL != strstr(glx_extensions, "GLX_SGIX_fbconfig")) {
972 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
973 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
974 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
976 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", client_glx_version);
980 /* The mesa libGL client library seems to forward glXQueryDrawable to the Xserver, so only
981 * enable this function when the Xserver understand GLX 1.3 or newer
983 if (!strcmp("1.2", server_glx_version))
984 wine_glx.p_glXQueryDrawable = NULL;
986 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
988 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
989 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
990 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
993 /* This is for brain-dead applications that use OpenGL functions before even
994 creating a rendering context.... */
995 static BOOL process_attach(void)
997 XWindowAttributes win_attr;
1000 XVisualInfo template;
1002 XVisualInfo *vis = NULL;
1003 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1004 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1005 void *opengl_handle;
1006 DWORD size = sizeof(internal_gl_disabled_extensions);
1011 ERR("X11DRV not loaded. Cannot create default context.\n");
1015 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1016 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1018 /* Load WGL function pointers from winex11.drv */
1019 wine_wgl.p_wglCreateContext = (void *)GetProcAddress(mod, "wglCreateContext");
1020 wine_wgl.p_wglDeleteContext = (void *)GetProcAddress(mod, "wglDeleteContext");
1021 wine_wgl.p_wglGetCurrentContext = (void *)GetProcAddress(mod, "wglGetCurrentContext");
1022 wine_wgl.p_wglGetCurrentDC = (void *)GetProcAddress(mod, "wglGetCurrentDC");
1023 wine_wgl.p_wglGetCurrentReadDCARB = (void *)GetProcAddress(mod, "wglGetCurrentReadDCARB");
1024 wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
1025 wine_wgl.p_wglMakeCurrent = (void *)GetProcAddress(mod, "wglMakeCurrent");
1026 wine_wgl.p_wglMakeContextCurrentARB = (void *)GetProcAddress(mod, "wglMakeContextCurrentARB");
1027 wine_wgl.p_wglShareLists = (void *)GetProcAddress(mod, "wglShareLists");
1028 /* Interal WGL function */
1029 wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
1032 default_display = get_display( hdc );
1033 ReleaseDC( 0, hdc );
1034 if (!default_display)
1036 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1042 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1043 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1044 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1045 with mismatched visuals. Note that the Root Window visual may not be double
1046 buffered, so apps actually attempting to render this way may flicker */
1047 if (XGetWindowAttributes( default_display, root, &win_attr ))
1049 rootVisual = win_attr.visual;
1053 /* Get the default visual, since we can't seem to get the attributes from the
1054 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1055 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1058 template.visualid = XVisualIDFromVisual(rootVisual);
1059 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1060 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1061 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1065 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1066 if (opengl_handle != NULL) {
1067 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1068 wine_dlclose(opengl_handle, NULL, 0);
1069 if (p_glXGetProcAddressARB == NULL)
1070 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1073 internal_gl_disabled_extensions[0] = 0;
1074 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1075 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1076 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1081 if (default_cx == NULL) {
1082 ERR("Could not create default context.\n");
1086 /* After context initialize also the list of supported WGL extensions. */
1087 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1093 /**********************************************************************/
1095 static void process_detach(void)
1097 glXDestroyContext(default_display, default_cx);
1099 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1102 /***********************************************************************
1103 * OpenGL initialisation routine
1105 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1109 case DLL_PROCESS_ATTACH:
1110 opengl32_handle = hinst;
1111 DisableThreadLibraryCalls(hinst);
1112 return process_attach();
1113 case DLL_PROCESS_DETACH: