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"
34 #include "opengl_ext.h"
35 #include "wine/library.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
40 /* x11drv GDI escapes */
41 #define X11DRV_ESCAPE 6789
42 enum x11drv_escape_codes
44 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
45 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
46 X11DRV_GET_FONT, /* get current X font for a DC */
49 void (*wine_tsx11_lock_ptr)(void) = NULL;
50 void (*wine_tsx11_unlock_ptr)(void) = NULL;
52 static GLXContext default_cx = NULL;
53 static Display *default_display; /* display to use for default context */
55 static HMODULE opengl32_handle;
57 static void *(*p_glXGetProcAddressARB)(const GLubyte *);
59 typedef struct wine_glcontext {
64 struct wine_glcontext *next;
65 struct wine_glcontext *prev;
67 static Wine_GLContext *context_list;
69 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
72 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
76 static inline void free_context(Wine_GLContext *context)
78 if (context->next != NULL) context->next->prev = context->prev;
79 if (context->prev != NULL) context->prev->next = context->next;
80 else context_list = context->next;
82 HeapFree(GetProcessHeap(), 0, context);
85 static inline Wine_GLContext *alloc_context(void)
89 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
91 ret->next = context_list;
92 if (context_list) context_list->prev = ret;
98 inline static BOOL is_valid_context( Wine_GLContext *ctx )
101 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
102 return (ptr != NULL);
105 /* retrieve the X display to use on a given DC */
106 inline static Display *get_display( HDC hdc )
109 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
111 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
112 sizeof(display), (LPSTR)&display )) display = NULL;
117 /* retrieve the X drawable to use on a given DC */
118 inline static Drawable get_drawable( HDC hdc )
121 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
123 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
124 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
129 /* retrieve the X drawable to use on a given DC */
130 inline static Font get_font( HDC hdc )
133 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
135 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
136 sizeof(font), (LPSTR)&font )) font = 0;
141 /***********************************************************************
142 * wglCreateContext (OPENGL32.@)
144 HGLRC WINAPI wglCreateContext(HDC hdc)
149 XVisualInfo template;
150 Display *display = get_display( hdc );
152 TRACE("(%p)\n", hdc);
154 /* First, get the visual in use by the X11DRV */
155 if (!display) return 0;
156 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
157 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
160 ERR("NULL visual !!!\n");
161 /* Need to set errors here */
165 /* The context will be allocated in the wglMakeCurrent call */
167 ret = alloc_context();
170 ret->display = display;
173 TRACE(" creating context %p (GL context creation delayed)\n", ret);
177 /***********************************************************************
178 * wglCreateLayerContext (OPENGL32.@)
180 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
182 TRACE("(%p,%d)\n", hdc, iLayerPlane);
184 if (iLayerPlane == 0) {
185 return wglCreateContext(hdc);
187 FIXME(" no handler for layer %d\n", iLayerPlane);
192 /***********************************************************************
193 * wglCopyContext (OPENGL32.@)
195 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
198 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
203 /***********************************************************************
204 * wglDeleteContext (OPENGL32.@)
206 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
208 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
211 TRACE("(%p)\n", hglrc);
214 /* A game (Half Life not to name it) deletes twice the same context,
215 * so make sure it is valid first */
216 if (is_valid_context( ctx ))
218 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
223 WARN("Error deleting context !\n");
224 SetLastError(ERROR_INVALID_HANDLE);
232 /***********************************************************************
233 * wglDescribeLayerPlane (OPENGL32.@)
235 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
239 LPLAYERPLANEDESCRIPTOR plpd) {
240 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
245 /***********************************************************************
246 * wglGetCurrentContext (OPENGL32.@)
248 HGLRC WINAPI wglGetCurrentContext(void) {
255 gl_ctx = glXGetCurrentContext();
256 ret = get_context_from_GLXContext(gl_ctx);
259 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
264 /***********************************************************************
265 * wglGetCurrentDC (OPENGL32.@)
267 HDC WINAPI wglGetCurrentDC(void) {
274 gl_ctx = glXGetCurrentContext();
275 ret = get_context_from_GLXContext(gl_ctx);
279 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
282 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
287 /***********************************************************************
288 * wglGetLayerPaletteEntries (OPENGL32.@)
290 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
294 const COLORREF *pcr) {
295 FIXME("(): stub !\n");
300 /***********************************************************************
301 * wglGetProcAddress (OPENGL32.@)
303 static int compar(const void *elt_a, const void *elt_b) {
304 return strcmp(((OpenGL_extension *) elt_a)->name,
305 ((OpenGL_extension *) elt_b)->name);
308 static int wgl_compar(const void *elt_a, const void *elt_b) {
309 return strcmp(((WGL_extension *) elt_a)->func_name,
310 ((WGL_extension *) elt_b)->func_name);
313 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
315 OpenGL_extension ext;
316 OpenGL_extension *ext_ret;
318 TRACE("(%s)\n", lpszProc);
320 /* First, look if it's not already defined in the 'standard' OpenGL functions */
321 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
322 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
326 if (p_glXGetProcAddressARB == NULL) {
327 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
331 /* After that, search in the thunks to find the real name of the extension */
332 ext.name = (char *) lpszProc;
333 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
334 extension_registry_size, sizeof(OpenGL_extension), compar);
336 if (ext_ret == NULL) {
337 WGL_extension wgl_ext, *wgl_ext_ret;
339 /* Try to find the function in the WGL extensions ... */
340 wgl_ext.func_name = (char *) lpszProc;
341 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
342 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
344 if (wgl_ext_ret == NULL) {
345 /* Some sanity checks :-) */
347 local_func = p_glXGetProcAddressARB(lpszProc);
349 if (local_func != NULL) {
350 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
354 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
359 if (wgl_ext_ret->func_init != NULL) {
361 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
362 wgl_ext_ret->context)) == NULL) {
363 ret = wgl_ext_ret->func_address;
365 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
369 ret = wgl_ext_ret->func_address;
373 TRACE(" returning WGL function (%p)\n", ret);
378 local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
381 /* After that, look at the extensions defined in the Linux OpenGL library */
382 if (local_func == NULL) {
386 /* Remove the 3 last letters (EXT, ARB, ...).
388 I know that some extensions have more than 3 letters (MESA, NV,
389 INTEL, ...), but this is only a stop-gap measure to fix buggy
390 OpenGL drivers (moreover, it is only useful for old 1.0 apps
391 that query the glBindTextureEXT extension).
393 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
394 buf[strlen(ext_ret->glx_name) - 3] = '\0';
395 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
397 ret = GetProcAddress(opengl32_handle, buf);
399 TRACE(" found function in main OpenGL library (%p) !\n", ret);
401 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
406 TRACE(" returning function (%p)\n", ext_ret->func);
407 *(ext_ret->func_ptr) = local_func;
409 return ext_ret->func;
414 /***********************************************************************
415 * wglMakeCurrent (OPENGL32.@)
417 BOOL WINAPI wglMakeCurrent(HDC hdc,
421 TRACE("(%p,%p)\n", hdc, hglrc);
425 ret = glXMakeCurrent(default_display, None, NULL);
427 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
428 Drawable drawable = get_drawable( hdc );
430 if (ctx->ctx == NULL) {
431 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
432 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
434 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
437 TRACE(" returning %s\n", (ret ? "True" : "False"));
441 /***********************************************************************
442 * wglRealizeLayerPalette (OPENGL32.@)
444 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
452 /***********************************************************************
453 * wglSetLayerPaletteEntries (OPENGL32.@)
455 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
459 const COLORREF *pcr) {
460 FIXME("(): stub !\n");
465 /***********************************************************************
466 * wglShareLists (OPENGL32.@)
468 BOOL WINAPI wglShareLists(HGLRC hglrc1,
470 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
471 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
473 TRACE("(%p, %p)\n", org, dest);
475 if (dest->ctx != NULL) {
476 ERR("Could not share display lists, context already created !\n");
479 if (org->ctx == NULL) {
481 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
483 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
487 /* Create the destination context with display lists shared */
488 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
490 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
496 /***********************************************************************
497 * wglSwapLayerBuffers (OPENGL32.@)
499 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
501 TRACE("(%p, %08x)\n", hdc, fuPlanes);
503 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
504 if (!SwapBuffers(hdc)) return FALSE;
505 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
509 WARN("Following layers unhandled : %08x\n", fuPlanes);
515 static BOOL internal_wglUseFontBitmaps(HDC hdc,
519 DWORD WINAPI (*GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
521 /* We are running using client-side rendering fonts... */
523 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
526 void *bitmap = NULL, *gl_bitmap = NULL;
530 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
531 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
534 for (glyph = first; glyph < first + count; glyph++) {
535 int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
536 int height, width_int;
538 if (needed_size == GDI_ERROR) goto error;
539 if (needed_size > size) {
541 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
542 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
543 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
544 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
546 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
547 if (TRACE_ON(opengl)) {
548 unsigned int height, width, bitmask;
549 unsigned char *bitmap_ = (unsigned char *) bitmap;
551 DPRINTF("Glyph : %d\n", glyph);
552 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
553 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
554 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
555 DPRINTF(" - size : %d\n", needed_size);
556 DPRINTF(" - bitmap : \n");
557 for (height = 0; height < gm.gmBlackBoxY; height++) {
559 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
564 if (*bitmap_ & bitmask)
569 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
574 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
575 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
576 width_int = (gm.gmBlackBoxX + 31) / 32;
577 for (height = 0; height < gm.gmBlackBoxY; height++) {
579 for (width = 0; width < width_int; width++) {
580 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
581 ((int *) bitmap)[height * width_int + width];
586 glNewList(listBase++, GL_COMPILE);
587 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x,
588 gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
594 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
597 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
598 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
603 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
606 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
607 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
611 /***********************************************************************
612 * wglUseFontBitmapsA (OPENGL32.@)
614 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
619 Font fid = get_font( hdc );
621 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
624 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
628 /* I assume that the glyphs are at the same position for X and for Windows */
629 glXUseXFont(fid, first, count, listBase);
634 /***********************************************************************
635 * wglUseFontBitmapsW (OPENGL32.@)
637 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
642 Font fid = get_font( hdc );
644 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
647 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
650 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
653 /* I assume that the glyphs are at the same position for X and for Windows */
654 glXUseXFont(fid, first, count, listBase);
659 /***********************************************************************
660 * wglUseFontOutlinesA (OPENGL32.@)
662 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
669 LPGLYPHMETRICSFLOAT lpgmf) {
670 FIXME("(): stub !\n");
675 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
676 include all dependencies
679 #define SONAME_LIBGL "libGL.so"
682 /* This is for brain-dead applications that use OpenGL functions before even
683 creating a rendering context.... */
684 static BOOL process_attach(void)
686 XWindowAttributes win_attr;
689 XVisualInfo template;
691 XVisualInfo *vis = NULL;
692 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
693 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
698 ERR("X11DRV not loaded. Cannot create default context.\n");
702 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
703 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
706 default_display = get_display( hdc );
708 if (!default_display)
710 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
716 /* Try to get the visual from the Root Window. We can't use the standard (presumably
717 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
718 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
719 with mismatched visuals. Note that the Root Window visual may not be double
720 buffered, so apps actually attempting to render this way may flicker */
721 if (XGetWindowAttributes( default_display, root, &win_attr ))
723 rootVisual = win_attr.visual;
727 /* Get the default visual, since we can't seem to get the attributes from the
728 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
729 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
732 template.visualid = XVisualIDFromVisual(rootVisual);
733 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
734 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
735 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
739 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
740 if (opengl_handle != NULL) {
741 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
742 wine_dlclose(opengl_handle, NULL, 0);
743 if (p_glXGetProcAddressARB == NULL)
744 TRACE("could not find glXGetProcAddressARB in libGL.\n");
747 /* Initialize also the list of supported WGL extensions. */
748 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display));
750 if (default_cx == NULL) {
751 ERR("Could not create default context.\n");
757 /**********************************************************************/
759 static void process_detach(void)
761 glXDestroyContext(default_display, default_cx);
763 /* Do not leak memory... */
764 wgl_ext_finalize_extensions();
767 /***********************************************************************
768 * OpenGL initialisation routine
770 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
774 case DLL_PROCESS_ATTACH:
775 opengl32_handle = hinst;
776 DisableThreadLibraryCalls(hinst);
777 return process_attach();
778 case DLL_PROCESS_DETACH: