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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 if (3 > wine_glx
.version
|| NULL
== wine_glx
.p_glXQueryDrawable
) {
514 /** glXQueryDrawable not available so returns not supported */
517 TRACE(" Drawable %p have :\n", (void*) drawable
);
518 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_FBCONFIG_ID
, (unsigned int*) &tmp
);
519 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp
);
520 wine_glx
.p_glXQueryDrawable(ctx
->display
, drawable
, GLX_VISUAL_ID
, (unsigned int*) &tmp
);
521 TRACE(" - VISUAL_ID as 0x%x\n", tmp
);
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
);
530 /***********************************************************************
531 * wglMakeCurrent (OPENGL32.@)
533 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
536 DWORD type
= GetObjectType(hdc
);
538 TRACE("(%p,%p)\n", hdc
, hglrc
);
542 ret
= glXMakeCurrent(default_display
, None
, NULL
);
543 NtCurrentTeb()->glContext
= NULL
;
545 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
546 Drawable drawable
= get_drawable( hdc
);
547 if (ctx
->ctx
== NULL
) {
548 int draw_vis_id
, ctx_vis_id
;
549 VisualID visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
550 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid
);
551 draw_vis_id
= describeDrawable(ctx
, drawable
);
552 ctx_vis_id
= describeContext(ctx
);
554 if (-1 == draw_vis_id
|| (draw_vis_id
== visualid
&& draw_vis_id
!= ctx_vis_id
)) {
556 * Inherits from root window so reuse desktop visual
558 XVisualInfo
template;
561 template.visualid
= visualid
;
562 vis
= XGetVisualInfo(ctx
->display
, VisualIDMask
, &template, &num
);
564 TRACE(" Creating GLX Context\n");
565 ctx
->ctx
= glXCreateContext(ctx
->display
, vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
567 TRACE(" Creating GLX Context\n");
568 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, type
== OBJ_MEMDC
? False
: True
);
570 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
572 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx
->display
, (void*) drawable
, ctx
->ctx
);
573 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
574 NtCurrentTeb()->glContext
= ctx
;
575 if(ret
&& type
== OBJ_MEMDC
)
577 ctx
->do_escape
= TRUE
;
578 glDrawBuffer(GL_FRONT_LEFT
);
582 TRACE(" returning %s\n", (ret
? "True" : "False"));
586 /***********************************************************************
587 * wglMakeContextCurrentARB (OPENGL32.@)
589 BOOL WINAPI
wglMakeContextCurrentARB(HDC hDrawDC
, HDC hReadDC
, HGLRC hglrc
)
592 TRACE("(%p,%p,%p)\n", hDrawDC
, hReadDC
, hglrc
);
596 ret
= glXMakeCurrent(default_display
, None
, NULL
);
598 if (NULL
== wine_glx
.p_glXMakeContextCurrent
) {
601 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
602 Drawable d_draw
= get_drawable( hDrawDC
);
603 Drawable d_read
= get_drawable( hReadDC
);
605 if (ctx
->ctx
== NULL
) {
606 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, GetObjectType(hDrawDC
) == OBJ_MEMDC
? False
: True
);
607 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
609 ret
= wine_glx
.p_glXMakeContextCurrent(ctx
->display
, d_draw
, d_read
, ctx
->ctx
);
614 TRACE(" returning %s\n", (ret
? "True" : "False"));
618 /***********************************************************************
619 * wglGetCurrentReadDCARB (OPENGL32.@)
621 HDC WINAPI
wglGetCurrentReadDCARB(void)
629 gl_d
= glXGetCurrentReadDrawable();
630 ret
= get_hdc_from_Drawable(gl_d
);
633 TRACE(" returning %p (GL drawable %lu)\n", ret
, gl_d
);
639 /***********************************************************************
640 * wglRealizeLayerPalette (OPENGL32.@)
642 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
650 /***********************************************************************
651 * wglSetLayerPaletteEntries (OPENGL32.@)
653 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
657 const COLORREF
*pcr
) {
658 FIXME("(): stub !\n");
663 /***********************************************************************
664 * wglShareLists (OPENGL32.@)
666 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
668 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
669 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
671 TRACE("(%p, %p)\n", org
, dest
);
673 if (NULL
!= dest
&& dest
->ctx
!= NULL
) {
674 ERR("Could not share display lists, context already created !\n");
677 if (org
->ctx
== NULL
) {
679 describeContext(org
);
680 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
682 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
686 describeContext(dest
);
687 /* Create the destination context with display lists shared */
688 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, GetObjectType(org
->hdc
) == OBJ_MEMDC
? False
: True
);
690 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
697 /***********************************************************************
698 * wglSwapLayerBuffers (OPENGL32.@)
700 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
702 TRACE_(opengl
)("(%p, %08x)\n", hdc
, fuPlanes
);
704 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
705 if (!SwapBuffers(hdc
)) return FALSE
;
706 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
710 WARN("Following layers unhandled : %08x\n", fuPlanes
);
716 static BOOL
internal_wglUseFontBitmaps(HDC hdc
,
720 DWORD (WINAPI
*GetGlyphOutline_ptr
)(HDC
,UINT
,UINT
,LPGLYPHMETRICS
,DWORD
,LPVOID
,const MAT2
*))
722 /* We are running using client-side rendering fonts... */
726 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
730 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
731 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
734 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
735 unsigned int needed_size
= GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, NULL
);
736 int height
, width_int
;
738 TRACE("Glyph : %3d / List : %ld\n", glyph
, listBase
);
739 if (needed_size
== GDI_ERROR
) {
740 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size
);
743 TRACE(" - needed size : %d\n", needed_size
);
746 if (needed_size
> size
) {
748 HeapFree(GetProcessHeap(), 0, bitmap
);
749 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
750 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
751 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
753 if (GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, NULL
) == GDI_ERROR
) goto error
;
754 if (TRACE_ON(opengl
)) {
755 unsigned int height
, width
, bitmask
;
756 unsigned char *bitmap_
= (unsigned char *) bitmap
;
758 TRACE(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
759 TRACE(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
760 TRACE(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
761 if (needed_size
!= 0) {
762 TRACE(" - bitmap :\n");
763 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
765 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
770 if (*bitmap_
& bitmask
)
775 bitmap_
+= (4 - ((UINT_PTR
)bitmap_
& 0x03));
781 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
782 * glyph for it to be drawn properly.
784 if (needed_size
!= 0) {
785 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
786 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
788 for (width
= 0; width
< width_int
; width
++) {
789 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
790 ((int *) bitmap
)[height
* width_int
+ width
];
796 glNewList(listBase
++, GL_COMPILE
);
797 if (needed_size
!= 0) {
798 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
799 0 - (int) gm
.gmptGlyphOrigin
.x
, (int) gm
.gmBlackBoxY
- (int) gm
.gmptGlyphOrigin
.y
,
800 gm
.gmCellIncX
, gm
.gmCellIncY
,
803 /* This is the case of 'empty' glyphs like the space character */
804 glBitmap(0, 0, 0, 0, gm
.gmCellIncX
, gm
.gmCellIncY
, NULL
);
811 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
814 HeapFree(GetProcessHeap(), 0, bitmap
);
815 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
820 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
823 HeapFree(GetProcessHeap(), 0, bitmap
);
824 HeapFree(GetProcessHeap(), 0, gl_bitmap
);
828 /***********************************************************************
829 * wglUseFontBitmapsA (OPENGL32.@)
831 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
836 Font fid
= get_font( hdc
);
838 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
841 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineA
);
845 /* I assume that the glyphs are at the same position for X and for Windows */
846 glXUseXFont(fid
, first
, count
, listBase
);
851 /***********************************************************************
852 * wglUseFontBitmapsW (OPENGL32.@)
854 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
,
859 Font fid
= get_font( hdc
);
861 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
864 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineW
);
867 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
870 /* I assume that the glyphs are at the same position for X and for Windows */
871 glXUseXFont(fid
, first
, count
, listBase
);
878 static void fixed_to_double(POINTFX fixed
, UINT em_size
, GLdouble vertex
[3])
880 vertex
[0] = (fixed
.x
.value
+ (GLdouble
)fixed
.x
.fract
/ (1 << 16)) / em_size
;
881 vertex
[1] = (fixed
.y
.value
+ (GLdouble
)fixed
.y
.fract
/ (1 << 16)) / em_size
;
885 static void tess_callback_vertex(GLvoid
*vertex
)
887 GLdouble
*dbl
= vertex
;
888 TRACE("%f, %f, %f\n", dbl
[0], dbl
[1], dbl
[2]);
892 static void tess_callback_begin(GLenum which
)
894 TRACE("%d\n", which
);
898 static void tess_callback_end(void)
904 /***********************************************************************
905 * wglUseFontOutlines_common
907 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
914 LPGLYPHMETRICSFLOAT lpgmf
,
918 const MAT2 identity
= {{0,1},{0,0},{0,0},{0,1}};
921 HFONT old_font
, unscaled_font
;
925 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc
, first
, count
,
926 listBase
, deviation
, extrusion
, format
, lpgmf
, unicode
? "W" : "A");
933 gluTessCallback(tess
, GLU_TESS_VERTEX
, (_GLUfuncptr
)tess_callback_vertex
);
934 gluTessCallback(tess
, GLU_TESS_BEGIN
, (_GLUfuncptr
)tess_callback_begin
);
935 gluTessCallback(tess
, GLU_TESS_END
, tess_callback_end
);
939 if(!tess
) return FALSE
;
941 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
942 rc
.left
= rc
.right
= rc
.bottom
= 0;
944 DPtoLP(hdc
, (POINT
*)&rc
, 2);
945 lf
.lfHeight
= -abs(rc
.top
- rc
.bottom
);
946 lf
.lfOrientation
= lf
.lfEscapement
= 0;
947 unscaled_font
= CreateFontIndirectW(&lf
);
948 old_font
= SelectObject(hdc
, unscaled_font
);
950 for (glyph
= first
; glyph
< first
+ count
; glyph
++)
955 TTPOLYGONHEADER
*pph
;
960 needed
= GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
962 needed
= GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
964 if(needed
== GDI_ERROR
)
967 buf
= HeapAlloc(GetProcessHeap(), 0, needed
);
968 vertices
= HeapAlloc(GetProcessHeap(), 0, needed
/ sizeof(POINTFX
) * 3 * sizeof(GLdouble
));
971 GetGlyphOutlineW(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
973 GetGlyphOutlineA(hdc
, glyph
, GGO_NATIVE
, &gm
, needed
, buf
, &identity
);
975 TRACE("glyph %d\n", glyph
);
979 lpgmf
->gmfBlackBoxX
= gm
.gmBlackBoxX
/ em_size
;
980 lpgmf
->gmfBlackBoxY
= gm
.gmBlackBoxY
/ em_size
;
981 lpgmf
->gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ em_size
;
982 lpgmf
->gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ em_size
;
983 lpgmf
->gmfCellIncX
= gm
.gmCellIncX
/ em_size
;
984 lpgmf
->gmfCellIncY
= gm
.gmCellIncY
/ em_size
;
985 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf
->gmfBlackBoxX
, lpgmf
->gmfBlackBoxY
,
986 lpgmf
->gmfptGlyphOrigin
.x
, lpgmf
->gmfptGlyphOrigin
.y
, lpgmf
->gmfCellIncX
, lpgmf
->gmfCellIncY
);
991 glNewList(listBase
++, GL_COMPILE
);
992 gluTessBeginPolygon(tess
, NULL
);
994 pph
= (TTPOLYGONHEADER
*)buf
;
995 while((BYTE
*)pph
< buf
+ needed
)
997 TRACE("\tstart %d, %d\n", pph
->pfxStart
.x
.value
, pph
->pfxStart
.y
.value
);
999 gluTessBeginContour(tess
);
1001 fixed_to_double(pph
->pfxStart
, em_size
, vertices
);
1002 gluTessVertex(tess
, vertices
, vertices
);
1005 ppc
= (TTPOLYCURVE
*)((char*)pph
+ sizeof(*pph
));
1006 while((char*)ppc
< (char*)pph
+ pph
->cb
)
1010 switch(ppc
->wType
) {
1012 for(i
= 0; i
< ppc
->cpfx
; i
++)
1014 TRACE("\t\tline to %d, %d\n", ppc
->apfx
[i
].x
.value
, ppc
->apfx
[i
].y
.value
);
1015 fixed_to_double(ppc
->apfx
[i
], em_size
, vertices
);
1016 gluTessVertex(tess
, vertices
, vertices
);
1021 case TT_PRIM_QSPLINE
:
1022 for(i
= 0; i
< ppc
->cpfx
/2; i
++)
1024 /* FIXME just connecting the control points for now */
1025 TRACE("\t\tcurve %d,%d %d,%d\n",
1026 ppc
->apfx
[i
* 2].x
.value
, ppc
->apfx
[i
* 3].y
.value
,
1027 ppc
->apfx
[i
* 2 + 1].x
.value
, ppc
->apfx
[i
* 3 + 1].y
.value
);
1028 fixed_to_double(ppc
->apfx
[i
* 2], em_size
, vertices
);
1029 gluTessVertex(tess
, vertices
, vertices
);
1031 fixed_to_double(ppc
->apfx
[i
* 2 + 1], em_size
, vertices
);
1032 gluTessVertex(tess
, vertices
, vertices
);
1037 ERR("\t\tcurve type = %d\n", ppc
->wType
);
1038 gluTessEndContour(tess
);
1042 ppc
= (TTPOLYCURVE
*)((char*)ppc
+ sizeof(*ppc
) +
1043 (ppc
->cpfx
- 1) * sizeof(POINTFX
));
1045 gluTessEndContour(tess
);
1046 pph
= (TTPOLYGONHEADER
*)((char*)pph
+ pph
->cb
);
1050 gluTessEndPolygon(tess
);
1053 HeapFree(GetProcessHeap(), 0, buf
);
1054 HeapFree(GetProcessHeap(), 0, vertices
);
1058 DeleteObject(SelectObject(hdc
, old_font
));
1059 gluDeleteTess(tess
);
1064 #else /* HAVE_GL_GLU_H */
1066 BOOL WINAPI
wglUseFontOutlines_common(HDC hdc
,
1073 LPGLYPHMETRICSFLOAT lpgmf
,
1076 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1080 #endif /* HAVE_GL_GLU_H */
1082 /***********************************************************************
1083 * wglUseFontOutlinesA (OPENGL32.@)
1085 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
1092 LPGLYPHMETRICSFLOAT lpgmf
)
1094 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, FALSE
);
1097 /***********************************************************************
1098 * wglUseFontOutlinesW (OPENGL32.@)
1100 BOOL WINAPI
wglUseFontOutlinesW(HDC hdc
,
1107 LPGLYPHMETRICSFLOAT lpgmf
)
1109 return wglUseFontOutlines_common(hdc
, first
, count
, listBase
, deviation
, extrusion
, format
, lpgmf
, TRUE
);
1112 const GLubyte
* internal_glGetString(GLenum name
) {
1113 const char* GL_Extensions
= NULL
;
1115 if (GL_EXTENSIONS
!= name
) {
1116 return glGetString(name
);
1119 if (NULL
== internal_gl_extensions
) {
1120 GL_Extensions
= (const char *) glGetString(GL_EXTENSIONS
);
1122 TRACE("GL_EXTENSIONS reported:\n");
1123 if (NULL
== GL_Extensions
) {
1124 ERR("GL_EXTENSIONS returns NULL\n");
1127 size_t len
= strlen(GL_Extensions
);
1128 internal_gl_extensions
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
+ 2);
1130 while (*GL_Extensions
!= 0x00) {
1131 const char* Start
= GL_Extensions
;
1134 memset(ThisExtn
, 0x00, sizeof(ThisExtn
));
1135 while (*GL_Extensions
!= ' ' && *GL_Extensions
!= 0x00) {
1138 memcpy(ThisExtn
, Start
, (GL_Extensions
- Start
));
1139 TRACE("- %s:", ThisExtn
);
1141 /* test if supported API is disabled by config */
1142 if (NULL
== strstr(internal_gl_disabled_extensions
, ThisExtn
)) {
1143 strcat(internal_gl_extensions
, " ");
1144 strcat(internal_gl_extensions
, ThisExtn
);
1147 TRACE(" deactived (by config)\n");
1150 if (*GL_Extensions
== ' ') GL_Extensions
++;
1154 return (const GLubyte
*) internal_gl_extensions
;
1157 void internal_glGetIntegerv(GLenum pname
, GLint
* params
) {
1158 glGetIntegerv(pname
, params
);
1159 if (pname
== GL_DEPTH_BITS
) {
1160 GLXContext gl_ctx
= glXGetCurrentContext();
1161 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1162 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1164 * if we cannot find a Wine Context
1165 * we only have the default wine desktop context,
1166 * so if we have only a 24 depth say we have 32
1168 if (NULL
== ret
&& 24 == *params
) {
1171 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params
);
1173 if (pname
== GL_ALPHA_BITS
) {
1175 GLXContext gl_ctx
= glXGetCurrentContext();
1176 Wine_GLContext
* ret
= get_context_from_GLXContext(gl_ctx
);
1177 glXGetFBConfigAttrib(ret
->display
, ret
->fb_conf
, GLX_ALPHA_SIZE
, &tmp
);
1178 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp
);
1184 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1185 include all dependencies
1187 #ifndef SONAME_LIBGL
1188 #define SONAME_LIBGL "libGL.so"
1191 static void wgl_initialize_glx(Display
*display
, int screen
, glXGetProcAddressARB_t proc
)
1193 const char *server_glx_version
= glXQueryServerString(display
, screen
, GLX_VERSION
);
1194 const char *server_glx_extensions
= glXQueryServerString(display
, screen
, GLX_EXTENSIONS
);
1196 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1197 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1198 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1201 memset(&wine_glx
, 0, sizeof(wine_glx
));
1203 if (!strcmp("1.2", server_glx_version
)) {
1204 wine_glx
.version
= 2;
1206 wine_glx
.version
= 3;
1209 if (2 < wine_glx
.version
) {
1210 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfig");
1211 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttrib");
1212 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfig");
1214 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1215 wine_glx
.p_glXQueryDrawable
= proc( (const GLubyte
*) "glXQueryDrawable");
1217 if (NULL
!= strstr(server_glx_extensions
, "GLX_SGIX_fbconfig")) {
1218 wine_glx
.p_glXChooseFBConfig
= proc( (const GLubyte
*) "glXChooseFBConfigSGIX");
1219 wine_glx
.p_glXGetFBConfigAttrib
= proc( (const GLubyte
*) "glXGetFBConfigAttribSGIX");
1220 wine_glx
.p_glXGetVisualFromFBConfig
= proc( (const GLubyte
*) "glXGetVisualFromFBConfigSGIX");
1222 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version
);
1225 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1226 wine_glx
.p_glXGetFBConfigs
= proc( (const GLubyte
*) "glXGetFBConfigs");
1227 wine_glx
.p_glXMakeContextCurrent
= proc( (const GLubyte
*) "glXMakeContextCurrent");
1230 /* This is for brain-dead applications that use OpenGL functions before even
1231 creating a rendering context.... */
1232 static BOOL
process_attach(void)
1234 XWindowAttributes win_attr
;
1237 XVisualInfo
template;
1239 XVisualInfo
*vis
= NULL
;
1240 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1241 HMODULE mod
= GetModuleHandleA( "winex11.drv" );
1242 void *opengl_handle
;
1243 DWORD size
= sizeof(internal_gl_disabled_extensions
);
1248 ERR("X11DRV not loaded. Cannot create default context.\n");
1252 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
1253 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
1256 default_display
= get_display( hdc
);
1257 ReleaseDC( 0, hdc
);
1258 if (!default_display
)
1260 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1266 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1267 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1268 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1269 with mismatched visuals. Note that the Root Window visual may not be double
1270 buffered, so apps actually attempting to render this way may flicker */
1271 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
1273 rootVisual
= win_attr
.visual
;
1277 /* Get the default visual, since we can't seem to get the attributes from the
1278 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1279 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
1282 template.visualid
= XVisualIDFromVisual(rootVisual
);
1283 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
1284 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
1285 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
1289 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
1290 if (opengl_handle
!= NULL
) {
1291 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
1292 wine_dlclose(opengl_handle
, NULL
, 0);
1293 if (p_glXGetProcAddressARB
== NULL
)
1294 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1297 internal_gl_disabled_extensions
[0] = 0;
1298 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\OpenGL", &hkey
)) {
1299 if (!RegQueryValueExA( hkey
, "DisabledExtensions", 0, NULL
, (LPBYTE
)internal_gl_disabled_extensions
, &size
)) {
1300 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions
);
1305 if (default_cx
== NULL
) {
1306 ERR("Could not create default context.\n");
1310 /* After context initialize also the list of supported WGL extensions. */
1311 wgl_initialize_glx(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
);
1312 wgl_ext_initialize_extensions(default_display
, DefaultScreen(default_display
), p_glXGetProcAddressARB
, internal_gl_disabled_extensions
);
1318 /**********************************************************************/
1320 static void process_detach(void)
1322 glXDestroyContext(default_display
, default_cx
);
1324 /* Do not leak memory... */
1325 wgl_ext_finalize_extensions();
1326 if (NULL
!= internal_gl_extensions
) {
1327 HeapFree(GetProcessHeap(), 0, internal_gl_extensions
);
1331 /***********************************************************************
1332 * OpenGL initialisation routine
1334 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
1338 case DLL_PROCESS_ATTACH
:
1339 opengl32_handle
= hinst
;
1340 DisableThreadLibraryCalls(hinst
);
1341 return process_attach();
1342 case DLL_PROCESS_DETACH
: