1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "wine/port.h"
33 #include "opengl_ext.h"
34 #include "wine/library.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(opengl
);
39 /* x11drv GDI escapes */
40 #define X11DRV_ESCAPE 6789
41 enum x11drv_escape_codes
43 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
44 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
45 X11DRV_GET_FONT
, /* get current X font for a DC */
48 void (*wine_tsx11_lock_ptr
)(void) = NULL
;
49 void (*wine_tsx11_unlock_ptr
)(void) = NULL
;
51 static GLXContext default_cx
= NULL
;
52 static Display
*default_display
; /* display to use for default context */
54 static void *(*p_glXGetProcAddressARB
)(const GLubyte
*);
56 typedef struct wine_glcontext
{
61 struct wine_glcontext
*next
;
62 struct wine_glcontext
*prev
;
64 static Wine_GLContext
*context_list
;
66 static inline Wine_GLContext
*get_context_from_GLXContext(GLXContext ctx
)
69 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
73 static inline void free_context(Wine_GLContext
*context
)
75 if (context
->next
!= NULL
) context
->next
->prev
= context
->prev
;
76 if (context
->prev
!= NULL
) context
->prev
->next
= context
->next
;
77 else context_list
= context
->next
;
79 HeapFree(GetProcessHeap(), 0, context
);
82 static inline Wine_GLContext
*alloc_context(void)
86 if ((ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(Wine_GLContext
))))
88 ret
->next
= context_list
;
89 if (context_list
) context_list
->prev
= ret
;
95 inline static BOOL
is_valid_context( Wine_GLContext
*ctx
)
98 for (ptr
= context_list
; ptr
; ptr
= ptr
->next
) if (ptr
== ctx
) break;
102 /* retrieve the X display to use on a given DC */
103 inline static Display
*get_display( HDC hdc
)
106 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
108 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
109 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
114 /* retrieve the X drawable to use on a given DC */
115 inline static Drawable
get_drawable( HDC hdc
)
118 enum x11drv_escape_codes escape
= X11DRV_GET_DRAWABLE
;
120 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
121 sizeof(drawable
), (LPSTR
)&drawable
)) drawable
= 0;
126 /* retrieve the X drawable to use on a given DC */
127 inline static Font
get_font( HDC hdc
)
130 enum x11drv_escape_codes escape
= X11DRV_GET_FONT
;
132 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
133 sizeof(font
), (LPSTR
)&font
)) font
= 0;
138 /***********************************************************************
139 * wglCreateContext (OPENGL32.@)
141 HGLRC WINAPI
wglCreateContext(HDC hdc
)
146 XVisualInfo
template;
147 Display
*display
= get_display( hdc
);
149 TRACE("(%p)\n", hdc
);
151 /* First, get the visual in use by the X11DRV */
152 if (!display
) return 0;
153 template.visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
154 vis
= XGetVisualInfo(display
, VisualIDMask
, &template, &num
);
157 ERR("NULL visual !!!\n");
158 /* Need to set errors here */
162 /* The context will be allocated in the wglMakeCurrent call */
164 ret
= alloc_context();
167 ret
->display
= display
;
170 TRACE(" creating context %p (GL context creation delayed)\n", ret
);
174 /***********************************************************************
175 * wglCreateLayerContext (OPENGL32.@)
177 HGLRC WINAPI
wglCreateLayerContext(HDC hdc
,
179 TRACE("(%p,%d)\n", hdc
, iLayerPlane
);
181 if (iLayerPlane
== 0) {
182 return wglCreateContext(hdc
);
184 FIXME(" no handler for layer %d\n", iLayerPlane
);
189 /***********************************************************************
190 * wglCopyContext (OPENGL32.@)
192 BOOL WINAPI
wglCopyContext(HGLRC hglrcSrc
,
195 FIXME("(%p,%p,%d)\n", hglrcSrc
, hglrcDst
, mask
);
200 /***********************************************************************
201 * wglDeleteContext (OPENGL32.@)
203 BOOL WINAPI
wglDeleteContext(HGLRC hglrc
)
205 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
208 TRACE("(%p)\n", hglrc
);
211 /* A game (Half Life not to name it) deletes twice the same context,
212 * so make sure it is valid first */
213 if (is_valid_context( ctx
))
215 if (ctx
->ctx
) glXDestroyContext(ctx
->display
, ctx
->ctx
);
220 WARN("Error deleting context !\n");
221 SetLastError(ERROR_INVALID_HANDLE
);
229 /***********************************************************************
230 * wglDescribeLayerPlane (OPENGL32.@)
232 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
236 LPLAYERPLANEDESCRIPTOR plpd
) {
237 FIXME("(%p,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
242 /***********************************************************************
243 * wglGetCurrentContext (OPENGL32.@)
245 HGLRC WINAPI
wglGetCurrentContext(void) {
252 gl_ctx
= glXGetCurrentContext();
253 ret
= get_context_from_GLXContext(gl_ctx
);
256 TRACE(" returning %p (GL context %p)\n", ret
, gl_ctx
);
261 /***********************************************************************
262 * wglGetCurrentDC (OPENGL32.@)
264 HDC WINAPI
wglGetCurrentDC(void) {
271 gl_ctx
= glXGetCurrentContext();
272 ret
= get_context_from_GLXContext(gl_ctx
);
276 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret
->hdc
, gl_ctx
, ret
);
279 TRACE(" no Wine context found for GLX context %p\n", gl_ctx
);
284 /***********************************************************************
285 * wglGetLayerPaletteEntries (OPENGL32.@)
287 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
291 const COLORREF
*pcr
) {
292 FIXME("(): stub !\n");
297 /***********************************************************************
298 * wglGetProcAddress (OPENGL32.@)
300 static int compar(const void *elt_a
, const void *elt_b
) {
301 return strcmp(((OpenGL_extension
*) elt_a
)->name
,
302 ((OpenGL_extension
*) elt_b
)->name
);
305 void* WINAPI
wglGetProcAddress(LPCSTR lpszProc
) {
307 static HMODULE hm
= 0;
308 OpenGL_extension ext
;
309 OpenGL_extension
*ext_ret
;
312 TRACE("(%s)\n", lpszProc
);
315 hm
= GetModuleHandleA("opengl32");
317 /* First, look if it's not already defined in the 'standard' OpenGL functions */
318 if ((local_func
= GetProcAddress(hm
, lpszProc
)) != NULL
) {
319 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func
);
323 if (p_glXGetProcAddressARB
== NULL
) {
324 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
328 /* After that, search in the thunks to find the real name of the extension */
329 ext
.name
= (char *) lpszProc
;
330 ext_ret
= (OpenGL_extension
*) bsearch(&ext
, extension_registry
,
331 extension_registry_size
, sizeof(OpenGL_extension
), compar
);
333 if (ext_ret
== NULL
) {
334 /* Some sanity checks :-) */
336 local_func
= p_glXGetProcAddressARB(lpszProc
);
338 if (local_func
!= NULL
) {
339 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc
);
343 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc
);
347 local_func
= p_glXGetProcAddressARB(ext_ret
->glx_name
);
350 /* After that, look at the extensions defined in the Linux OpenGL library */
351 if (local_func
== NULL
) {
355 /* Remove the 3 last letters (EXT, ARB, ...).
357 I know that some extensions have more than 3 letters (MESA, NV,
358 INTEL, ...), but this is only a stop-gap measure to fix buggy
359 OpenGL drivers (moreover, it is only useful for old 1.0 apps
360 that query the glBindTextureEXT extension).
362 strncpy(buf
, ext_ret
->glx_name
, strlen(ext_ret
->glx_name
) - 3);
363 buf
[strlen(ext_ret
->glx_name
) - 3] = '\0';
364 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
366 ret
= GetProcAddress(hm
, buf
);
368 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
370 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, ext_ret
->glx_name
);
375 TRACE(" returning function (%p)\n", ext_ret
->func
);
376 *(ext_ret
->func_ptr
) = local_func
;
378 return ext_ret
->func
;
383 /***********************************************************************
384 * wglMakeCurrent (OPENGL32.@)
386 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
390 TRACE("(%p,%p)\n", hdc
, hglrc
);
394 ret
= glXMakeCurrent(default_display
, None
, NULL
);
396 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
397 Drawable drawable
= get_drawable( hdc
);
399 if (ctx
->ctx
== NULL
) {
400 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, True
);
401 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
403 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
406 TRACE(" returning %s\n", (ret
? "True" : "False"));
410 /***********************************************************************
411 * wglRealizeLayerPalette (OPENGL32.@)
413 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
421 /***********************************************************************
422 * wglSetLayerPaletteEntries (OPENGL32.@)
424 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
428 const COLORREF
*pcr
) {
429 FIXME("(): stub !\n");
434 /***********************************************************************
435 * wglShareLists (OPENGL32.@)
437 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
439 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
440 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
442 TRACE("(%p, %p)\n", org
, dest
);
444 if (dest
->ctx
!= NULL
) {
445 ERR("Could not share display lists, context already created !\n");
448 if (org
->ctx
== NULL
) {
450 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, True
);
452 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
456 /* Create the destination context with display lists shared */
457 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, True
);
459 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
465 /***********************************************************************
466 * wglSwapLayerBuffers (OPENGL32.@)
468 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
470 TRACE("(%p, %08x)\n", hdc
, fuPlanes
);
472 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
473 if (!SwapBuffers(hdc
)) return FALSE
;
474 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
478 WARN("Following layers unhandled : %08x\n", fuPlanes
);
484 static BOOL
internal_wglUseFontBitmaps(HDC hdc
,
488 DWORD
WINAPI (*GetGlyphOutline_ptr
)(HDC
,UINT
,UINT
,LPGLYPHMETRICS
,DWORD
,LPVOID
,const MAT2
*))
490 /* We are running using client-side rendering fonts... */
492 static const MAT2 id
= { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
495 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
499 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
500 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
503 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
504 int needed_size
= GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &id
);
505 int height
, width_int
;
507 if (needed_size
== GDI_ERROR
) goto error
;
508 if (needed_size
> size
) {
510 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
511 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
512 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
513 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
515 if (GetGlyphOutline_ptr(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &id
) == GDI_ERROR
) goto error
;
516 if (TRACE_ON(opengl
)) {
517 unsigned int height
, width
, bitmask
;
518 unsigned char *bitmap_
= (unsigned char *) bitmap
;
520 DPRINTF("Glyph : %d\n", glyph
);
521 DPRINTF(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
522 DPRINTF(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
523 DPRINTF(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
524 DPRINTF(" - size : %d\n", needed_size
);
525 DPRINTF(" - bitmap : \n");
526 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
528 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
533 if (*bitmap_
& bitmask
)
538 bitmap_
+= (4 - (((unsigned int) bitmap_
) & 0x03));
543 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
544 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
545 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
546 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
548 for (width
= 0; width
< width_int
; width
++) {
549 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
550 ((int *) bitmap
)[height
* width_int
+ width
];
555 glNewList(listBase
++, GL_COMPILE
);
556 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmptGlyphOrigin
.x
,
557 gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
, gm
.gmCellIncX
, gm
.gmCellIncY
, gl_bitmap
);
563 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
566 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
567 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
572 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
575 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
576 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
580 /***********************************************************************
581 * wglUseFontBitmapsA (OPENGL32.@)
583 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
588 Font fid
= get_font( hdc
);
590 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
593 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineA
);
597 /* I assume that the glyphs are at the same position for X and for Windows */
598 glXUseXFont(fid
, first
, count
, listBase
);
603 /***********************************************************************
604 * wglUseFontBitmapsW (OPENGL32.@)
606 BOOL WINAPI
wglUseFontBitmapsW(HDC hdc
,
611 Font fid
= get_font( hdc
);
613 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
616 return internal_wglUseFontBitmaps(hdc
, first
, count
, listBase
, GetGlyphOutlineW
);
619 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
622 /* I assume that the glyphs are at the same position for X and for Windows */
623 glXUseXFont(fid
, first
, count
, listBase
);
628 /***********************************************************************
629 * wglUseFontOutlinesA (OPENGL32.@)
631 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
638 LPGLYPHMETRICSFLOAT lpgmf
) {
639 FIXME("(): stub !\n");
644 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
645 include all dependencies
648 #define SONAME_LIBGL "libGL.so"
651 /* This is for brain-dead applications that use OpenGL functions before even
652 creating a rendering context.... */
653 static BOOL
process_attach(void)
655 XWindowAttributes win_attr
;
658 XVisualInfo
template;
660 XVisualInfo
*vis
= NULL
;
661 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
662 HMODULE mod
= GetModuleHandleA( "x11drv.dll" );
667 ERR("X11DRV not loaded. Cannot create default context.\n");
671 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
672 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
675 default_display
= get_display( hdc
);
677 if (!default_display
)
679 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
685 /* Try to get the visual from the Root Window. We can't use the standard (presumably
686 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
687 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
688 with mismatched visuals. Note that the Root Window visual may not be double
689 buffered, so apps actually attempting to render this way may flicker */
690 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
692 rootVisual
= win_attr
.visual
;
696 /* Get the default visual, since we can't seem to get the attributes from the
697 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
698 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
701 template.visualid
= XVisualIDFromVisual(rootVisual
);
702 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
703 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
704 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
708 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
709 if (opengl_handle
!= NULL
) {
710 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
711 wine_dlclose(opengl_handle
, NULL
, 0);
712 if (p_glXGetProcAddressARB
== NULL
)
713 TRACE("could not find glXGetProcAddressARB in libGL.\n");
716 if (default_cx
== NULL
) {
717 ERR("Could not create default context.\n");
722 /**********************************************************************/
724 /* Some WGL extensions... */
725 static const char *WGL_extensions
= "WGL_ARB_extensions_string WGL_EXT_extensions_string";
727 /**********************************************************************/
729 const char * WINAPI
wglGetExtensionsStringEXT(void) {
730 TRACE("() returning \"%s\"\n", WGL_extensions
);
732 return WGL_extensions
;
735 /**********************************************************************/
737 static void process_detach(void)
739 glXDestroyContext(default_display
, default_cx
);
742 /***********************************************************************
743 * wglGetExtensionsStringARB(OPENGL32.@)
745 const char * WINAPI
wglGetExtensionsStringARB(HDC hdc
) {
747 return wglGetExtensionsStringEXT();
751 /***********************************************************************
752 * OpenGL initialisation routine
754 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
758 case DLL_PROCESS_ATTACH
:
759 DisableThreadLibraryCalls(hinst
);
760 return process_attach();
761 case DLL_PROCESS_DETACH
: