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
31 #include "opengl_ext.h"
32 #include "wine/debug.h"
33 #include "wine/port.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl
);
37 /* x11drv GDI escapes */
38 #define X11DRV_ESCAPE 6789
39 enum x11drv_escape_codes
41 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
42 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
43 X11DRV_GET_FONT
, /* get current X font for a DC */
46 void (*wine_tsx11_lock_ptr
)(void) = NULL
;
47 void (*wine_tsx11_unlock_ptr
)(void) = NULL
;
49 static GLXContext default_cx
= NULL
;
50 static Display
*default_display
; /* display to use for default context */
52 static void *(*p_glXGetProcAddressARB
)(const GLubyte
*);
54 typedef struct wine_glcontext
{
59 struct wine_glcontext
*next
;
60 struct wine_glcontext
*prev
;
62 static Wine_GLContext
*context_list
;
64 static inline Wine_GLContext
*get_context_from_GLXContext(GLXContext ctx
)
67 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
71 static inline void free_context(Wine_GLContext
*context
)
73 if (context
->next
!= NULL
) context
->next
->prev
= context
->prev
;
74 if (context
->prev
!= NULL
) context
->prev
->next
= context
->next
;
75 else context_list
= context
->next
;
77 HeapFree(GetProcessHeap(), 0, context
);
80 static inline Wine_GLContext
*alloc_context(void)
84 if ((ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(Wine_GLContext
))))
86 ret
->next
= context_list
;
87 if (context_list
) context_list
->prev
= ret
;
93 inline static BOOL
is_valid_context( Wine_GLContext
*ctx
)
96 for (ptr
= context_list
; ptr
; ptr
= ptr
->next
) if (ptr
== ctx
) break;
100 /* retrieve the X display to use on a given DC */
101 inline static Display
*get_display( HDC hdc
)
104 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
106 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
107 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
112 /* retrieve the X drawable to use on a given DC */
113 inline static Drawable
get_drawable( HDC hdc
)
116 enum x11drv_escape_codes escape
= X11DRV_GET_DRAWABLE
;
118 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
119 sizeof(drawable
), (LPSTR
)&drawable
)) drawable
= 0;
124 /* retrieve the X drawable to use on a given DC */
125 inline static Font
get_font( HDC hdc
)
128 enum x11drv_escape_codes escape
= X11DRV_GET_FONT
;
130 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
131 sizeof(font
), (LPSTR
)&font
)) font
= 0;
136 /***********************************************************************
137 * wglCreateContext (OPENGL32.@)
139 HGLRC WINAPI
wglCreateContext(HDC hdc
)
144 XVisualInfo
template;
145 Display
*display
= get_display( hdc
);
147 TRACE("(%p)\n", hdc
);
149 /* First, get the visual in use by the X11DRV */
150 if (!display
) return 0;
151 template.visualid
= (VisualID
)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
152 vis
= XGetVisualInfo(display
, VisualIDMask
, &template, &num
);
155 ERR("NULL visual !!!\n");
156 /* Need to set errors here */
160 /* The context will be allocated in the wglMakeCurrent call */
162 ret
= alloc_context();
165 ret
->display
= display
;
168 TRACE(" creating context %p (GL context creation delayed)\n", ret
);
172 /***********************************************************************
173 * wglCreateLayerContext (OPENGL32.@)
175 HGLRC WINAPI
wglCreateLayerContext(HDC hdc
,
177 TRACE("(%p,%d)\n", hdc
, iLayerPlane
);
179 if (iLayerPlane
== 0) {
180 return wglCreateContext(hdc
);
182 FIXME(" no handler for layer %d\n", iLayerPlane
);
187 /***********************************************************************
188 * wglCopyContext (OPENGL32.@)
190 BOOL WINAPI
wglCopyContext(HGLRC hglrcSrc
,
193 FIXME("(%p,%p,%d)\n", hglrcSrc
, hglrcDst
, mask
);
198 /***********************************************************************
199 * wglDeleteContext (OPENGL32.@)
201 BOOL WINAPI
wglDeleteContext(HGLRC hglrc
)
203 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
206 TRACE("(%p)\n", hglrc
);
209 /* A game (Half Life not to name it) deletes twice the same context,
210 * so make sure it is valid first */
211 if (is_valid_context( ctx
))
213 if (ctx
->ctx
) glXDestroyContext(ctx
->display
, ctx
->ctx
);
218 WARN("Error deleting context !\n");
219 SetLastError(ERROR_INVALID_HANDLE
);
227 /***********************************************************************
228 * wglDescribeLayerPlane (OPENGL32.@)
230 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
234 LPLAYERPLANEDESCRIPTOR plpd
) {
235 FIXME("(%p,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
240 /***********************************************************************
241 * wglGetCurrentContext (OPENGL32.@)
243 HGLRC WINAPI
wglGetCurrentContext(void) {
250 gl_ctx
= glXGetCurrentContext();
251 ret
= get_context_from_GLXContext(gl_ctx
);
254 TRACE(" returning %p (GL context %p)\n", ret
, gl_ctx
);
259 /***********************************************************************
260 * wglGetCurrentDC (OPENGL32.@)
262 HDC WINAPI
wglGetCurrentDC(void) {
269 gl_ctx
= glXGetCurrentContext();
270 ret
= get_context_from_GLXContext(gl_ctx
);
274 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret
->hdc
, gl_ctx
, ret
);
277 TRACE(" no Wine context found for GLX context %p\n", gl_ctx
);
282 /***********************************************************************
283 * wglGetLayerPaletteEntries (OPENGL32.@)
285 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
289 const COLORREF
*pcr
) {
290 FIXME("(): stub !\n");
295 /***********************************************************************
296 * wglGetProcAddress (OPENGL32.@)
298 static int compar(const void *elt_a
, const void *elt_b
) {
299 return strcmp(((OpenGL_extension
*) elt_a
)->name
,
300 ((OpenGL_extension
*) elt_b
)->name
);
303 void* WINAPI
wglGetProcAddress(LPCSTR lpszProc
) {
305 static HMODULE hm
= 0;
306 OpenGL_extension ext
;
307 OpenGL_extension
*ext_ret
;
310 TRACE("(%s)\n", lpszProc
);
313 hm
= GetModuleHandleA("opengl32");
315 /* First, look if it's not already defined in the 'standard' OpenGL functions */
316 if ((local_func
= GetProcAddress(hm
, lpszProc
)) != NULL
) {
317 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func
);
321 if (p_glXGetProcAddressARB
== NULL
) {
322 ERR("Warning : dynamic GL extension loading not supported by native GL library.");
326 /* After that, search in the thunks to find the real name of the extension */
327 ext
.name
= (char *) lpszProc
;
328 ext_ret
= (OpenGL_extension
*) bsearch(&ext
, extension_registry
,
329 extension_registry_size
, sizeof(OpenGL_extension
), compar
);
331 if (ext_ret
== NULL
) {
332 /* Some sanity checks :-) */
334 local_func
= p_glXGetProcAddressARB(lpszProc
);
336 if (local_func
!= NULL
) {
337 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc
);
341 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc
);
345 local_func
= p_glXGetProcAddressARB(ext_ret
->glx_name
);
348 /* After that, look at the extensions defined in the Linux OpenGL library */
349 if (local_func
== NULL
) {
353 /* Remove the 3 last letters (EXT, ARB, ...).
355 I know that some extensions have more than 3 letters (MESA, NV,
356 INTEL, ...), but this is only a stop-gap measure to fix buggy
357 OpenGL drivers (moreover, it is only useful for old 1.0 apps
358 that query the glBindTextureEXT extension).
360 strncpy(buf
, ext_ret
->glx_name
, strlen(ext_ret
->glx_name
) - 3);
361 buf
[strlen(ext_ret
->glx_name
) - 3] = '\0';
362 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
364 ret
= GetProcAddress(hm
, buf
);
366 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
368 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, ext_ret
->glx_name
);
373 TRACE(" returning function (%p)\n", ext_ret
->func
);
374 *(ext_ret
->func_ptr
) = local_func
;
376 return ext_ret
->func
;
381 /***********************************************************************
382 * wglMakeCurrent (OPENGL32.@)
384 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
388 TRACE("(%p,%p)\n", hdc
, hglrc
);
392 ret
= glXMakeCurrent(default_display
, None
, NULL
);
394 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
395 Drawable drawable
= get_drawable( hdc
);
397 if (ctx
->ctx
== NULL
) {
398 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, True
);
399 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
401 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
404 TRACE(" returning %s\n", (ret
? "True" : "False"));
408 /***********************************************************************
409 * wglRealizeLayerPalette (OPENGL32.@)
411 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
419 /***********************************************************************
420 * wglSetLayerPaletteEntries (OPENGL32.@)
422 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
426 const COLORREF
*pcr
) {
427 FIXME("(): stub !\n");
432 /***********************************************************************
433 * wglShareLists (OPENGL32.@)
435 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
437 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
438 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
440 TRACE("(%p, %p)\n", org
, dest
);
442 if (dest
->ctx
!= NULL
) {
443 ERR("Could not share display lists, context already created !\n");
446 if (org
->ctx
== NULL
) {
448 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, True
);
450 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
454 /* Create the destination context with display lists shared */
455 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, True
);
457 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
463 /***********************************************************************
464 * wglSwapLayerBuffers (OPENGL32.@)
466 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
468 TRACE("(%p, %08x)\n", hdc
, fuPlanes
);
470 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
471 if (!SwapBuffers(hdc
)) return FALSE
;
472 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
476 WARN("Following layers unhandled : %08x\n", fuPlanes
);
482 /***********************************************************************
483 * wglUseFontBitmapsA (OPENGL32.@)
485 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
490 Font fid
= get_font( hdc
);
492 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc
, first
, count
, listBase
, fid
);
495 /* We are running using client-side rendering fonts... */
497 static const MAT2 id
= { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
500 void *bitmap
= NULL
, *gl_bitmap
= NULL
;
504 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &org_alignment
);
505 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
508 for (glyph
= first
; glyph
< first
+ count
; glyph
++) {
509 int needed_size
= GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, 0, NULL
, &id
);
510 int height
, width_int
;
512 if (needed_size
== GDI_ERROR
) goto error
;
513 if (needed_size
> size
) {
515 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
516 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
517 bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
518 gl_bitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
520 if (GetGlyphOutlineA(hdc
, glyph
, GGO_BITMAP
, &gm
, size
, bitmap
, &id
) == GDI_ERROR
) goto error
;
521 if (TRACE_ON(opengl
)) {
522 unsigned int height
, width
, bitmask
;
523 unsigned char *bitmap_
= (unsigned char *) bitmap
;
525 DPRINTF("Glyph : %d\n", glyph
);
526 DPRINTF(" - bbox : %d x %d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
527 DPRINTF(" - origin : (%ld , %ld)\n", gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
528 DPRINTF(" - increment : %d - %d\n", gm
.gmCellIncX
, gm
.gmCellIncY
);
529 DPRINTF(" - size : %d\n", needed_size
);
530 DPRINTF(" - bitmap : \n");
531 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
533 for (width
= 0, bitmask
= 0x80; width
< gm
.gmBlackBoxX
; width
++, bitmask
>>= 1) {
538 if (*bitmap_
& bitmask
)
543 bitmap_
+= (4 - (((unsigned int) bitmap_
) & 0x03));
548 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
549 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
550 width_int
= (gm
.gmBlackBoxX
+ 31) / 32;
551 for (height
= 0; height
< gm
.gmBlackBoxY
; height
++) {
553 for (width
= 0; width
< width_int
; width
++) {
554 ((int *) gl_bitmap
)[(gm
.gmBlackBoxY
- height
- 1) * width_int
+ width
] =
555 ((int *) bitmap
)[height
* width_int
+ width
];
560 glNewList(listBase
++, GL_COMPILE
);
561 glBitmap(gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmptGlyphOrigin
.x
, gm
.gmBlackBoxY
- gm
.gmptGlyphOrigin
.y
, gm
.gmCellIncX
, gm
.gmCellIncY
, gl_bitmap
);
567 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
570 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
571 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
576 glPixelStorei(GL_UNPACK_ALIGNMENT
, org_alignment
);
579 if (bitmap
) HeapFree(GetProcessHeap(), 0, bitmap
);
580 if (gl_bitmap
) HeapFree(GetProcessHeap(), 0, gl_bitmap
);
585 /* I assume that the glyphs are at the same position for X and for Windows */
586 glXUseXFont(fid
, first
, count
, listBase
);
591 /***********************************************************************
592 * wglUseFontOutlinesA (OPENGL32.@)
594 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
601 LPGLYPHMETRICSFLOAT lpgmf
) {
602 FIXME("(): stub !\n");
607 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
608 include all dependencies
611 #define SONAME_LIBGL "libGL.so"
614 /* This is for brain-dead applications that use OpenGL functions before even
615 creating a rendering context.... */
616 static BOOL
process_attach(void)
618 XWindowAttributes win_attr
;
621 XVisualInfo
template;
623 XVisualInfo
*vis
= NULL
;
624 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
625 HMODULE mod
= GetModuleHandleA( "x11drv.dll" );
627 const char *extensions
= NULL
;
631 ERR("X11DRV not loaded. Cannot create default context.\n");
635 wine_tsx11_lock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_lock" );
636 wine_tsx11_unlock_ptr
= (void *)GetProcAddress( mod
, "wine_tsx11_unlock" );
639 default_display
= get_display( hdc
);
641 if (!default_display
)
643 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
649 /* Try to get the visual from the Root Window. We can't use the standard (presumably
650 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
651 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
652 with mismatched visuals. Note that the Root Window visual may not be double
653 buffered, so apps actually attempting to render this way may flicker */
654 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
656 rootVisual
= win_attr
.visual
;
660 /* Get the default visual, since we can't seem to get the attributes from the
661 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
662 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
665 template.visualid
= XVisualIDFromVisual(rootVisual
);
666 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
667 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
668 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
669 extensions
= glXQueryExtensionsString(default_display
, DefaultScreen(default_display
));
673 if ((extensions
!= NULL
) && (strstr(extensions
, "GLX_ARB_get_proc_address"))) {
674 opengl_handle
= wine_dlopen(SONAME_LIBGL
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0);
675 if (opengl_handle
!= NULL
) {
676 p_glXGetProcAddressARB
= wine_dlsym(opengl_handle
, "glXGetProcAddressARB", NULL
, 0);
677 wine_dlclose(opengl_handle
, NULL
, 0);
681 if (default_cx
== NULL
) {
682 ERR("Could not create default context.\n");
687 /* Some WGL extensions... */
688 static const char *WGL_extensions
= "WGL_ARB_extensions_string WGL_EXT_extensions_string";
690 const char * WINAPI
wglGetExtensionsStringEXT(void) {
691 TRACE("() returning \"%s\"\n", WGL_extensions
);
693 return WGL_extensions
;
696 static void process_detach(void)
698 glXDestroyContext(default_display
, default_cx
);
701 /***********************************************************************
702 * wglGetExtensionsStringARB(OPENGL32.@)
704 const char * WINAPI
wglGetExtensionsStringARB(HDC hdc
) {
706 return wglGetExtensionsStringEXT();
710 /***********************************************************************
711 * OpenGL initialisation routine
713 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
717 case DLL_PROCESS_ATTACH
:
718 DisableThreadLibraryCalls(hinst
);
719 return process_attach();
720 case DLL_PROCESS_DETACH
: