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 if (!ctx
) return NULL
;
98 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
104 Wine_GLContext
*curctx
= (Wine_GLContext
*) NtCurrentTeb()->glContext
;
106 if (curctx
&& curctx
->do_escape
)
108 enum x11drv_escape_codes escape
= X11DRV_SYNC_PIXMAP
;
109 ExtEscape(curctx
->hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
, 0, NULL
);
112 wine_tsx11_lock_ptr();
116 static inline void free_context(Wine_GLContext
*context
)
118 if (context
->next
!= NULL
) context
->next
->prev
= context
->prev
;
119 if (context
->prev
!= NULL
) context
->prev
->next
= context
->next
;
120 else context_list
= context
->next
;
122 HeapFree(GetProcessHeap(), 0, context
);
125 static inline Wine_GLContext
*alloc_context(void)
129 if ((ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(Wine_GLContext
))))
131 ret
->next
= context_list
;
132 if (context_list
) context_list
->prev
= ret
;
138 inline static BOOL
is_valid_context( Wine_GLContext
*ctx
)
141 for (ptr
= context_list
; ptr
; ptr
= ptr
->next
) if (ptr
== ctx
) break;
142 return (ptr
!= NULL
);
145 /* retrieve the X display to use on a given DC */
146 inline static Display
*get_display( HDC hdc
)
149 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
151 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
152 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
157 /* retrieve the GLX drawable to use on a given DC */
158 inline static Drawable
get_drawable( HDC hdc
)
160 GLXDrawable drawable
;
161 enum x11drv_escape_codes escape
= X11DRV_GET_GLX_DRAWABLE
;
163 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
164 sizeof(drawable
), (LPSTR
)&drawable
)) drawable
= 0;
168 /** for use of wglGetCurrentReadDCARB */
169 inline static HDC
get_hdc_from_Drawable(GLXDrawable d
)
172 for (ret
= context_list
; ret
; ret
= ret
->next
) {
173 if (d
== get_drawable( ret
->hdc
)) {
180 /* retrieve the X font to use on a given DC */
181 inline static Font
get_font( HDC hdc
)
184 enum x11drv_escape_codes escape
= X11DRV_GET_FONT
;
186 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
187 sizeof(font
), (LPSTR
)&font
)) font
= 0;
192 /***********************************************************************
193 * wglCreateContext (OPENGL32.@)
195 HGLRC WINAPI
wglCreateContext(HDC hdc
)
199 XVisualInfo
template;
200 XVisualInfo
*vis
= NULL
;
201 Display
*display
= get_display( hdc
);
202 int hdcPF
= GetPixelFormat(hdc
);
205 TRACE("(%p)->(PF:%d)\n", hdc
, hdcPF
);
207 /* First, get the visual in use by the X11DRV */
208 if (!display
) return 0;
209 template.visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
210 vis
= XGetVisualInfo(display
, VisualIDMask
, &template, &num
);
213 ERR("NULL visual !!!\n");
214 /* Need to set errors here */
218 SetLastError(ERROR_INVALID_PIXEL_FORMAT
);
224 GLXFBConfig
* cfgs_fmt
= NULL
;
227 cfgs_fmt
= wine_glx
.p_glXGetFBConfigs(display
, DefaultScreen(display
), &nCfgs_fmt
);
228 if (NULL
== cfgs_fmt
|| 0 == nCfgs_fmt
) {
229 ERR("Cannot get FB Configs, expect problems.\n");
230 SetLastError(ERROR_INVALID_PIXEL_FORMAT
);
233 if (nCfgs_fmt
< hdcPF
) {
234 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc
, hdcPF
, nCfgs_fmt
);
235 SetLastError(ERROR_INVALID_PIXEL_FORMAT
);
238 cur_cfg
= cfgs_fmt
[hdcPF
- 1];
239 gl_test
= wine_glx
.p_glXGetFBConfigAttrib(display
, cur_cfg
, GLX_FBCONFIG_ID
, &value
);
241 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
242 SetLastError(ERROR_INVALID_PIXEL_FORMAT
);
248 /* The context will be allocated in the wglMakeCurrent call */
250 ret
= alloc_context();
253 ret
->display
= display
;
254 ret
->fb_conf
= cur_cfg
;
256 ret
->vis
= wine_glx
.p_glXGetVisualFromFBConfig(display
, cur_cfg
);
258 TRACE(" creating context %p (GL context creation delayed)\n", ret
);
262 /***********************************************************************
263 * wglCreateLayerContext (OPENGL32.@)
265 HGLRC WINAPI
wglCreateLayerContext(HDC hdc
,
267 TRACE("(%p,%d)\n", hdc
, iLayerPlane
);
269 if (iLayerPlane
== 0) {
270 return wglCreateContext(hdc
);
272 FIXME(" no handler for layer %d\n", iLayerPlane
);
277 /***********************************************************************
278 * wglCopyContext (OPENGL32.@)
280 BOOL WINAPI
wglCopyContext(HGLRC hglrcSrc
,
283 FIXME("(%p,%p,%d)\n", hglrcSrc
, hglrcDst
, mask
);
288 /***********************************************************************
289 * wglDeleteContext (OPENGL32.@)
291 BOOL WINAPI
wglDeleteContext(HGLRC hglrc
)
293 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
296 TRACE("(%p)\n", hglrc
);
299 /* A game (Half Life not to name it) deletes twice the same context,
300 * so make sure it is valid first */
301 if (is_valid_context( ctx
))
303 if (ctx
->ctx
) glXDestroyContext(ctx
->display
, ctx
->ctx
);
308 WARN("Error deleting context !\n");
309 SetLastError(ERROR_INVALID_HANDLE
);
317 /***********************************************************************
318 * wglDescribeLayerPlane (OPENGL32.@)
320 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
324 LPLAYERPLANEDESCRIPTOR plpd
) {
325 FIXME("(%p,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
330 /***********************************************************************
331 * wglGetCurrentContext (OPENGL32.@)
333 HGLRC WINAPI
wglGetCurrentContext(void) {
340 gl_ctx
= glXGetCurrentContext();
341 ret
= get_context_from_GLXContext(gl_ctx
);
344 TRACE(" returning %p (GL context %p)\n", ret
, gl_ctx
);
349 /***********************************************************************
350 * wglGetCurrentDC (OPENGL32.@)
352 HDC WINAPI
wglGetCurrentDC(void) {
359 gl_ctx
= glXGetCurrentContext();
360 ret
= get_context_from_GLXContext(gl_ctx
);
364 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret
->hdc
, gl_ctx
, ret
);
367 TRACE(" no Wine context found for GLX context %p\n", gl_ctx
);
372 /***********************************************************************
373 * wglGetLayerPaletteEntries (OPENGL32.@)
375 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
379 const COLORREF
*pcr
) {
380 FIXME("(): stub !\n");
385 /***********************************************************************
386 * wglGetProcAddress (OPENGL32.@)
388 static int compar(const void *elt_a
, const void *elt_b
) {
389 return strcmp(((const OpenGL_extension
*) elt_a
)->name
,
390 ((const OpenGL_extension
*) elt_b
)->name
);
393 static int wgl_compar(const void *elt_a
, const void *elt_b
) {
394 return strcmp(((const WGL_extension
*) elt_a
)->func_name
,
395 ((const WGL_extension
*) elt_b
)->func_name
);
398 PROC WINAPI
wglGetProcAddress(LPCSTR lpszProc
) {
400 OpenGL_extension ext
;
401 const OpenGL_extension
*ext_ret
;
403 TRACE("(%s)\n", lpszProc
);
405 /* First, look if it's not already defined in the 'standard' OpenGL functions */
406 if ((local_func
= GetProcAddress(opengl32_handle
, lpszProc
)) != NULL
) {
407 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func
);
411 if (p_glXGetProcAddressARB
== NULL
) {
412 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
416 /* After that, search in the thunks to find the real name of the extension */
418 ext_ret
= (const OpenGL_extension
*) bsearch(&ext
, extension_registry
,
419 extension_registry_size
, sizeof(OpenGL_extension
), compar
);
421 if (ext_ret
== NULL
) {
422 WGL_extension wgl_ext
, *wgl_ext_ret
;
424 /* Try to find the function in the WGL extensions ... */
425 wgl_ext
.func_name
= (char *) lpszProc
;
426 wgl_ext_ret
= (WGL_extension
*) bsearch(&wgl_ext
, wgl_extension_registry
,
427 wgl_extension_registry_size
, sizeof(WGL_extension
), wgl_compar
);
429 if (wgl_ext_ret
== NULL
) {
430 /* Some sanity checks :-) */
432 local_func
= p_glXGetProcAddressARB( (const GLubyte
*) lpszProc
);
434 if (local_func
!= NULL
) {
435 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc
);
439 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc
);
444 if (wgl_ext_ret
->func_init
!= NULL
) {
446 if ((err_msg
= wgl_ext_ret
->func_init(p_glXGetProcAddressARB
,
447 wgl_ext_ret
->context
)) == NULL
) {
448 ret
= wgl_ext_ret
->func_address
;
450 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc
), err_msg
);
454 ret
= wgl_ext_ret
->func_address
;
458 TRACE(" returning WGL function (%p)\n", ret
);
462 const char *glx_name
= ext_ret
->glx_name
? ext_ret
->glx_name
: ext_ret
->name
;
464 local_func
= p_glXGetProcAddressARB( (const GLubyte
*)glx_name
);
467 /* After that, look at the extensions defined in the Linux OpenGL library */
468 if (local_func
== NULL
) {
472 /* Remove the 3 last letters (EXT, ARB, ...).
474 I know that some extensions have more than 3 letters (MESA, NV,
475 INTEL, ...), but this is only a stop-gap measure to fix buggy
476 OpenGL drivers (moreover, it is only useful for old 1.0 apps
477 that query the glBindTextureEXT extension).
479 memcpy(buf
, glx_name
, strlen(glx_name
) - 3);
480 buf
[strlen(glx_name
) - 3] = '\0';
481 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
483 ret
= GetProcAddress(opengl32_handle
, buf
);
485 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
487 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, glx_name
);
492 TRACE(" returning function (%p)\n", ext_ret
->func
);
493 extension_funcs
[ext_ret
- extension_registry
] = local_func
;
495 return ext_ret
->func
;
500 static int describeContext(Wine_GLContext
* ctx
) {
503 TRACE(" Context %p have (vis:%p):\n", ctx
, ctx
->vis
);
504 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, ctx
->fb_conf
, GLX_FBCONFIG_ID
, &tmp
);
505 TRACE(" - FBCONFIG_ID 0x%x\n", tmp
);
506 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, ctx
->fb_conf
, GLX_VISUAL_ID
, &tmp
);
507 TRACE(" - VISUAL_ID 0x%x\n", tmp
);
512 static int describeDrawable(Wine_GLContext
* ctx
, Drawable drawable
) {
515 int attribList
[3] = { GLX_FBCONFIG_ID
, 0, None
};
518 if (3 > wine_glx
.version
|| NULL
== wine_glx
.p_glXQueryDrawable
) {
519 /** glXQueryDrawable not available so returns not supported */
523 TRACE(" Drawable %p have :\n", (void*) drawable
);
524 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_WIDTH
, (unsigned int*) &tmp
);
525 TRACE(" - WIDTH as %d\n", tmp
);
526 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_HEIGHT
, (unsigned int*) &tmp
);
527 TRACE(" - HEIGHT as %d\n", tmp
);
528 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_FBCONFIG_ID
, (unsigned int*) &tmp
);
529 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp
);
532 fbCfgs
= wine_glx
.p_glXChooseFBConfig(ctx
->display
, DefaultScreen(ctx
->display
), attribList
, &nElements
);
533 if (fbCfgs
== NULL
) {
537 wine_glx
.p_glXGetFBConfigAttrib(ctx
->display
, fbCfgs
[0], GLX_VISUAL_ID
, &tmp
);
538 TRACE(" - VISUAL_ID as 0x%x\n", tmp
);
545 /***********************************************************************
546 * wglMakeCurrent (OPENGL32.@)
548 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
551 DWORD type
= GetObjectType(hdc
);
553 TRACE("(%p,%p)\n", hdc
, hglrc
);
557 ret
= glXMakeCurrent(default_display
, None
, NULL
);
558 NtCurrentTeb()->glContext
= NULL
;
560 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
561 Drawable drawable
= get_drawable( hdc
);
562 if (ctx
->ctx
== NULL
) {
563 int draw_vis_id
, ctx_vis_id
;
564 VisualID visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
565 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid
);
566 draw_vis_id
= describeDrawable(ctx
, drawable
);
567 ctx_vis_id
= describeContext(ctx
);
569 if (-1 == draw_vis_id
|| (draw_vis_id
== visualid
&& draw_vis_id
!= ctx_vis_id
)) {
571 * Inherits from root window so reuse desktop visual
573 XVisualInfo
template;
576 template.visualid
= visualid
;
577 vis
= XGetVisualInfo(ctx
->display
, VisualIDMask
, &template, &num
);
579 TRACE(" Creating GLX Context\n");
580 ctx
->ctx
= glXCreateContext(ctx
->display
, vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
582 TRACE(" Creating GLX Context\n");
583 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
585 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
587 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx
->display
, (void*) drawable
, ctx
->ctx
);
588 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
589 NtCurrentTeb()->glContext
= ctx
;
590 if(ret
&& type
== OBJ_MEMDC
)
592 ctx
->do_escape
= TRUE
;
593 glDrawBuffer(GL_FRONT_LEFT
);
597 TRACE(" returning %s\n", (ret
? "True" : "False"));
601 /***********************************************************************
602 * wglMakeContextCurrentARB (OPENGL32.@)
604 BOOL WINAPI
wglMakeContextCurrentARB(HDC hDrawDC
, HDC hReadDC
, HGLRC hglrc
)
607 TRACE("(%p,%p,%p)\n", hDrawDC
, hReadDC
, hglrc
);
611 ret
= glXMakeCurrent(default_display
, None
, NULL
);
613 if (NULL
== wine_glx
.p_glXMakeContextCurrent
) {
616 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
617 Drawable d_draw
= get_drawable( hDrawDC
);
618 Drawable d_read
= get_drawable( hReadDC
);
620 if (ctx
->ctx
== NULL
) {
621 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, GetObjectType(hDrawDC
) == OBJ_MEMDC
? False
: True
);
622 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
624 ret
= wine_glx
.p_glXMakeContextCurrent(ctx
->display
, d_draw
, d_read
, ctx
->ctx
);
629 TRACE(" returning %s\n", (ret
? "True" : "False"));
633 /***********************************************************************
634 * wglGetCurrentReadDCARB (OPENGL32.@)
636 HDC WINAPI
wglGetCurrentReadDCARB(void)
644 gl_d
= glXGetCurrentReadDrawable();
645 ret
= get_hdc_from_Drawable(gl_d
);
648 TRACE(" returning %p (GL drawable %lu)\n", ret
, gl_d
);
654 /***********************************************************************
655 * wglRealizeLayerPalette (OPENGL32.@)
657 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
665 /***********************************************************************
666 * wglSetLayerPaletteEntries (OPENGL32.@)
668 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
672 const COLORREF
*pcr
) {
673 FIXME("(): stub !\n");
678 /***********************************************************************
679 * wglShareLists (OPENGL32.@)
681 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
683 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
684 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
686 TRACE("(%p, %p)\n", org
, dest
);
688 if (NULL
!= dest
&& dest
->ctx
!= NULL
) {
689 ERR("Could not share display lists, context already created !\n");
692 if (org
->ctx
== NULL
) {
694 describeContext(org
);
695 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
697 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
701 describeContext(dest
);
702 /* Create the destination context with display lists shared */
703 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
705 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
712 /***********************************************************************
713 * wglSwapLayerBuffers (OPENGL32.@)
715 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
717 TRACE_(opengl
)("(%p, %08x)\n", hdc
, fuPlanes
);
719 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
720 if (!SwapBuffers(hdc
)) return FALSE
;
721 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
725 WARN("Following layers unhandled : %08x\n", fuPlanes
);
731 static BOOL
internal_wglUseFontBitmaps(HDC hdc
,
735 DWORD (WINAPI
*GetGlyphOutline_ptr
)(HDC
,UINT
,UINT
,LPGLYPHMETRICS
,DWORD
,LPVOID
,const MAT2
*))
737 /* We are running using client-side rendering fonts... */
741 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
745 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
746 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
749 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
750 unsigned int needed_size
= GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, NULL
);
751 int height
, width_int
;
753 TRACE("Glyph : %3d / List : %ld\n", glyph
, listBase
);
754 if (needed_size
== GDI_ERROR
) {
755 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size
);
758 TRACE(" - needed size : %d\n", needed_size
);
761 if (needed_size
> size
) {
763 HeapFree(GetProcessHeap(), 0, bitmap
);
764 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
765 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
766 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
768 if (GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, NULL
) == GDI_ERROR
) goto error
;
769 if (TRACE_ON(opengl
)) {
770 unsigned int height
, width
, bitmask
;
771 unsigned char *bitmap_
= (unsigned char *) bitmap
;
773 TRACE(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
774 TRACE(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
775 TRACE(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
776 if (needed_size
!= 0) {
777 TRACE(" - bitmap :\n");
778 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
780 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
785 if (*bitmap_
& bitmask
)
790 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
796 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
797 * glyph for it to be drawn properly.
799 if (needed_size
!= 0) {
800 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
801 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
803 for (width
= 0; width
< width_int
; width
++) {
804 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
805 ((int *) bitmap
)[height
* width_int
+ width
];
811 glNewList(listBase
++, GL_COMPILE
);
812 if (needed_size
!= 0) {
813 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
814 0 - (int) gm
.gmptGlyphOrigin
.x
, (int) gm
.gmBlackBoxY
- (int) gm
.gmptGlyphOrigin
.y
,
815 gm
.gmCellIncX
, gm
.gmCellIncY
,
818 /* This is the case of 'empty' glyphs like the space character */
819 glBitmap(0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
826 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
829 HeapFree(GetProcessHeap(), 0, bitmap
);
830 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
835 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
838 HeapFree(GetProcessHeap(), 0, bitmap
);
839 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
843 /***********************************************************************
844 * wglUseFontBitmapsA (OPENGL32.@)
846 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
851 Font fid
= get_font( hdc
);
853 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
856 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineA
);
860 /* I assume that the glyphs are at the same position for X and for Windows */
861 glXUseXFont(fid
, first
, count
, listBase
);
866 /***********************************************************************
867 * wglUseFontBitmapsW (OPENGL32.@)
869 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
,
874 Font fid
= get_font( hdc
);
876 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
879 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineW
);
882 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
885 /* I assume that the glyphs are at the same position for X and for Windows */
886 glXUseXFont(fid
, first
, count
, listBase
);
893 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
895 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
896 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
900 static void tess_callback_vertex(GLvoid
*vertex
)
902 GLdouble
*dbl
= vertex
;
903 TRACE("%f, %f, %f\n", dbl
[0], dbl
[1], dbl
[2]);
907 static void tess_callback_begin(GLenum which
)
909 TRACE("%d\n", which
);
913 static void tess_callback_end(void)
919 /***********************************************************************
920 * wglUseFontOutlines_common
922 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
929 LPGLYPHMETRICSFLOAT lpgmf
,
933 const MAT2 identity
= {{0,1},{0,0},{0,0},{0,1}};
936 HFONT old_font
, unscaled_font
;
940 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
941 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
948 gluTessCallback(tess
, GLU_TESS_VERTEX
, (_GLUfuncptr
)tess_callback_vertex
);
949 gluTessCallback(tess
, GLU_TESS_BEGIN
, (_GLUfuncptr
)tess_callback_begin
);
950 gluTessCallback(tess
, GLU_TESS_END
, tess_callback_end
);
954 if(!tess
) return FALSE
;
956 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
957 rc
.left
= rc
.right
= rc
.bottom
= 0;
959 DPtoLP(hdc
, (POINT
*)&rc
, 2);
960 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
961 lf
.lfOrientation
= lf
.lfEscapement
= 0;
962 unscaled_font
= CreateFontIndirectW(&lf
);
963 old_font
= SelectObject(hdc
, unscaled_font
);
965 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
970 TTPOLYGONHEADER
*pph
;
975 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
977 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
979 if(needed
== GDI_ERROR
)
982 buf
= HeapAlloc(GetProcessHeap(), 0, needed
);
983 vertices
= HeapAlloc(GetProcessHeap(), 0, needed
/ sizeof(POINTFX
) * 3 * sizeof(GLdouble
));
986 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
988 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
990 TRACE("glyph %d\n", glyph
);
994 lpgmf
->gmfBlackBoxX
= gm
.gmBlackBoxX
/ em_size
;
995 lpgmf
->gmfBlackBoxY
= gm
.gmBlackBoxY
/ em_size
;
996 lpgmf
->gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ em_size
;
997 lpgmf
->gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ em_size
;
998 lpgmf
->gmfCellIncX
= gm
.gmCellIncX
/ em_size
;
999 lpgmf
->gmfCellIncY
= gm
.gmCellIncY
/ em_size
;
1000 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
1001 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
1006 glNewList(listBase
++, GL_COMPILE
);
1007 gluTessBeginPolygon(tess
, NULL
);
1009 pph
= (TTPOLYGONHEADER
*)buf
;
1010 while((BYTE
*)pph
< buf
+ needed
)
1012 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
1014 gluTessBeginContour(tess
);
1016 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
1017 gluTessVertex(tess
, vertices
, vertices
);
1020 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
1021 while((char*)ppc
< (char*)pph
+ pph
->cb
)
1025 switch(ppc
->wType
) {
1027 for(i
= 0; i
< ppc
->cpfx
; i
++)
1029 TRACE("\t\tline to %d, %d\n", ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
1030 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
1031 gluTessVertex(tess
, vertices
, vertices
);
1036 case TT_PRIM_QSPLINE
:
1037 for(i
= 0; i
< ppc
->cpfx
/2; i
++)
1039 /* FIXME just connecting the control points for now */
1040 TRACE("\t\tcurve %d,%d %d,%d\n",
1041 ppc
->apfx
[i
* 2].x
.value
, ppc
->apfx
[i
* 3].y
.value
,
1042 ppc
->apfx
[i
* 2 + 1].x
.value
, ppc
->apfx
[i
* 3 + 1].y
.value
);
1043 fixed_to_double(ppc
->apfx
[i
* 2], em_size
, vertices
);
1044 gluTessVertex(tess
, vertices
, vertices
);
1046 fixed_to_double(ppc
->apfx
[i
* 2 + 1], em_size
, vertices
);
1047 gluTessVertex(tess
, vertices
, vertices
);
1052 ERR("\t\tcurve type = %d\n", ppc
->wType
);
1053 gluTessEndContour(tess
);
1057 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
1058 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
1060 gluTessEndContour(tess
);
1061 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
1065 gluTessEndPolygon(tess
);
1068 HeapFree(GetProcessHeap(), 0, buf
);
1069 HeapFree(GetProcessHeap(), 0, vertices
);
1073 DeleteObject(SelectObject(hdc
, old_font
));
1074 gluDeleteTess(tess
);
1079 #else /* HAVE_GL_GLU_H */
1081 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
1088 LPGLYPHMETRICSFLOAT lpgmf
,
1091 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1095 #endif /* HAVE_GL_GLU_H */
1097 /***********************************************************************
1098 * wglUseFontOutlinesA (OPENGL32.@)
1100 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
1107 LPGLYPHMETRICSFLOAT lpgmf
)
1109 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
1112 /***********************************************************************
1113 * wglUseFontOutlinesW (OPENGL32.@)
1115 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
1122 LPGLYPHMETRICSFLOAT lpgmf
)
1124 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);
1127 const GLubyte
* internal_glGetString(GLenum name
) {
1128 const char* GL_Extensions
= NULL
;
1130 if (GL_EXTENSIONS
!= name
) {
1131 return glGetString(name
);
1134 if (NULL
== internal_gl_extensions
) {
1135 GL_Extensions
= (const char *) glGetString(GL_EXTENSIONS
);
1137 TRACE("GL_EXTENSIONS reported:\n");
1138 if (NULL
== GL_Extensions
) {
1139 ERR("GL_EXTENSIONS returns NULL\n");
1142 size_t len
= strlen(GL_Extensions
);
1143 internal_gl_extensions
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
+ 2);
1145 while (*GL_Extensions
!= 0x00) {
1146 const char* Start
= GL_Extensions
;
1149 memset(ThisExtn
, 0x00, sizeof(ThisExtn
));
1150 while (*GL_Extensions
!= ' ' && *GL_Extensions
!= 0x00) {
1153 memcpy(ThisExtn
, Start
, (GL_Extensions
- Start
));
1154 TRACE("- %s:", ThisExtn
);
1156 /* test if supported API is disabled by config */
1157 if (NULL
== strstr(internal_gl_disabled_extensions
, ThisExtn
)) {
1158 strcat(internal_gl_extensions
, " ");
1159 strcat(internal_gl_extensions
, ThisExtn
);
1162 TRACE(" deactived (by config)\n");
1165 if (*GL_Extensions
== ' ') GL_Extensions
++;
1169 return (const GLubyte
*) internal_gl_extensions
;
1172 void internal_glGetIntegerv(GLenum pname
, GLint
* params
) {
1173 glGetIntegerv(pname
, params
);
1174 if (pname
== GL_DEPTH_BITS
) {
1175 GLXContext gl_ctx
= glXGetCurrentContext();
1176 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1177 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1179 * if we cannot find a Wine Context
1180 * we only have the default wine desktop context,
1181 * so if we have only a 24 depth say we have 32
1183 if (NULL
== ret
&& 24 == *params
) {
1186 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params
);
1188 if (pname
== GL_ALPHA_BITS
) {
1190 GLXContext gl_ctx
= glXGetCurrentContext();
1191 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1192 glXGetFBConfigAttrib(ret
->display
, ret
->fb_conf
, GLX_ALPHA_SIZE
, &tmp
);
1193 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp
);
1199 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1200 include all dependencies
1202 #ifndef SONAME_LIBGL
1203 #define SONAME_LIBGL "libGL.so"
1206 static void wgl_initialize_glx(Display
*display
, int screen
, glXGetProcAddressARB_t proc
)
1208 const char *server_glx_version
= glXQueryServerString(display
, screen
, GLX_VERSION
);
1209 const char *server_glx_extensions
= glXQueryServerString(display
, screen
, GLX_EXTENSIONS
);
1211 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1212 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1213 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1216 memset(&wine_glx
, 0, sizeof(wine_glx
));
1218 if (!strcmp("1.2", server_glx_version
)) {
1219 wine_glx
.version
= 2;
1221 wine_glx
.version
= 3;
1224 if (2 < wine_glx
.version
) {
1225 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfig");
1226 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttrib");
1227 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfig");
1229 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1230 wine_glx
.p_glXQueryDrawable
= proc( (const GLubyte
*) "glXQueryDrawable");
1232 if (NULL
!= strstr(server_glx_extensions
, "GLX_SGIX_fbconfig")) {
1233 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfigSGIX");
1234 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttribSGIX");
1235 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfigSGIX");
1237 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version
);
1240 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1241 wine_glx
.p_glXGetFBConfigs
= proc( (const GLubyte
*) "glXGetFBConfigs");
1242 wine_glx
.p_glXMakeContextCurrent
= proc( (const GLubyte
*) "glXMakeContextCurrent");
1245 /* This is for brain-dead applications that use OpenGL functions before even
1246 creating a rendering context.... */
1247 static BOOL
process_attach(void)
1249 XWindowAttributes win_attr
;
1252 XVisualInfo
template;
1254 XVisualInfo
*vis
= NULL
;
1255 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1256 HMODULE mod
= GetModuleHandleA( "winex11.drv" );
1257 void *opengl_handle
;
1258 DWORD size
= sizeof(internal_gl_disabled_extensions
);
1263 ERR("X11DRV not loaded. Cannot create default context.\n");
1267 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
1268 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
1271 default_display
= get_display( hdc
);
1272 ReleaseDC( 0, hdc
);
1273 if (!default_display
)
1275 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1281 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1282 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1283 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1284 with mismatched visuals. Note that the Root Window visual may not be double
1285 buffered, so apps actually attempting to render this way may flicker */
1286 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
1288 rootVisual
= win_attr
.visual
;
1292 /* Get the default visual, since we can't seem to get the attributes from the
1293 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1294 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
1297 template.visualid
= XVisualIDFromVisual(rootVisual
);
1298 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
1299 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
1300 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
1304 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
1305 if (opengl_handle
!= NULL
) {
1306 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
1307 wine_dlclose(opengl_handle
, NULL
, 0);
1308 if (p_glXGetProcAddressARB
== NULL
)
1309 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1312 internal_gl_disabled_extensions
[0] = 0;
1313 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\OpenGL", &hkey
)) {
1314 if (!RegQueryValueExA( hkey
, "DisabledExtensions", 0, NULL
, (LPBYTE
)internal_gl_disabled_extensions
, &size
)) {
1315 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions
);
1320 if (default_cx
== NULL
) {
1321 ERR("Could not create default context.\n");
1325 /* After context initialize also the list of supported WGL extensions. */
1326 wgl_initialize_glx(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
);
1327 wgl_ext_initialize_extensions(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
, internal_gl_disabled_extensions
);
1333 /**********************************************************************/
1335 static void process_detach(void)
1337 glXDestroyContext(default_display
, default_cx
);
1339 /* Do not leak memory... */
1340 wgl_ext_finalize_extensions();
1341 HeapFree(GetProcessHeap(), 0, internal_gl_extensions
);
1344 /***********************************************************************
1345 * OpenGL initialisation routine
1347 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
1351 case DLL_PROCESS_ATTACH
:
1352 opengl32_handle
= hinst
;
1353 DisableThreadLibraryCalls(hinst
);
1354 return process_attach();
1355 case DLL_PROCESS_DETACH
: