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 /** global glx object */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
60 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
61 X11DRV_START_EXPOSURES, /* start graphics exposures */
62 X11DRV_END_EXPOSURES, /* end graphics exposures */
63 X11DRV_GET_DCE, /* get the DCE pointer */
64 X11DRV_SET_DCE, /* set the DCE pointer */
65 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
66 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
69 void (*wine_tsx11_lock_ptr)(void) = NULL;
70 void (*wine_tsx11_unlock_ptr)(void) = NULL;
72 static GLXContext default_cx = NULL;
73 static Display *default_display; /* display to use for default context */
75 static HMODULE opengl32_handle;
77 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
79 static char internal_gl_disabled_extensions[512];
80 static char* internal_gl_extensions = NULL;
82 typedef struct wine_glcontext {
89 struct wine_glcontext *next;
90 struct wine_glcontext *prev;
92 static Wine_GLContext *context_list;
94 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
97 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
103 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
105 if (curctx && curctx->do_escape)
107 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
108 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
111 wine_tsx11_lock_ptr();
115 static inline void free_context(Wine_GLContext *context)
117 if (context->next != NULL) context->next->prev = context->prev;
118 if (context->prev != NULL) context->prev->next = context->next;
119 else context_list = context->next;
121 HeapFree(GetProcessHeap(), 0, context);
124 static inline Wine_GLContext *alloc_context(void)
128 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
130 ret->next = context_list;
131 if (context_list) context_list->prev = ret;
137 inline static BOOL is_valid_context( Wine_GLContext *ctx )
140 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
141 return (ptr != NULL);
144 /* retrieve the X display to use on a given DC */
145 inline static Display *get_display( HDC hdc )
148 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
150 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
151 sizeof(display), (LPSTR)&display )) display = NULL;
156 /* retrieve the GLX drawable to use on a given DC */
157 inline static Drawable get_drawable( HDC hdc )
159 GLXDrawable drawable;
160 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
162 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
163 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
167 /** for use of wglGetCurrentReadDCARB */
168 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
171 for (ret = context_list; ret; ret = ret->next) {
172 if (d == get_drawable( ret->hdc )) {
179 /* retrieve the X font to use on a given DC */
180 inline static Font get_font( HDC hdc )
183 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
185 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
186 sizeof(font), (LPSTR)&font )) font = 0;
191 /***********************************************************************
192 * wglCreateContext (OPENGL32.@)
194 HGLRC WINAPI wglCreateContext(HDC hdc)
198 XVisualInfo template;
199 XVisualInfo *vis = NULL;
200 Display *display = get_display( hdc );
201 int hdcPF = GetPixelFormat(hdc);
204 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
206 /* First, get the visual in use by the X11DRV */
207 if (!display) return 0;
208 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
209 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
212 ERR("NULL visual !!!\n");
213 /* Need to set errors here */
217 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
223 GLXFBConfig* cfgs_fmt = NULL;
226 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
227 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
228 ERR("Cannot get FB Configs, expect problems.\n");
229 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
232 if (nCfgs_fmt < hdcPF) {
233 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
234 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
237 cur_cfg = cfgs_fmt[hdcPF - 1];
238 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
240 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
241 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
247 /* The context will be allocated in the wglMakeCurrent call */
249 ret = alloc_context();
252 ret->display = display;
253 ret->fb_conf = cur_cfg;
255 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
257 TRACE(" creating context %p (GL context creation delayed)\n", ret);
261 /***********************************************************************
262 * wglCreateLayerContext (OPENGL32.@)
264 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
266 TRACE("(%p,%d)\n", hdc, iLayerPlane);
268 if (iLayerPlane == 0) {
269 return wglCreateContext(hdc);
271 FIXME(" no handler for layer %d\n", iLayerPlane);
276 /***********************************************************************
277 * wglCopyContext (OPENGL32.@)
279 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
282 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
287 /***********************************************************************
288 * wglDeleteContext (OPENGL32.@)
290 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
292 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
295 TRACE("(%p)\n", hglrc);
298 /* A game (Half Life not to name it) deletes twice the same context,
299 * so make sure it is valid first */
300 if (is_valid_context( ctx ))
302 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
307 WARN("Error deleting context !\n");
308 SetLastError(ERROR_INVALID_HANDLE);
316 /***********************************************************************
317 * wglDescribeLayerPlane (OPENGL32.@)
319 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
323 LPLAYERPLANEDESCRIPTOR plpd) {
324 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
329 /***********************************************************************
330 * wglGetCurrentContext (OPENGL32.@)
332 HGLRC WINAPI wglGetCurrentContext(void) {
339 gl_ctx = glXGetCurrentContext();
340 ret = get_context_from_GLXContext(gl_ctx);
343 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
348 /***********************************************************************
349 * wglGetCurrentDC (OPENGL32.@)
351 HDC WINAPI wglGetCurrentDC(void) {
358 gl_ctx = glXGetCurrentContext();
359 ret = get_context_from_GLXContext(gl_ctx);
363 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
366 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
371 /***********************************************************************
372 * wglGetLayerPaletteEntries (OPENGL32.@)
374 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
378 const COLORREF *pcr) {
379 FIXME("(): stub !\n");
384 /***********************************************************************
385 * wglGetProcAddress (OPENGL32.@)
387 static int compar(const void *elt_a, const void *elt_b) {
388 return strcmp(((const OpenGL_extension *) elt_a)->name,
389 ((const OpenGL_extension *) elt_b)->name);
392 static int wgl_compar(const void *elt_a, const void *elt_b) {
393 return strcmp(((const WGL_extension *) elt_a)->func_name,
394 ((const WGL_extension *) elt_b)->func_name);
397 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
399 OpenGL_extension ext;
400 OpenGL_extension *ext_ret;
402 TRACE("(%s)\n", lpszProc);
404 /* First, look if it's not already defined in the 'standard' OpenGL functions */
405 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
406 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
410 if (p_glXGetProcAddressARB == NULL) {
411 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
415 /* After that, search in the thunks to find the real name of the extension */
416 ext.name = (char *) lpszProc;
417 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
418 extension_registry_size, sizeof(OpenGL_extension), compar);
420 if (ext_ret == NULL) {
421 WGL_extension wgl_ext, *wgl_ext_ret;
423 /* Try to find the function in the WGL extensions ... */
424 wgl_ext.func_name = (char *) lpszProc;
425 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
426 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
428 if (wgl_ext_ret == NULL) {
429 /* Some sanity checks :-) */
431 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
433 if (local_func != NULL) {
434 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
438 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
443 if (wgl_ext_ret->func_init != NULL) {
445 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
446 wgl_ext_ret->context)) == NULL) {
447 ret = wgl_ext_ret->func_address;
449 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
453 ret = wgl_ext_ret->func_address;
457 TRACE(" returning WGL function (%p)\n", ret);
462 local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
465 /* After that, look at the extensions defined in the Linux OpenGL library */
466 if (local_func == NULL) {
470 /* Remove the 3 last letters (EXT, ARB, ...).
472 I know that some extensions have more than 3 letters (MESA, NV,
473 INTEL, ...), but this is only a stop-gap measure to fix buggy
474 OpenGL drivers (moreover, it is only useful for old 1.0 apps
475 that query the glBindTextureEXT extension).
477 memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
478 buf[strlen(ext_ret->glx_name) - 3] = '\0';
479 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
481 ret = GetProcAddress(opengl32_handle, buf);
483 TRACE(" found function in main OpenGL library (%p) !\n", ret);
485 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
490 TRACE(" returning function (%p)\n", ext_ret->func);
491 *(ext_ret->func_ptr) = local_func;
493 return ext_ret->func;
498 static int describeContext(Wine_GLContext* ctx) {
501 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
502 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
503 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
504 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
505 TRACE(" - VISUAL_ID 0x%x\n", tmp);
510 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
513 int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
516 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
517 /** glXQueryDrawable not available so returns not supported */
521 TRACE(" Drawable %p have :\n", (void*) drawable);
522 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
523 TRACE(" - WIDTH as %d\n", tmp);
524 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
525 TRACE(" - HEIGHT as %d\n", tmp);
526 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
527 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
530 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
531 if (fbCfgs == NULL) {
535 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
536 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
543 /***********************************************************************
544 * wglMakeCurrent (OPENGL32.@)
546 BOOL WINAPI wglMakeCurrent(HDC hdc,
549 DWORD type = GetObjectType(hdc);
551 TRACE("(%p,%p)\n", hdc, hglrc);
555 ret = glXMakeCurrent(default_display, None, NULL);
556 NtCurrentTeb()->glContext = NULL;
558 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
559 Drawable drawable = get_drawable( hdc );
560 if (ctx->ctx == NULL) {
561 int draw_vis_id, ctx_vis_id;
562 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
563 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
564 draw_vis_id = describeDrawable(ctx, drawable);
565 ctx_vis_id = describeContext(ctx);
567 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
569 * Inherits from root window so reuse desktop visual
571 XVisualInfo template;
574 template.visualid = visualid;
575 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
577 TRACE(" Creating GLX Context\n");
578 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
580 TRACE(" Creating GLX Context\n");
581 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
583 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
585 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
586 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
587 NtCurrentTeb()->glContext = ctx;
588 if(ret && type == OBJ_MEMDC)
590 ctx->do_escape = TRUE;
591 glDrawBuffer(GL_FRONT_LEFT);
595 TRACE(" returning %s\n", (ret ? "True" : "False"));
599 /***********************************************************************
600 * wglMakeContextCurrentARB (OPENGL32.@)
602 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
605 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
609 ret = glXMakeCurrent(default_display, None, NULL);
611 if (NULL == wine_glx.p_glXMakeContextCurrent) {
614 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
615 Drawable d_draw = get_drawable( hDrawDC );
616 Drawable d_read = get_drawable( hReadDC );
618 if (ctx->ctx == NULL) {
619 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
620 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
622 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
627 TRACE(" returning %s\n", (ret ? "True" : "False"));
631 /***********************************************************************
632 * wglGetCurrentReadDCARB (OPENGL32.@)
634 HDC WINAPI wglGetCurrentReadDCARB(void)
642 gl_d = glXGetCurrentReadDrawable();
643 ret = get_hdc_from_Drawable(gl_d);
646 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
652 /***********************************************************************
653 * wglRealizeLayerPalette (OPENGL32.@)
655 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
663 /***********************************************************************
664 * wglSetLayerPaletteEntries (OPENGL32.@)
666 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
670 const COLORREF *pcr) {
671 FIXME("(): stub !\n");
676 /***********************************************************************
677 * wglShareLists (OPENGL32.@)
679 BOOL WINAPI wglShareLists(HGLRC hglrc1,
681 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
682 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
684 TRACE("(%p, %p)\n", org, dest);
686 if (NULL != dest && dest->ctx != NULL) {
687 ERR("Could not share display lists, context already created !\n");
690 if (org->ctx == NULL) {
692 describeContext(org);
693 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
695 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
699 describeContext(dest);
700 /* Create the destination context with display lists shared */
701 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
703 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
710 /***********************************************************************
711 * wglSwapLayerBuffers (OPENGL32.@)
713 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
715 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
717 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
718 if (!SwapBuffers(hdc)) return FALSE;
719 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
723 WARN("Following layers unhandled : %08x\n", fuPlanes);
729 static BOOL internal_wglUseFontBitmaps(HDC hdc,
733 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
735 /* We are running using client-side rendering fonts... */
739 void *bitmap = NULL, *gl_bitmap = NULL;
743 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
744 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
747 for (glyph = first; glyph < first + count; glyph++) {
748 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
749 int height, width_int;
751 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
752 if (needed_size == GDI_ERROR) {
753 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
756 TRACE(" - needed size : %d\n", needed_size);
759 if (needed_size > size) {
761 HeapFree(GetProcessHeap(), 0, bitmap);
762 HeapFree(GetProcessHeap(), 0, gl_bitmap);
763 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
764 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
766 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
767 if (TRACE_ON(opengl)) {
768 unsigned int height, width, bitmask;
769 unsigned char *bitmap_ = (unsigned char *) bitmap;
771 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
772 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
773 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
774 if (needed_size != 0) {
775 TRACE(" - bitmap :\n");
776 for (height = 0; height < gm.gmBlackBoxY; height++) {
778 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
783 if (*bitmap_ & bitmask)
788 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
794 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
795 * glyph for it to be drawn properly.
797 if (needed_size != 0) {
798 width_int = (gm.gmBlackBoxX + 31) / 32;
799 for (height = 0; height < gm.gmBlackBoxY; height++) {
801 for (width = 0; width < width_int; width++) {
802 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
803 ((int *) bitmap)[height * width_int + width];
809 glNewList(listBase++, GL_COMPILE);
810 if (needed_size != 0) {
811 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
812 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
813 gm.gmCellIncX, gm.gmCellIncY,
816 /* This is the case of 'empty' glyphs like the space character */
817 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
824 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
827 HeapFree(GetProcessHeap(), 0, bitmap);
828 HeapFree(GetProcessHeap(), 0, gl_bitmap);
833 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
836 HeapFree(GetProcessHeap(), 0, bitmap);
837 HeapFree(GetProcessHeap(), 0, gl_bitmap);
841 /***********************************************************************
842 * wglUseFontBitmapsA (OPENGL32.@)
844 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
849 Font fid = get_font( hdc );
851 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
854 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
858 /* I assume that the glyphs are at the same position for X and for Windows */
859 glXUseXFont(fid, first, count, listBase);
864 /***********************************************************************
865 * wglUseFontBitmapsW (OPENGL32.@)
867 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
872 Font fid = get_font( hdc );
874 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
877 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
880 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
883 /* I assume that the glyphs are at the same position for X and for Windows */
884 glXUseXFont(fid, first, count, listBase);
891 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
893 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
894 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
898 static void tess_callback_vertex(GLvoid *vertex)
900 GLdouble *dbl = vertex;
901 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
905 static void tess_callback_begin(GLenum which)
907 TRACE("%d\n", which);
911 static void tess_callback_end(void)
917 /***********************************************************************
918 * wglUseFontOutlines_common
920 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
927 LPGLYPHMETRICSFLOAT lpgmf,
931 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
934 HFONT old_font, unscaled_font;
938 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
939 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
946 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
947 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
948 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
952 if(!tess) return FALSE;
954 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
955 rc.left = rc.right = rc.bottom = 0;
957 DPtoLP(hdc, (POINT*)&rc, 2);
958 lf.lfHeight = -abs(rc.top - rc.bottom);
959 lf.lfOrientation = lf.lfEscapement = 0;
960 unscaled_font = CreateFontIndirectW(&lf);
961 old_font = SelectObject(hdc, unscaled_font);
963 for (glyph = first; glyph < first + count; glyph++)
968 TTPOLYGONHEADER *pph;
973 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
975 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
977 if(needed == GDI_ERROR)
980 buf = HeapAlloc(GetProcessHeap(), 0, needed);
981 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
984 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
986 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
988 TRACE("glyph %d\n", glyph);
992 lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
993 lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
994 lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
995 lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
996 lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
997 lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
998 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
999 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
1004 glNewList(listBase++, GL_COMPILE);
1005 gluTessBeginPolygon(tess, NULL);
1007 pph = (TTPOLYGONHEADER*)buf;
1008 while((BYTE*)pph < buf + needed)
1010 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1012 gluTessBeginContour(tess);
1014 fixed_to_double(pph->pfxStart, em_size, vertices);
1015 gluTessVertex(tess, vertices, vertices);
1018 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1019 while((char*)ppc < (char*)pph + pph->cb)
1023 switch(ppc->wType) {
1025 for(i = 0; i < ppc->cpfx; i++)
1027 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1028 fixed_to_double(ppc->apfx[i], em_size, vertices);
1029 gluTessVertex(tess, vertices, vertices);
1034 case TT_PRIM_QSPLINE:
1035 for(i = 0; i < ppc->cpfx/2; i++)
1037 /* FIXME just connecting the control points for now */
1038 TRACE("\t\tcurve %d,%d %d,%d\n",
1039 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1040 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1041 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1042 gluTessVertex(tess, vertices, vertices);
1044 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1045 gluTessVertex(tess, vertices, vertices);
1050 ERR("\t\tcurve type = %d\n", ppc->wType);
1051 gluTessEndContour(tess);
1055 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1056 (ppc->cpfx - 1) * sizeof(POINTFX));
1058 gluTessEndContour(tess);
1059 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1063 gluTessEndPolygon(tess);
1066 HeapFree(GetProcessHeap(), 0, buf);
1067 HeapFree(GetProcessHeap(), 0, vertices);
1071 DeleteObject(SelectObject(hdc, old_font));
1072 gluDeleteTess(tess);
1077 #else /* HAVE_GL_GLU_H */
1079 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1086 LPGLYPHMETRICSFLOAT lpgmf,
1089 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1093 #endif /* HAVE_GL_GLU_H */
1095 /***********************************************************************
1096 * wglUseFontOutlinesA (OPENGL32.@)
1098 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1105 LPGLYPHMETRICSFLOAT lpgmf)
1107 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1110 /***********************************************************************
1111 * wglUseFontOutlinesW (OPENGL32.@)
1113 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1120 LPGLYPHMETRICSFLOAT lpgmf)
1122 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1125 const GLubyte * internal_glGetString(GLenum name) {
1126 const char* GL_Extensions = NULL;
1128 if (GL_EXTENSIONS != name) {
1129 return glGetString(name);
1132 if (NULL == internal_gl_extensions) {
1133 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1135 TRACE("GL_EXTENSIONS reported:\n");
1136 if (NULL == GL_Extensions) {
1137 ERR("GL_EXTENSIONS returns NULL\n");
1140 size_t len = strlen(GL_Extensions);
1141 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1143 while (*GL_Extensions != 0x00) {
1144 const char* Start = GL_Extensions;
1147 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1148 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1151 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1152 TRACE("- %s:", ThisExtn);
1154 /* test if supported API is disabled by config */
1155 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1156 strcat(internal_gl_extensions, " ");
1157 strcat(internal_gl_extensions, ThisExtn);
1160 TRACE(" deactived (by config)\n");
1163 if (*GL_Extensions == ' ') GL_Extensions++;
1167 return (const GLubyte *) internal_gl_extensions;
1170 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1171 glGetIntegerv(pname, params);
1172 if (pname == GL_DEPTH_BITS) {
1173 GLXContext gl_ctx = glXGetCurrentContext();
1174 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1175 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1177 * if we cannot find a Wine Context
1178 * we only have the default wine desktop context,
1179 * so if we have only a 24 depth say we have 32
1181 if (NULL == ret && 24 == *params) {
1184 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1186 if (pname == GL_ALPHA_BITS) {
1188 GLXContext gl_ctx = glXGetCurrentContext();
1189 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1190 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1191 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1197 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1198 include all dependencies
1200 #ifndef SONAME_LIBGL
1201 #define SONAME_LIBGL "libGL.so"
1204 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1206 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1207 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1209 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1210 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1211 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1214 memset(&wine_glx, 0, sizeof(wine_glx));
1216 if (!strcmp("1.2", server_glx_version)) {
1217 wine_glx.version = 2;
1219 wine_glx.version = 3;
1222 if (2 < wine_glx.version) {
1223 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1224 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1225 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1227 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1228 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1230 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1231 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1232 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1233 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1235 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1238 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1239 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1240 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1243 /* This is for brain-dead applications that use OpenGL functions before even
1244 creating a rendering context.... */
1245 static BOOL process_attach(void)
1247 XWindowAttributes win_attr;
1250 XVisualInfo template;
1252 XVisualInfo *vis = NULL;
1253 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1254 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1255 void *opengl_handle;
1256 DWORD size = sizeof(internal_gl_disabled_extensions);
1261 ERR("X11DRV not loaded. Cannot create default context.\n");
1265 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1266 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1269 default_display = get_display( hdc );
1270 ReleaseDC( 0, hdc );
1271 if (!default_display)
1273 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1279 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1280 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1281 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1282 with mismatched visuals. Note that the Root Window visual may not be double
1283 buffered, so apps actually attempting to render this way may flicker */
1284 if (XGetWindowAttributes( default_display, root, &win_attr ))
1286 rootVisual = win_attr.visual;
1290 /* Get the default visual, since we can't seem to get the attributes from the
1291 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1292 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1295 template.visualid = XVisualIDFromVisual(rootVisual);
1296 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1297 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1298 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1302 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1303 if (opengl_handle != NULL) {
1304 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1305 wine_dlclose(opengl_handle, NULL, 0);
1306 if (p_glXGetProcAddressARB == NULL)
1307 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1310 internal_gl_disabled_extensions[0] = 0;
1311 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1312 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1313 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1318 if (default_cx == NULL) {
1319 ERR("Could not create default context.\n");
1323 /* After context initialize also the list of supported WGL extensions. */
1324 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1325 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1331 /**********************************************************************/
1333 static void process_detach(void)
1335 glXDestroyContext(default_display, default_cx);
1337 /* Do not leak memory... */
1338 wgl_ext_finalize_extensions();
1339 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1342 /***********************************************************************
1343 * OpenGL initialisation routine
1345 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1349 case DLL_PROCESS_ATTACH:
1350 opengl32_handle = hinst;
1351 DisableThreadLibraryCalls(hinst);
1352 return process_attach();
1353 case DLL_PROCESS_DETACH: