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
33 #include "opengl_ext.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(opengl
);
38 static GLXContext default_cx
= NULL
;
39 static Display
*default_display
; /* display to use for default context */
41 typedef struct wine_glcontext
{
46 struct wine_glcontext
*next
;
47 struct wine_glcontext
*prev
;
49 static Wine_GLContext
*context_list
;
51 static inline Wine_GLContext
*get_context_from_GLXContext(GLXContext ctx
)
54 for (ret
= context_list
; ret
; ret
= ret
->next
) if (ctx
== ret
->ctx
) break;
58 static inline void free_context(Wine_GLContext
*context
)
60 if (context
->next
!= NULL
) context
->next
->prev
= context
->prev
;
61 if (context
->prev
!= NULL
) context
->prev
->next
= context
->next
;
62 else context_list
= context
->next
;
64 HeapFree(GetProcessHeap(), 0, context
);
67 static inline Wine_GLContext
*alloc_context(void)
71 if ((ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(Wine_GLContext
))))
73 ret
->next
= context_list
;
74 if (context_list
) context_list
->prev
= ret
;
80 inline static BOOL
is_valid_context( Wine_GLContext
*ctx
)
83 for (ptr
= context_list
; ptr
; ptr
= ptr
->next
) if (ptr
== ctx
) break;
87 /* retrieve the X display to use on a given DC */
88 inline static Display
*get_display( HDC hdc
)
91 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
93 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
94 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
99 /* retrieve the X drawable to use on a given DC */
100 inline static Drawable
get_drawable( HDC hdc
)
103 enum x11drv_escape_codes escape
= X11DRV_GET_DRAWABLE
;
105 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
106 sizeof(drawable
), (LPSTR
)&drawable
)) drawable
= 0;
111 /* retrieve the X drawable to use on a given DC */
112 inline static Font
get_font( HDC hdc
)
115 enum x11drv_escape_codes escape
= X11DRV_GET_FONT
;
117 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
118 sizeof(font
), (LPSTR
)&font
)) font
= 0;
123 /***********************************************************************
124 * wglCreateContext (OPENGL32.@)
126 HGLRC WINAPI
wglCreateContext(HDC hdc
)
131 XVisualInfo
template;
132 Display
*display
= get_display( hdc
);
134 TRACE("(%08x)\n", hdc
);
136 /* First, get the visual in use by the X11DRV */
137 if (!display
) return 0;
138 template.visualid
= GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
139 vis
= XGetVisualInfo(display
, VisualIDMask
, &template, &num
);
142 ERR("NULL visual !!!\n");
143 /* Need to set errors here */
147 /* The context will be allocated in the wglMakeCurrent call */
149 ret
= alloc_context();
152 ret
->display
= display
;
155 TRACE(" creating context %p (GL context creation delayed)\n", ret
);
159 /***********************************************************************
160 * wglCreateLayerContext (OPENGL32.@)
162 HGLRC WINAPI
wglCreateLayerContext(HDC hdc
,
164 FIXME("(%08x,%d): stub !\n", hdc
, iLayerPlane
);
169 /***********************************************************************
170 * wglCopyContext (OPENGL32.@)
172 BOOL WINAPI
wglCopyContext(HGLRC hglrcSrc
,
175 FIXME("(%p,%p,%d)\n", hglrcSrc
, hglrcDst
, mask
);
180 /***********************************************************************
181 * wglDeleteContext (OPENGL32.@)
183 BOOL WINAPI
wglDeleteContext(HGLRC hglrc
)
185 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
188 TRACE("(%p)\n", hglrc
);
191 /* A game (Half Life not to name it) deletes twice the same context,
192 * so make sure it is valid first */
193 if (is_valid_context( ctx
))
195 if (ctx
->ctx
) glXDestroyContext(ctx
->display
, ctx
->ctx
);
200 WARN("Error deleting context !\n");
201 SetLastError(ERROR_INVALID_HANDLE
);
209 /***********************************************************************
210 * wglDescribeLayerPlane (OPENGL32.@)
212 BOOL WINAPI
wglDescribeLayerPlane(HDC hdc
,
216 LPLAYERPLANEDESCRIPTOR plpd
) {
217 FIXME("(%08x,%d,%d,%d,%p)\n", hdc
, iPixelFormat
, iLayerPlane
, nBytes
, plpd
);
222 /***********************************************************************
223 * wglGetCurrentContext (OPENGL32.@)
225 HGLRC WINAPI
wglGetCurrentContext(void) {
232 gl_ctx
= glXGetCurrentContext();
233 ret
= get_context_from_GLXContext(gl_ctx
);
236 TRACE(" returning %p (GL context %p)\n", ret
, gl_ctx
);
241 /***********************************************************************
242 * wglGetCurrentDC (OPENGL32.@)
244 HDC WINAPI
wglGetCurrentDC(void) {
251 gl_ctx
= glXGetCurrentContext();
252 ret
= get_context_from_GLXContext(gl_ctx
);
256 TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret
->hdc
, gl_ctx
, ret
);
259 TRACE(" no Wine context found for GLX context %p\n", gl_ctx
);
264 /***********************************************************************
265 * wglGetLayerPaletteEntries (OPENGL32.@)
267 int WINAPI
wglGetLayerPaletteEntries(HDC hdc
,
271 const COLORREF
*pcr
) {
272 FIXME("(): stub !\n");
277 /***********************************************************************
278 * wglGetProcAddress (OPENGL32.@)
280 static int compar(const void *elt_a
, const void *elt_b
) {
281 return strcmp(((OpenGL_extension
*) elt_a
)->name
,
282 ((OpenGL_extension
*) elt_b
)->name
);
285 void* WINAPI
wglGetProcAddress(LPCSTR lpszProc
) {
287 static HMODULE hm
= 0;
288 OpenGL_extension ext
;
289 OpenGL_extension
*ext_ret
;
292 TRACE("(%s)\n", lpszProc
);
295 hm
= GetModuleHandleA("opengl32");
297 /* First, look if it's not already defined in the 'standard' OpenGL functions */
298 if ((local_func
= GetProcAddress(hm
, lpszProc
)) != NULL
) {
299 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func
);
303 /* After that, search in the thunks to find the real name of the extension */
304 ext
.name
= (char *) lpszProc
;
305 ext_ret
= (OpenGL_extension
*) bsearch(&ext
, extension_registry
,
306 extension_registry_size
, sizeof(OpenGL_extension
), compar
);
308 if (ext_ret
== NULL
) {
309 /* Some sanity checks :-) */
310 if (glXGetProcAddressARB(lpszProc
) != NULL
) {
311 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc
);
315 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc
);
318 /* After that, look at the extensions defined in the Linux OpenGL library */
319 if ((local_func
= glXGetProcAddressARB(ext_ret
->glx_name
)) == NULL
) {
323 /* Remove the 3 last letters (EXT, ARB, ...).
325 I know that some extensions have more than 3 letters (MESA, NV,
326 INTEL, ...), but this is only a stop-gap measure to fix buggy
327 OpenGL drivers (moreover, it is only useful for old 1.0 apps
328 that query the glBindTextureEXT extension).
330 strncpy(buf
, ext_ret
->glx_name
, strlen(ext_ret
->glx_name
) - 3);
331 buf
[strlen(ext_ret
->glx_name
) - 3] = '\0';
332 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf
);
334 ret
= GetProcAddress(hm
, buf
);
336 TRACE(" found function in main OpenGL library (%p) !\n", ret
);
338 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc
, ext_ret
->glx_name
);
343 TRACE(" returning function (%p)\n", ext_ret
->func
);
344 *(ext_ret
->func_ptr
) = local_func
;
346 return ext_ret
->func
;
351 /***********************************************************************
352 * wglMakeCurrent (OPENGL32.@)
354 BOOL WINAPI
wglMakeCurrent(HDC hdc
,
358 TRACE("(%08x,%p)\n", hdc
, hglrc
);
362 ret
= glXMakeCurrent(default_display
, None
, NULL
);
364 Wine_GLContext
*ctx
= (Wine_GLContext
*) hglrc
;
365 Drawable drawable
= get_drawable( hdc
);
367 if (ctx
->ctx
== NULL
) {
368 ctx
->ctx
= glXCreateContext(ctx
->display
, ctx
->vis
, NULL
, True
);
369 TRACE(" created a delayed OpenGL context (%p)\n", ctx
->ctx
);
371 ret
= glXMakeCurrent(ctx
->display
, drawable
, ctx
->ctx
);
374 TRACE(" returning %s\n", (ret
? "True" : "False"));
378 /***********************************************************************
379 * wglRealizeLayerPalette (OPENGL32.@)
381 BOOL WINAPI
wglRealizeLayerPalette(HDC hdc
,
389 /***********************************************************************
390 * wglSetLayerPaletteEntries (OPENGL32.@)
392 int WINAPI
wglSetLayerPaletteEntries(HDC hdc
,
396 const COLORREF
*pcr
) {
397 FIXME("(): stub !\n");
402 /***********************************************************************
403 * wglShareLists (OPENGL32.@)
405 BOOL WINAPI
wglShareLists(HGLRC hglrc1
,
407 Wine_GLContext
*org
= (Wine_GLContext
*) hglrc1
;
408 Wine_GLContext
*dest
= (Wine_GLContext
*) hglrc2
;
410 TRACE("(%p, %p)\n", org
, dest
);
412 if (dest
->ctx
!= NULL
) {
413 ERR("Could not share display lists, context already created !\n");
416 if (org
->ctx
== NULL
) {
418 org
->ctx
= glXCreateContext(org
->display
, org
->vis
, NULL
, True
);
420 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org
->ctx
, org
);
424 /* Create the destination context with display lists shared */
425 dest
->ctx
= glXCreateContext(org
->display
, dest
->vis
, org
->ctx
, True
);
427 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest
->ctx
, dest
, org
->ctx
);
433 /***********************************************************************
434 * wglSwapLayerBuffers (OPENGL32.@)
436 BOOL WINAPI
wglSwapLayerBuffers(HDC hdc
,
438 TRACE("(%08x, %08x)\n", hdc
, fuPlanes
);
440 if (fuPlanes
& WGL_SWAP_MAIN_PLANE
) {
441 if (!SwapBuffers(hdc
)) return FALSE
;
442 fuPlanes
&= ~WGL_SWAP_MAIN_PLANE
;
446 WARN("Following layers unhandled : %08x\n", fuPlanes
);
452 /***********************************************************************
453 * wglUseFontBitmapsA (OPENGL32.@)
455 BOOL WINAPI
wglUseFontBitmapsA(HDC hdc
,
460 Font fid
= get_font( hdc
);
462 TRACE("(%08x, %ld, %ld, %ld)\n", hdc
, first
, count
, listBase
);
465 /* I assume that the glyphs are at the same position for X and for Windows */
466 glXUseXFont(fid
, first
, count
, listBase
);
471 /***********************************************************************
472 * wglUseFontOutlinesA (OPENGL32.@)
474 BOOL WINAPI
wglUseFontOutlinesA(HDC hdc
,
481 LPGLYPHMETRICSFLOAT lpgmf
) {
482 FIXME("(): stub !\n");
488 /* This is for brain-dead applications that use OpenGL functions before even
489 creating a rendering context.... */
490 static BOOL
process_attach(void)
492 XWindowAttributes win_attr
;
495 XVisualInfo
template;
497 XVisualInfo
*vis
= NULL
;
498 Window root
= (Window
)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
502 ERR("X11DRV not loaded. Cannot create default context.\n");
507 default_display
= get_display( hdc
);
509 if (!default_display
)
511 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
517 /* Try to get the visual from the Root Window. We can't use the standard (presumably
518 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
519 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
520 with mismatched visuals. Note that the Root Window visual may not be double
521 buffered, so apps actually attempting to render this way may flicker */
522 if (XGetWindowAttributes( default_display
, root
, &win_attr
))
524 rootVisual
= win_attr
.visual
;
528 /* Get the default visual, since we can't seem to get the attributes from the
529 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
530 rootVisual
= DefaultVisual( default_display
, DefaultScreen(default_display
) );
533 template.visualid
= XVisualIDFromVisual(rootVisual
);
534 vis
= XGetVisualInfo(default_display
, VisualIDMask
, &template, &num
);
535 if (vis
!= NULL
) default_cx
= glXCreateContext(default_display
, vis
, 0, GL_TRUE
);
536 if (default_cx
!= NULL
) glXMakeCurrent(default_display
, root
, default_cx
);
540 if (default_cx
== NULL
) {
541 ERR("Could not create default context.\n");
546 static void process_detach(void)
548 glXDestroyContext(default_display
, default_cx
);
551 /***********************************************************************
552 * OpenGL initialisation routine
554 BOOL WINAPI
OpenGL32_Init( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
558 case DLL_PROCESS_ATTACH
:
559 return process_attach();
560 case DLL_PROCESS_DETACH
: