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
32 #include "opengl_ext.h"
33 #include "wine/debug.h"
34 #include "wine/port.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(opengl
);
38 /* x11drv GDI escapes */
39 #define X11DRV_ESCAPE 6789
40 enum x11drv_escape_codes
42 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
43 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
44 X11DRV_GET_FONT
, /* get current X font for a DC */
47 void (*wine_tsx11_lock_ptr
)(void) = NULL
;
48 void (*wine_tsx11_unlock_ptr
)(void) = NULL
;
50 static GLXContext default_cx
= NULL
;
51 static Display
*default_display
; /* display to use for default context */
53 static void *(*p_glXGetProcAddressARB
)(const GLubyte
*);
55 typedef struct wine_glcontext
{
60 struct wine_glcontext
*next
;
61 struct wine_glcontext
*prev
;
63 static Wine_GLContext
*context_list
;
65 static inline Wine_GLContext
*get_context_from_GLXContext(GLXContext ctx
)
68 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
72 static inline void free_context(Wine_GLContext
*context
)
74 if (context
->next
!= NULL
) context
->next
->prev
= context
->prev
;
75 if (context
->prev
!= NULL
) context
->prev
->next
= context
->next
;
76 else context_list
= context
->next
;
78 HeapFree(GetProcessHeap(), 0, context
);
81 static inline Wine_GLContext
*alloc_context(void)
85 if ((ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(Wine_GLContext
))))
87 ret
->next
= context_list
;
88 if (context_list
) context_list
->prev
= ret
;
94 inline static BOOL
is_valid_context( Wine_GLContext
*ctx
)
97 for (ptr
= context_list
; ptr
; ptr
= ptr
->next
) if (ptr
== ctx
) break;
101 /* retrieve the X display to use on a given DC */
102 inline static Display
*get_display( HDC hdc
)
105 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
107 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
108 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
113 /* retrieve the X drawable to use on a given DC */
114 inline static Drawable
get_drawable( HDC hdc
)
117 enum x11drv_escape_codes escape
= X11DRV_GET_DRAWABLE
;
119 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
120 sizeof(drawable
), (LPSTR
)&drawable
)) drawable
= 0;
125 /* retrieve the X drawable to use on a given DC */
126 inline static Font
get_font( HDC hdc
)
129 enum x11drv_escape_codes escape
= X11DRV_GET_FONT
;
131 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
132 sizeof(font
), (LPSTR
)&font
)) font
= 0;
137 /***********************************************************************
138 * wglCreateContext (OPENGL32.@)
140 HGLRC WINAPI
wglCreateContext(HDC hdc
)
145 XVisualInfo
template;
146 Display
*display
= get_display( hdc
);
148 TRACE("(%p)\n", hdc
);
150 /* First, get the visual in use by the X11DRV */
151 if (!display
) return 0;
152 template.visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
153 vis
= XGetVisualInfo(display
, VisualIDMask
, &template, &num
);
156 ERR("NULL visual !!!\n");
157 /* Need to set errors here */
161 /* The context will be allocated in the wglMakeCurrent call */
163 ret
= alloc_context();
166 ret
->display
= display
;
169 TRACE(" creating context %p (GL context creation delayed)\n", ret
);
173 /***********************************************************************
174 * wglCreateLayerContext (OPENGL32.@)
176 HGLRC WINAPI
wglCreateLayerContext(HDC hdc
,
178 TRACE("(%p,%d)\n", hdc
, iLayerPlane
);
180 if (iLayerPlane
== 0) {
181 return wglCreateContext(hdc
);
183 FIXME(" no handler for layer %d\n", iLayerPlane
);
188 /***********************************************************************
189 * wglCopyContext (OPENGL32.@)
191 BOOL WINAPI
wglCopyContext(HGLRC hglrcSrc
,
194 FIXME("(%p,%p,%d)\n", hglrcSrc
, hglrcDst
, mask
);
199 /***********************************************************************
200 * wglDeleteContext (OPENGL32.@)
202 BOOL WINAPI
wglDeleteContext(HGLRC hglrc
)
204 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
207 TRACE("(%p)\n", hglrc
);
210 /* A game (Half Life not to name it) deletes twice the same context,
211 * so make sure it is valid first */
212 if (is_valid_context( ctx
))
214 if (ctx
->ctx
) glXDestroyContext(ctx
->display
, ctx
->ctx
);
219 WARN("Error deleting context !\n");
220 SetLastError(ERROR_INVALID_HANDLE
);
228 /***********************************************************************
229 * wglDescribeLayerPlane (OPENGL32.@)
231 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
235 LPLAYERPLANEDESCRIPTOR plpd
) {
236 FIXME("(%p,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
241 /***********************************************************************
242 * wglGetCurrentContext (OPENGL32.@)
244 HGLRC WINAPI
wglGetCurrentContext(void) {
251 gl_ctx
= glXGetCurrentContext();
252 ret
= get_context_from_GLXContext(gl_ctx
);
255 TRACE(" returning %p (GL context %p)\n", ret
, gl_ctx
);
260 /***********************************************************************
261 * wglGetCurrentDC (OPENGL32.@)
263 HDC WINAPI
wglGetCurrentDC(void) {
270 gl_ctx
= glXGetCurrentContext();
271 ret
= get_context_from_GLXContext(gl_ctx
);
275 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret
->hdc
, gl_ctx
, ret
);
278 TRACE(" no Wine context found for GLX context %p\n", gl_ctx
);
283 /***********************************************************************
284 * wglGetLayerPaletteEntries (OPENGL32.@)
286 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
290 const COLORREF
*pcr
) {
291 FIXME("(): stub !\n");
296 /***********************************************************************
297 * wglGetProcAddress (OPENGL32.@)
299 static int compar(const void *elt_a
, const void *elt_b
) {
300 return strcmp(((OpenGL_extension
*) elt_a
)->name
,
301 ((OpenGL_extension
*) elt_b
)->name
);
304 void* WINAPI
wglGetProcAddress(LPCSTR lpszProc
) {
306 static HMODULE hm
= 0;
307 OpenGL_extension ext
;
308 OpenGL_extension
*ext_ret
;
311 TRACE("(%s)\n", lpszProc
);
314 hm
= GetModuleHandleA("opengl32");
316 /* First, look if it's not already defined in the 'standard' OpenGL functions */
317 if ((local_func
= GetProcAddress(hm
, lpszProc
)) != NULL
) {
318 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func
);
322 if (p_glXGetProcAddressARB
== NULL
) {
323 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
327 /* After that, search in the thunks to find the real name of the extension */
328 ext
.name
= (char *) lpszProc
;
329 ext_ret
= (OpenGL_extension
*) bsearch(&ext
, extension_registry
,
330 extension_registry_size
, sizeof(OpenGL_extension
), compar
);
332 if (ext_ret
== NULL
) {
333 /* Some sanity checks :-) */
335 local_func
= p_glXGetProcAddressARB(lpszProc
);
337 if (local_func
!= NULL
) {
338 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc
);
342 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc
);
346 local_func
= p_glXGetProcAddressARB(ext_ret
->glx_name
);
349 /* After that, look at the extensions defined in the Linux OpenGL library */
350 if (local_func
== NULL
) {
354 /* Remove the 3 last letters (EXT, ARB, ...).
356 I know that some extensions have more than 3 letters (MESA, NV,
357 INTEL, ...), but this is only a stop-gap measure to fix buggy
358 OpenGL drivers (moreover, it is only useful for old 1.0 apps
359 that query the glBindTextureEXT extension).
361 strncpy(buf
, ext_ret
->glx_name
, strlen(ext_ret
->glx_name
) - 3);
362 buf
[strlen(ext_ret
->glx_name
) - 3] = '\0';
363 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
365 ret
= GetProcAddress(hm
, buf
);
367 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
369 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, ext_ret
->glx_name
);
374 TRACE(" returning function (%p)\n", ext_ret
->func
);
375 *(ext_ret
->func_ptr
) = local_func
;
377 return ext_ret
->func
;
382 /***********************************************************************
383 * wglMakeCurrent (OPENGL32.@)
385 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
389 TRACE("(%p,%p)\n", hdc
, hglrc
);
393 ret
= glXMakeCurrent(default_display
, None
, NULL
);
395 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
396 Drawable drawable
= get_drawable( hdc
);
398 if (ctx
->ctx
== NULL
) {
399 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, True
);
400 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
402 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
405 TRACE(" returning %s\n", (ret
? "True" : "False"));
409 /***********************************************************************
410 * wglRealizeLayerPalette (OPENGL32.@)
412 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
420 /***********************************************************************
421 * wglSetLayerPaletteEntries (OPENGL32.@)
423 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
427 const COLORREF
*pcr
) {
428 FIXME("(): stub !\n");
433 /***********************************************************************
434 * wglShareLists (OPENGL32.@)
436 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
438 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
439 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
441 TRACE("(%p, %p)\n", org
, dest
);
443 if (dest
->ctx
!= NULL
) {
444 ERR("Could not share display lists, context already created !\n");
447 if (org
->ctx
== NULL
) {
449 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, True
);
451 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
455 /* Create the destination context with display lists shared */
456 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, True
);
458 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
464 /***********************************************************************
465 * wglSwapLayerBuffers (OPENGL32.@)
467 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
469 TRACE("(%p, %08x)\n", hdc
, fuPlanes
);
471 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
472 if (!SwapBuffers(hdc
)) return FALSE
;
473 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
477 WARN("Following layers unhandled : %08x\n", fuPlanes
);
483 /***********************************************************************
484 * wglUseFontBitmapsA (OPENGL32.@)
486 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
491 Font fid
= get_font( hdc
);
493 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
496 /* We are running using client-side rendering fonts... */
498 static const MAT2 id
= { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
501 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
505 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
506 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
509 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
510 int needed_size
= GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &id
);
511 int height
, width_int
;
513 if (needed_size
== GDI_ERROR
) goto error
;
514 if (needed_size
> size
) {
516 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
517 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
518 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
519 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
521 if (GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &id
) == GDI_ERROR
) goto error
;
522 if (TRACE_ON(opengl
)) {
523 unsigned int height
, width
, bitmask
;
524 unsigned char *bitmap_
= (unsigned char *) bitmap
;
526 DPRINTF("Glyph : %d\n", glyph
);
527 DPRINTF(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
528 DPRINTF(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
529 DPRINTF(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
530 DPRINTF(" - size : %d\n", needed_size
);
531 DPRINTF(" - bitmap : \n");
532 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
534 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
539 if (*bitmap_
& bitmask
)
544 bitmap_
+= (4 - (((unsigned int) bitmap_
) & 0x03));
549 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
550 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
551 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
552 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
554 for (width
= 0; width
< width_int
; width
++) {
555 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
556 ((int *) bitmap
)[height
* width_int
+ width
];
561 glNewList(listBase
++, GL_COMPILE
);
562 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmptGlyphOrigin
.x
, gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
, gm
.gmCellIncX
, gm
.gmCellIncY
, gl_bitmap
);
568 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
571 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
572 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
577 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
580 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
581 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
586 /* I assume that the glyphs are at the same position for X and for Windows */
587 glXUseXFont(fid
, first
, count
, listBase
);
592 /***********************************************************************
593 * wglUseFontOutlinesA (OPENGL32.@)
595 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
602 LPGLYPHMETRICSFLOAT lpgmf
) {
603 FIXME("(): stub !\n");
608 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
609 include all dependencies
612 #define SONAME_LIBGL "libGL.so"
615 /* This is for brain-dead applications that use OpenGL functions before even
616 creating a rendering context.... */
617 static BOOL
process_attach(void)
619 XWindowAttributes win_attr
;
622 XVisualInfo
template;
624 XVisualInfo
*vis
= NULL
;
625 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
626 HMODULE mod
= GetModuleHandleA( "x11drv.dll" );
628 const char *extensions
= NULL
;
632 ERR("X11DRV not loaded. Cannot create default context.\n");
636 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
637 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
640 default_display
= get_display( hdc
);
642 if (!default_display
)
644 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
650 /* Try to get the visual from the Root Window. We can't use the standard (presumably
651 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
652 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
653 with mismatched visuals. Note that the Root Window visual may not be double
654 buffered, so apps actually attempting to render this way may flicker */
655 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
657 rootVisual
= win_attr
.visual
;
661 /* Get the default visual, since we can't seem to get the attributes from the
662 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
663 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
666 template.visualid
= XVisualIDFromVisual(rootVisual
);
667 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
668 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
669 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
670 extensions
= glXQueryExtensionsString(default_display
, DefaultScreen(default_display
));
674 if ((extensions
!= NULL
) && (strstr(extensions
, "GLX_ARB_get_proc_address"))) {
675 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
676 if (opengl_handle
!= NULL
) {
677 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
678 wine_dlclose(opengl_handle
, NULL
, 0);
682 if (default_cx
== NULL
) {
683 ERR("Could not create default context.\n");
688 /**********************************************************************/
690 /* Some WGL extensions... */
691 static const char *WGL_extensions
= "WGL_ARB_extensions_string WGL_EXT_extensions_string";
693 /**********************************************************************/
695 const char * WINAPI
wglGetExtensionsStringEXT(void) {
696 TRACE("() returning \"%s\"\n", WGL_extensions
);
698 return WGL_extensions
;
701 /**********************************************************************/
703 static void process_detach(void)
705 glXDestroyContext(default_display
, default_cx
);
708 /***********************************************************************
709 * wglGetExtensionsStringARB(OPENGL32.@)
711 const char * WINAPI
wglGetExtensionsStringARB(HDC hdc
) {
713 return wglGetExtensionsStringEXT();
717 /***********************************************************************
718 * OpenGL initialisation routine
720 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
724 case DLL_PROCESS_ATTACH
:
725 DisableThreadLibraryCalls(hinst
);
726 return process_attach();
727 case DLL_PROCESS_DETACH
: