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 const 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 */
417 ext_ret = (const 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);
461 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
463 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
466 /* After that, look at the extensions defined in the Linux OpenGL library */
467 if (local_func == NULL) {
471 /* Remove the 3 last letters (EXT, ARB, ...).
473 I know that some extensions have more than 3 letters (MESA, NV,
474 INTEL, ...), but this is only a stop-gap measure to fix buggy
475 OpenGL drivers (moreover, it is only useful for old 1.0 apps
476 that query the glBindTextureEXT extension).
478 memcpy(buf, glx_name, strlen(glx_name) - 3);
479 buf[strlen(glx_name) - 3] = '\0';
480 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
482 ret = GetProcAddress(opengl32_handle, buf);
484 TRACE(" found function in main OpenGL library (%p) !\n", ret);
486 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
491 TRACE(" returning function (%p)\n", ext_ret->func);
492 extension_funcs[ext_ret - extension_registry] = local_func;
494 return ext_ret->func;
499 static int describeContext(Wine_GLContext* ctx) {
502 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
503 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
504 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
505 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
506 TRACE(" - VISUAL_ID 0x%x\n", tmp);
511 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
514 int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
517 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
518 /** glXQueryDrawable not available so returns not supported */
522 TRACE(" Drawable %p have :\n", (void*) drawable);
523 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
524 TRACE(" - WIDTH as %d\n", tmp);
525 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
526 TRACE(" - HEIGHT as %d\n", tmp);
527 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
528 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
531 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
532 if (fbCfgs == NULL) {
536 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
537 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
544 /***********************************************************************
545 * wglMakeCurrent (OPENGL32.@)
547 BOOL WINAPI wglMakeCurrent(HDC hdc,
550 DWORD type = GetObjectType(hdc);
552 TRACE("(%p,%p)\n", hdc, hglrc);
556 ret = glXMakeCurrent(default_display, None, NULL);
557 NtCurrentTeb()->glContext = NULL;
559 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
560 Drawable drawable = get_drawable( hdc );
561 if (ctx->ctx == NULL) {
562 int draw_vis_id, ctx_vis_id;
563 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
564 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
565 draw_vis_id = describeDrawable(ctx, drawable);
566 ctx_vis_id = describeContext(ctx);
568 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
570 * Inherits from root window so reuse desktop visual
572 XVisualInfo template;
575 template.visualid = visualid;
576 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
578 TRACE(" Creating GLX Context\n");
579 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
581 TRACE(" Creating GLX Context\n");
582 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
584 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
586 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
587 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
588 NtCurrentTeb()->glContext = ctx;
589 if(ret && type == OBJ_MEMDC)
591 ctx->do_escape = TRUE;
592 glDrawBuffer(GL_FRONT_LEFT);
596 TRACE(" returning %s\n", (ret ? "True" : "False"));
600 /***********************************************************************
601 * wglMakeContextCurrentARB (OPENGL32.@)
603 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
606 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
610 ret = glXMakeCurrent(default_display, None, NULL);
612 if (NULL == wine_glx.p_glXMakeContextCurrent) {
615 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
616 Drawable d_draw = get_drawable( hDrawDC );
617 Drawable d_read = get_drawable( hReadDC );
619 if (ctx->ctx == NULL) {
620 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
621 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
623 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
628 TRACE(" returning %s\n", (ret ? "True" : "False"));
632 /***********************************************************************
633 * wglGetCurrentReadDCARB (OPENGL32.@)
635 HDC WINAPI wglGetCurrentReadDCARB(void)
643 gl_d = glXGetCurrentReadDrawable();
644 ret = get_hdc_from_Drawable(gl_d);
647 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
653 /***********************************************************************
654 * wglRealizeLayerPalette (OPENGL32.@)
656 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
664 /***********************************************************************
665 * wglSetLayerPaletteEntries (OPENGL32.@)
667 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
671 const COLORREF *pcr) {
672 FIXME("(): stub !\n");
677 /***********************************************************************
678 * wglShareLists (OPENGL32.@)
680 BOOL WINAPI wglShareLists(HGLRC hglrc1,
682 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
683 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
685 TRACE("(%p, %p)\n", org, dest);
687 if (NULL != dest && dest->ctx != NULL) {
688 ERR("Could not share display lists, context already created !\n");
691 if (org->ctx == NULL) {
693 describeContext(org);
694 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
696 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
700 describeContext(dest);
701 /* Create the destination context with display lists shared */
702 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
704 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
711 /***********************************************************************
712 * wglSwapLayerBuffers (OPENGL32.@)
714 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
716 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
718 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
719 if (!SwapBuffers(hdc)) return FALSE;
720 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
724 WARN("Following layers unhandled : %08x\n", fuPlanes);
730 static BOOL internal_wglUseFontBitmaps(HDC hdc,
734 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
736 /* We are running using client-side rendering fonts... */
740 void *bitmap = NULL, *gl_bitmap = NULL;
744 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
745 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
748 for (glyph = first; glyph < first + count; glyph++) {
749 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
750 int height, width_int;
752 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
753 if (needed_size == GDI_ERROR) {
754 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
757 TRACE(" - needed size : %d\n", needed_size);
760 if (needed_size > size) {
762 HeapFree(GetProcessHeap(), 0, bitmap);
763 HeapFree(GetProcessHeap(), 0, gl_bitmap);
764 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
765 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
767 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
768 if (TRACE_ON(opengl)) {
769 unsigned int height, width, bitmask;
770 unsigned char *bitmap_ = (unsigned char *) bitmap;
772 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
773 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
774 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
775 if (needed_size != 0) {
776 TRACE(" - bitmap :\n");
777 for (height = 0; height < gm.gmBlackBoxY; height++) {
779 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
784 if (*bitmap_ & bitmask)
789 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
795 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
796 * glyph for it to be drawn properly.
798 if (needed_size != 0) {
799 width_int = (gm.gmBlackBoxX + 31) / 32;
800 for (height = 0; height < gm.gmBlackBoxY; height++) {
802 for (width = 0; width < width_int; width++) {
803 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
804 ((int *) bitmap)[height * width_int + width];
810 glNewList(listBase++, GL_COMPILE);
811 if (needed_size != 0) {
812 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
813 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
814 gm.gmCellIncX, gm.gmCellIncY,
817 /* This is the case of 'empty' glyphs like the space character */
818 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
825 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
828 HeapFree(GetProcessHeap(), 0, bitmap);
829 HeapFree(GetProcessHeap(), 0, gl_bitmap);
834 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
837 HeapFree(GetProcessHeap(), 0, bitmap);
838 HeapFree(GetProcessHeap(), 0, gl_bitmap);
842 /***********************************************************************
843 * wglUseFontBitmapsA (OPENGL32.@)
845 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
850 Font fid = get_font( hdc );
852 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
855 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
859 /* I assume that the glyphs are at the same position for X and for Windows */
860 glXUseXFont(fid, first, count, listBase);
865 /***********************************************************************
866 * wglUseFontBitmapsW (OPENGL32.@)
868 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
873 Font fid = get_font( hdc );
875 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
878 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
881 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
884 /* I assume that the glyphs are at the same position for X and for Windows */
885 glXUseXFont(fid, first, count, listBase);
892 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
894 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
895 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
899 static void tess_callback_vertex(GLvoid *vertex)
901 GLdouble *dbl = vertex;
902 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
906 static void tess_callback_begin(GLenum which)
908 TRACE("%d\n", which);
912 static void tess_callback_end(void)
918 /***********************************************************************
919 * wglUseFontOutlines_common
921 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
928 LPGLYPHMETRICSFLOAT lpgmf,
932 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
935 HFONT old_font, unscaled_font;
939 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
940 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
947 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
948 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
949 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
953 if(!tess) return FALSE;
955 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
956 rc.left = rc.right = rc.bottom = 0;
958 DPtoLP(hdc, (POINT*)&rc, 2);
959 lf.lfHeight = -abs(rc.top - rc.bottom);
960 lf.lfOrientation = lf.lfEscapement = 0;
961 unscaled_font = CreateFontIndirectW(&lf);
962 old_font = SelectObject(hdc, unscaled_font);
964 for (glyph = first; glyph < first + count; glyph++)
969 TTPOLYGONHEADER *pph;
974 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
976 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
978 if(needed == GDI_ERROR)
981 buf = HeapAlloc(GetProcessHeap(), 0, needed);
982 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
985 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
987 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
989 TRACE("glyph %d\n", glyph);
993 lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
994 lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
995 lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
996 lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
997 lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
998 lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
999 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1000 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
1005 glNewList(listBase++, GL_COMPILE);
1006 gluTessBeginPolygon(tess, NULL);
1008 pph = (TTPOLYGONHEADER*)buf;
1009 while((BYTE*)pph < buf + needed)
1011 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1013 gluTessBeginContour(tess);
1015 fixed_to_double(pph->pfxStart, em_size, vertices);
1016 gluTessVertex(tess, vertices, vertices);
1019 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1020 while((char*)ppc < (char*)pph + pph->cb)
1024 switch(ppc->wType) {
1026 for(i = 0; i < ppc->cpfx; i++)
1028 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1029 fixed_to_double(ppc->apfx[i], em_size, vertices);
1030 gluTessVertex(tess, vertices, vertices);
1035 case TT_PRIM_QSPLINE:
1036 for(i = 0; i < ppc->cpfx/2; i++)
1038 /* FIXME just connecting the control points for now */
1039 TRACE("\t\tcurve %d,%d %d,%d\n",
1040 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1041 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1042 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1043 gluTessVertex(tess, vertices, vertices);
1045 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1046 gluTessVertex(tess, vertices, vertices);
1051 ERR("\t\tcurve type = %d\n", ppc->wType);
1052 gluTessEndContour(tess);
1056 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1057 (ppc->cpfx - 1) * sizeof(POINTFX));
1059 gluTessEndContour(tess);
1060 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1064 gluTessEndPolygon(tess);
1067 HeapFree(GetProcessHeap(), 0, buf);
1068 HeapFree(GetProcessHeap(), 0, vertices);
1072 DeleteObject(SelectObject(hdc, old_font));
1073 gluDeleteTess(tess);
1078 #else /* HAVE_GL_GLU_H */
1080 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1087 LPGLYPHMETRICSFLOAT lpgmf,
1090 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1094 #endif /* HAVE_GL_GLU_H */
1096 /***********************************************************************
1097 * wglUseFontOutlinesA (OPENGL32.@)
1099 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1106 LPGLYPHMETRICSFLOAT lpgmf)
1108 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1111 /***********************************************************************
1112 * wglUseFontOutlinesW (OPENGL32.@)
1114 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1121 LPGLYPHMETRICSFLOAT lpgmf)
1123 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1126 const GLubyte * internal_glGetString(GLenum name) {
1127 const char* GL_Extensions = NULL;
1129 if (GL_EXTENSIONS != name) {
1130 return glGetString(name);
1133 if (NULL == internal_gl_extensions) {
1134 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1136 TRACE("GL_EXTENSIONS reported:\n");
1137 if (NULL == GL_Extensions) {
1138 ERR("GL_EXTENSIONS returns NULL\n");
1141 size_t len = strlen(GL_Extensions);
1142 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1144 while (*GL_Extensions != 0x00) {
1145 const char* Start = GL_Extensions;
1148 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1149 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1152 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1153 TRACE("- %s:", ThisExtn);
1155 /* test if supported API is disabled by config */
1156 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1157 strcat(internal_gl_extensions, " ");
1158 strcat(internal_gl_extensions, ThisExtn);
1161 TRACE(" deactived (by config)\n");
1164 if (*GL_Extensions == ' ') GL_Extensions++;
1168 return (const GLubyte *) internal_gl_extensions;
1171 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1172 glGetIntegerv(pname, params);
1173 if (pname == GL_DEPTH_BITS) {
1174 GLXContext gl_ctx = glXGetCurrentContext();
1175 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1176 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1178 * if we cannot find a Wine Context
1179 * we only have the default wine desktop context,
1180 * so if we have only a 24 depth say we have 32
1182 if (NULL == ret && 24 == *params) {
1185 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1187 if (pname == GL_ALPHA_BITS) {
1189 GLXContext gl_ctx = glXGetCurrentContext();
1190 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1191 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1192 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1198 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1199 include all dependencies
1201 #ifndef SONAME_LIBGL
1202 #define SONAME_LIBGL "libGL.so"
1205 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1207 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1208 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1210 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1211 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1212 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1215 memset(&wine_glx, 0, sizeof(wine_glx));
1217 if (!strcmp("1.2", server_glx_version)) {
1218 wine_glx.version = 2;
1220 wine_glx.version = 3;
1223 if (2 < wine_glx.version) {
1224 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1225 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1226 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1228 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1229 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1231 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1232 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1233 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1234 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1236 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1239 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1240 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1241 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1244 /* This is for brain-dead applications that use OpenGL functions before even
1245 creating a rendering context.... */
1246 static BOOL process_attach(void)
1248 XWindowAttributes win_attr;
1251 XVisualInfo template;
1253 XVisualInfo *vis = NULL;
1254 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1255 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1256 void *opengl_handle;
1257 DWORD size = sizeof(internal_gl_disabled_extensions);
1262 ERR("X11DRV not loaded. Cannot create default context.\n");
1266 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1267 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1270 default_display = get_display( hdc );
1271 ReleaseDC( 0, hdc );
1272 if (!default_display)
1274 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1280 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1281 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1282 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1283 with mismatched visuals. Note that the Root Window visual may not be double
1284 buffered, so apps actually attempting to render this way may flicker */
1285 if (XGetWindowAttributes( default_display, root, &win_attr ))
1287 rootVisual = win_attr.visual;
1291 /* Get the default visual, since we can't seem to get the attributes from the
1292 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1293 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1296 template.visualid = XVisualIDFromVisual(rootVisual);
1297 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1298 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1299 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1303 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1304 if (opengl_handle != NULL) {
1305 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1306 wine_dlclose(opengl_handle, NULL, 0);
1307 if (p_glXGetProcAddressARB == NULL)
1308 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1311 internal_gl_disabled_extensions[0] = 0;
1312 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1313 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1314 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1319 if (default_cx == NULL) {
1320 ERR("Could not create default context.\n");
1324 /* After context initialize also the list of supported WGL extensions. */
1325 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1326 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1332 /**********************************************************************/
1334 static void process_detach(void)
1336 glXDestroyContext(default_display, default_cx);
1338 /* Do not leak memory... */
1339 wgl_ext_finalize_extensions();
1340 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1343 /***********************************************************************
1344 * OpenGL initialisation routine
1346 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1350 case DLL_PROCESS_ATTACH:
1351 opengl32_handle = hinst;
1352 DisableThreadLibraryCalls(hinst);
1353 return process_attach();
1354 case DLL_PROCESS_DETACH: