winex11.drv: Move WGL extension code to winex11.drv.
[wine/wine64.git] / dlls / opengl32 / wgl.c
blob518e99606b54dfecab485ba72c9b4d0979d4db14
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
37 #include "wgl_ext.h"
38 #include "opengl_ext.h"
39 #ifdef HAVE_GL_GLU_H
40 #undef far
41 #undef near
42 #include <GL/glu.h>
43 #endif
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 {
51 unsigned version;
52 /** SGIX / 1.3 */
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);
56 /** 1.3 */
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);
60 } wine_glx_t;
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);
74 } wine_wgl_t;
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 {
111 HDC hdc;
112 Display *display;
113 XVisualInfo *vis;
114 GLXFBConfig fb_conf;
115 GLXContext ctx;
116 BOOL do_escape;
117 struct wine_glcontext *next;
118 struct wine_glcontext *prev;
119 } Wine_GLContext;
121 void enter_gl(void)
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();
132 return;
135 /* retrieve the X display to use on a given DC */
136 inline static Display *get_display( HDC hdc )
138 Display *display;
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;
143 return display;
146 /* retrieve the X font to use on a given DC */
147 inline static Font get_font( HDC hdc )
149 Font font;
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;
154 return font;
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)
165 int res = FALSE;
166 int i = 0;
167 GLXFBConfig* cfgs = NULL;
168 int nCfgs = 0;
169 int tmp_fmt_id = 0;
170 int tmp_vis_id = 0;
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);
185 return FALSE;
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) {
195 *fmt_index = i;
196 TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", tmp_fmt_id, *fmt_index, tmp_vis_id);
197 res = TRUE;
199 /* We found an offscreen rendering format :) */
200 else if(tmp_vis_id == 0) {
201 nFormats++;
202 TRACE("Checking offscreen format FBCONFIG_ID 0x%x at index %d\n", tmp_fmt_id, i);
204 if(iPixelFormat == nFormats) {
205 *fmt_index = i;
206 TRACE("Found offscreen format FBCONFIG_ID 0x%x corresponding to iPixelFormat %d at GLX index %d\n", tmp_fmt_id, iPixelFormat, i);
207 res = TRUE;
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);
216 return res;
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,
232 int iLayerPlane) {
233 TRACE("(%p,%d)\n", hdc, iLayerPlane);
235 if (iLayerPlane == 0) {
236 return wglCreateContext(hdc);
238 FIXME(" no handler for layer %d\n", iLayerPlane);
240 return NULL;
243 /***********************************************************************
244 * wglCopyContext (OPENGL32.@)
246 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
247 HGLRC hglrcDst,
248 UINT mask) {
249 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
251 return FALSE;
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,
267 int iPixelFormat,
268 int iLayerPlane,
269 UINT nBytes,
270 LPLAYERPLANEDESCRIPTOR plpd) {
271 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
273 return FALSE;
276 /***********************************************************************
277 * wglGetCurrentContext (OPENGL32.@)
279 HGLRC WINAPI wglGetCurrentContext(void) {
280 TRACE("\n");
281 return wine_wgl.p_wglGetCurrentContext();
284 /***********************************************************************
285 * wglGetCurrentDC (OPENGL32.@)
287 HDC WINAPI wglGetCurrentDC(void) {
288 TRACE("\n");
289 return wine_wgl.p_wglGetCurrentDC();
292 /***********************************************************************
293 * wglGetLayerPaletteEntries (OPENGL32.@)
295 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
296 int iLayerPlane,
297 int iStart,
298 int cEntries,
299 const COLORREF *pcr) {
300 FIXME("(): stub !\n");
302 return 0;
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) {
314 void *local_func;
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);
323 return local_func;
326 if (p_glXGetProcAddressARB == NULL) {
327 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
328 return NULL;
331 /* After that, search in the thunks to find the real name of the extension */
332 ext.name = lpszProc;
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;
341 ENTER_GL();
342 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
343 LEAVE_GL();
345 /* After that, look at the extensions defined in the Linux OpenGL library */
346 if (local_func == NULL) {
347 char buf[256];
348 void *ret = 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);
362 if (ret != NULL) {
363 TRACE(" found function in main OpenGL library (%p) !\n", ret);
364 } else {
365 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
368 return ret;
369 } else {
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)
400 TRACE("\n");
401 return wine_wgl.p_wglGetCurrentReadDCARB();
404 /***********************************************************************
405 * wglRealizeLayerPalette (OPENGL32.@)
407 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
408 int iLayerPlane,
409 BOOL bRealize) {
410 FIXME("()\n");
412 return FALSE;
415 /***********************************************************************
416 * wglSetLayerPaletteEntries (OPENGL32.@)
418 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
419 int iLayerPlane,
420 int iStart,
421 int cEntries,
422 const COLORREF *pcr) {
423 FIXME("(): stub !\n");
425 return 0;
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,
440 UINT fuPlanes) {
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;
448 if (fuPlanes) {
449 WARN("Following layers unhandled : %08x\n", fuPlanes);
452 return TRUE;
455 static BOOL internal_wglUseFontBitmaps(HDC hdc,
456 DWORD first,
457 DWORD count,
458 DWORD listBase,
459 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
461 /* We are running using client-side rendering fonts... */
462 GLYPHMETRICS gm;
463 unsigned int glyph;
464 int size = 0;
465 void *bitmap = NULL, *gl_bitmap = NULL;
466 int org_alignment;
468 ENTER_GL();
469 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
470 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
471 LEAVE_GL();
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);
480 goto error;
481 } else {
482 TRACE(" - needed size : %d\n", needed_size);
485 if (needed_size > size) {
486 size = needed_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++) {
503 TRACE(" ");
504 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
505 if (bitmask == 0) {
506 bitmap_ += 1;
507 bitmask = 0x80;
509 if (*bitmap_ & bitmask)
510 TRACE("*");
511 else
512 TRACE(" ");
514 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
515 TRACE("\n");
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++) {
526 int width;
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];
534 ENTER_GL();
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,
540 gl_bitmap);
541 } else {
542 /* This is the case of 'empty' glyphs like the space character */
543 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
545 glEndList();
546 LEAVE_GL();
549 ENTER_GL();
550 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
551 LEAVE_GL();
553 HeapFree(GetProcessHeap(), 0, bitmap);
554 HeapFree(GetProcessHeap(), 0, gl_bitmap);
555 return TRUE;
557 error:
558 ENTER_GL();
559 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
560 LEAVE_GL();
562 HeapFree(GetProcessHeap(), 0, bitmap);
563 HeapFree(GetProcessHeap(), 0, gl_bitmap);
564 return FALSE;
567 /***********************************************************************
568 * wglUseFontBitmapsA (OPENGL32.@)
570 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
571 DWORD first,
572 DWORD count,
573 DWORD listBase)
575 Font fid = get_font( hdc );
577 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
579 if (fid == 0) {
580 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
583 ENTER_GL();
584 /* I assume that the glyphs are at the same position for X and for Windows */
585 glXUseXFont(fid, first, count, listBase);
586 LEAVE_GL();
587 return TRUE;
590 /***********************************************************************
591 * wglUseFontBitmapsW (OPENGL32.@)
593 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
594 DWORD first,
595 DWORD count,
596 DWORD listBase)
598 Font fid = get_font( hdc );
600 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
602 if (fid == 0) {
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");
608 ENTER_GL();
609 /* I assume that the glyphs are at the same position for X and for Windows */
610 glXUseXFont(fid, first, count, listBase);
611 LEAVE_GL();
612 return TRUE;
615 #ifdef HAVE_GL_GLU_H
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;
621 vertex[2] = 0.0;
624 static void tess_callback_vertex(GLvoid *vertex)
626 GLdouble *dbl = vertex;
627 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
628 glVertex3dv(vertex);
631 static void tess_callback_begin(GLenum which)
633 TRACE("%d\n", which);
634 glBegin(which);
637 static void tess_callback_end(void)
639 TRACE("\n");
640 glEnd();
643 /***********************************************************************
644 * wglUseFontOutlines_common
646 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
647 DWORD first,
648 DWORD count,
649 DWORD listBase,
650 FLOAT deviation,
651 FLOAT extrusion,
652 int format,
653 LPGLYPHMETRICSFLOAT lpgmf,
654 BOOL unicode)
656 UINT glyph;
657 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
658 GLUtesselator *tess;
659 LOGFONTW lf;
660 HFONT old_font, unscaled_font;
661 UINT em_size = 1024;
662 RECT rc;
664 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
665 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
668 ENTER_GL();
669 tess = gluNewTess();
670 if(tess)
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);
676 LEAVE_GL();
678 if(!tess) return FALSE;
680 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
681 rc.left = rc.right = rc.bottom = 0;
682 rc.top = em_size;
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++)
691 DWORD needed;
692 GLYPHMETRICS gm;
693 BYTE *buf;
694 TTPOLYGONHEADER *pph;
695 TTPOLYCURVE *ppc;
696 GLdouble *vertices;
698 if(unicode)
699 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
700 else
701 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
703 if(needed == GDI_ERROR)
704 goto error;
706 buf = HeapAlloc(GetProcessHeap(), 0, needed);
707 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
709 if(unicode)
710 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
711 else
712 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
714 TRACE("glyph %d\n", glyph);
716 if(lpgmf)
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);
727 lpgmf++;
730 ENTER_GL();
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);
743 vertices += 3;
745 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
746 while((char*)ppc < (char*)pph + pph->cb)
748 int i;
750 switch(ppc->wType) {
751 case TT_PRIM_LINE:
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);
757 vertices += 3;
759 break;
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);
770 vertices += 3;
771 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
772 gluTessVertex(tess, vertices, vertices);
773 vertices += 3;
775 break;
776 default:
777 ERR("\t\tcurve type = %d\n", ppc->wType);
778 gluTessEndContour(tess);
779 goto error_in_list;
782 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
783 (ppc->cpfx - 1) * sizeof(POINTFX));
785 gluTessEndContour(tess);
786 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
789 error_in_list:
790 gluTessEndPolygon(tess);
791 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
792 glEndList();
793 LEAVE_GL();
794 HeapFree(GetProcessHeap(), 0, buf);
795 HeapFree(GetProcessHeap(), 0, vertices);
798 error:
799 DeleteObject(SelectObject(hdc, old_font));
800 gluDeleteTess(tess);
801 return TRUE;
805 #else /* HAVE_GL_GLU_H */
807 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
808 DWORD first,
809 DWORD count,
810 DWORD listBase,
811 FLOAT deviation,
812 FLOAT extrusion,
813 int format,
814 LPGLYPHMETRICSFLOAT lpgmf,
815 BOOL unicode)
817 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
818 return FALSE;
821 #endif /* HAVE_GL_GLU_H */
823 /***********************************************************************
824 * wglUseFontOutlinesA (OPENGL32.@)
826 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
827 DWORD first,
828 DWORD count,
829 DWORD listBase,
830 FLOAT deviation,
831 FLOAT extrusion,
832 int format,
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,
842 DWORD first,
843 DWORD count,
844 DWORD listBase,
845 FLOAT deviation,
846 FLOAT extrusion,
847 int format,
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");
866 return NULL;
867 } else {
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;
873 char ThisExtn[256];
875 memset(ThisExtn, 0x00, sizeof(ThisExtn));
876 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
877 GL_Extensions++;
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);
886 TRACE(" active\n");
887 } else {
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
909 #ifndef SONAME_LIBGL
910 #define SONAME_LIBGL "libGL.so"
911 #endif
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
924 * rendering is used.
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;
952 } else {
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.
959 if(glx_direct)
960 glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
961 else
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");*/
970 } else {
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");
975 } else {
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;
985 else
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;
998 Visual *rootVisual;
999 int num;
1000 XVisualInfo template;
1001 HDC hdc;
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);
1007 HKEY hkey = 0;
1009 if (!root || !mod)
1011 ERR("X11DRV not loaded. Cannot create default context.\n");
1012 return FALSE;
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");
1031 hdc = GetDC(0);
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");
1037 return FALSE;
1040 ENTER_GL();
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;
1051 else
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);
1062 XFree(vis);
1063 LEAVE_GL();
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);
1078 RegCloseKey(hkey);
1081 if (default_cx == NULL) {
1082 ERR("Could not create default context.\n");
1084 else
1086 /* After context initialize also the list of supported WGL extensions. */
1087 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1089 return TRUE;
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 )
1107 switch(reason)
1109 case DLL_PROCESS_ATTACH:
1110 opengl32_handle = hinst;
1111 DisableThreadLibraryCalls(hinst);
1112 return process_attach();
1113 case DLL_PROCESS_DETACH:
1114 process_detach();
1115 break;
1117 return TRUE;