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"
34 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
36 /* x11drv GDI escapes */
37 #define X11DRV_ESCAPE 6789
38 enum x11drv_escape_codes
40 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
41 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
42 X11DRV_GET_FONT, /* get current X font for a DC */
45 void (*wine_tsx11_lock_ptr)(void) = NULL;
46 void (*wine_tsx11_unlock_ptr)(void) = NULL;
48 static GLXContext default_cx = NULL;
49 static Display *default_display; /* display to use for default context */
51 typedef struct wine_glcontext {
56 struct wine_glcontext *next;
57 struct wine_glcontext *prev;
59 static Wine_GLContext *context_list;
61 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
64 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
68 static inline void free_context(Wine_GLContext *context)
70 if (context->next != NULL) context->next->prev = context->prev;
71 if (context->prev != NULL) context->prev->next = context->next;
72 else context_list = context->next;
74 HeapFree(GetProcessHeap(), 0, context);
77 static inline Wine_GLContext *alloc_context(void)
81 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
83 ret->next = context_list;
84 if (context_list) context_list->prev = ret;
90 inline static BOOL is_valid_context( Wine_GLContext *ctx )
93 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
97 /* retrieve the X display to use on a given DC */
98 inline static Display *get_display( HDC hdc )
101 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
103 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
104 sizeof(display), (LPSTR)&display )) display = NULL;
109 /* retrieve the X drawable to use on a given DC */
110 inline static Drawable get_drawable( HDC hdc )
113 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
115 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
116 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
121 /* retrieve the X drawable to use on a given DC */
122 inline static Font get_font( HDC hdc )
125 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
127 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
128 sizeof(font), (LPSTR)&font )) font = 0;
133 /***********************************************************************
134 * wglCreateContext (OPENGL32.@)
136 HGLRC WINAPI wglCreateContext(HDC hdc)
141 XVisualInfo template;
142 Display *display = get_display( hdc );
144 TRACE("(%p)\n", hdc);
146 /* First, get the visual in use by the X11DRV */
147 if (!display) return 0;
148 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
149 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
152 ERR("NULL visual !!!\n");
153 /* Need to set errors here */
157 /* The context will be allocated in the wglMakeCurrent call */
159 ret = alloc_context();
162 ret->display = display;
165 TRACE(" creating context %p (GL context creation delayed)\n", ret);
169 /***********************************************************************
170 * wglCreateLayerContext (OPENGL32.@)
172 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
174 TRACE("(%p,%d)\n", hdc, iLayerPlane);
176 if (iLayerPlane == 0) {
177 return wglCreateContext(hdc);
179 FIXME(" no handler for layer %d\n", iLayerPlane);
184 /***********************************************************************
185 * wglCopyContext (OPENGL32.@)
187 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
190 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
195 /***********************************************************************
196 * wglDeleteContext (OPENGL32.@)
198 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
200 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
203 TRACE("(%p)\n", hglrc);
206 /* A game (Half Life not to name it) deletes twice the same context,
207 * so make sure it is valid first */
208 if (is_valid_context( ctx ))
210 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
215 WARN("Error deleting context !\n");
216 SetLastError(ERROR_INVALID_HANDLE);
224 /***********************************************************************
225 * wglDescribeLayerPlane (OPENGL32.@)
227 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
231 LPLAYERPLANEDESCRIPTOR plpd) {
232 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
237 /***********************************************************************
238 * wglGetCurrentContext (OPENGL32.@)
240 HGLRC WINAPI wglGetCurrentContext(void) {
247 gl_ctx = glXGetCurrentContext();
248 ret = get_context_from_GLXContext(gl_ctx);
251 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
256 /***********************************************************************
257 * wglGetCurrentDC (OPENGL32.@)
259 HDC WINAPI wglGetCurrentDC(void) {
266 gl_ctx = glXGetCurrentContext();
267 ret = get_context_from_GLXContext(gl_ctx);
271 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
274 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
279 /***********************************************************************
280 * wglGetLayerPaletteEntries (OPENGL32.@)
282 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
286 const COLORREF *pcr) {
287 FIXME("(): stub !\n");
292 /***********************************************************************
293 * wglGetProcAddress (OPENGL32.@)
295 static int compar(const void *elt_a, const void *elt_b) {
296 return strcmp(((OpenGL_extension *) elt_a)->name,
297 ((OpenGL_extension *) elt_b)->name);
300 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
302 static HMODULE hm = 0;
303 OpenGL_extension ext;
304 OpenGL_extension *ext_ret;
307 TRACE("(%s)\n", lpszProc);
310 hm = GetModuleHandleA("opengl32");
312 /* First, look if it's not already defined in the 'standard' OpenGL functions */
313 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
314 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
318 /* After that, search in the thunks to find the real name of the extension */
319 ext.name = (char *) lpszProc;
320 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
321 extension_registry_size, sizeof(OpenGL_extension), compar);
323 if (ext_ret == NULL) {
324 /* Some sanity checks :-) */
325 if (glXGetProcAddressARB(lpszProc) != NULL) {
326 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
330 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
333 /* After that, look at the extensions defined in the Linux OpenGL library */
334 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
338 /* Remove the 3 last letters (EXT, ARB, ...).
340 I know that some extensions have more than 3 letters (MESA, NV,
341 INTEL, ...), but this is only a stop-gap measure to fix buggy
342 OpenGL drivers (moreover, it is only useful for old 1.0 apps
343 that query the glBindTextureEXT extension).
345 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
346 buf[strlen(ext_ret->glx_name) - 3] = '\0';
347 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
349 ret = GetProcAddress(hm, buf);
351 TRACE(" found function in main OpenGL library (%p) !\n", ret);
353 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
358 TRACE(" returning function (%p)\n", ext_ret->func);
359 *(ext_ret->func_ptr) = local_func;
361 return ext_ret->func;
366 /***********************************************************************
367 * wglMakeCurrent (OPENGL32.@)
369 BOOL WINAPI wglMakeCurrent(HDC hdc,
373 TRACE("(%p,%p)\n", hdc, hglrc);
377 ret = glXMakeCurrent(default_display, None, NULL);
379 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
380 Drawable drawable = get_drawable( hdc );
382 if (ctx->ctx == NULL) {
383 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
384 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
386 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
389 TRACE(" returning %s\n", (ret ? "True" : "False"));
393 /***********************************************************************
394 * wglRealizeLayerPalette (OPENGL32.@)
396 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
404 /***********************************************************************
405 * wglSetLayerPaletteEntries (OPENGL32.@)
407 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
411 const COLORREF *pcr) {
412 FIXME("(): stub !\n");
417 /***********************************************************************
418 * wglShareLists (OPENGL32.@)
420 BOOL WINAPI wglShareLists(HGLRC hglrc1,
422 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
423 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
425 TRACE("(%p, %p)\n", org, dest);
427 if (dest->ctx != NULL) {
428 ERR("Could not share display lists, context already created !\n");
431 if (org->ctx == NULL) {
433 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
435 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
439 /* Create the destination context with display lists shared */
440 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
442 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
448 /***********************************************************************
449 * wglSwapLayerBuffers (OPENGL32.@)
451 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
453 TRACE("(%p, %08x)\n", hdc, fuPlanes);
455 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
456 if (!SwapBuffers(hdc)) return FALSE;
457 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
461 WARN("Following layers unhandled : %08x\n", fuPlanes);
467 /***********************************************************************
468 * wglUseFontBitmapsA (OPENGL32.@)
470 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
475 Font fid = get_font( hdc );
477 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
480 /* We are running using client-side rendering fonts... */
482 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
485 void *bitmap = NULL, *gl_bitmap = NULL;
489 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
490 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
493 for (glyph = first; glyph < first + count; glyph++) {
494 int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
495 int height, width_int;
497 if (needed_size == GDI_ERROR) goto error;
498 if (needed_size > size) {
500 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
501 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
502 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
503 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
505 if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
506 if (TRACE_ON(opengl)) {
507 unsigned int height, width, bitmask;
508 unsigned char *bitmap_ = (unsigned char *) bitmap;
510 DPRINTF("Glyph : %d\n", glyph);
511 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
512 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
513 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
514 DPRINTF(" - size : %d\n", needed_size);
515 DPRINTF(" - bitmap : \n");
516 for (height = 0; height < gm.gmBlackBoxY; height++) {
518 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
523 if (*bitmap_ & bitmask)
528 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
533 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
534 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
535 width_int = (gm.gmBlackBoxX + 31) / 32;
536 for (height = 0; height < gm.gmBlackBoxY; height++) {
538 for (width = 0; width < width_int; width++) {
539 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
540 ((int *) bitmap)[height * width_int + width];
545 glNewList(listBase++, GL_COMPILE);
546 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
552 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
555 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
556 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
561 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
564 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
565 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
570 /* I assume that the glyphs are at the same position for X and for Windows */
571 glXUseXFont(fid, first, count, listBase);
576 /***********************************************************************
577 * wglUseFontOutlinesA (OPENGL32.@)
579 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
586 LPGLYPHMETRICSFLOAT lpgmf) {
587 FIXME("(): stub !\n");
593 /* This is for brain-dead applications that use OpenGL functions before even
594 creating a rendering context.... */
595 static BOOL process_attach(void)
597 XWindowAttributes win_attr;
600 XVisualInfo template;
602 XVisualInfo *vis = NULL;
603 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
604 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
608 ERR("X11DRV not loaded. Cannot create default context.\n");
612 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
613 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
616 default_display = get_display( hdc );
618 if (!default_display)
620 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
626 /* Try to get the visual from the Root Window. We can't use the standard (presumably
627 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
628 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
629 with mismatched visuals. Note that the Root Window visual may not be double
630 buffered, so apps actually attempting to render this way may flicker */
631 if (XGetWindowAttributes( default_display, root, &win_attr ))
633 rootVisual = win_attr.visual;
637 /* Get the default visual, since we can't seem to get the attributes from the
638 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
639 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
642 template.visualid = XVisualIDFromVisual(rootVisual);
643 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
644 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
645 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
649 if (default_cx == NULL) {
650 ERR("Could not create default context.\n");
655 /* Some WGL extensions... */
656 static const char *WGL_extensions = "WGL_ARB_extensions_string WGL_EXT_extensions_string";
658 const char * WINAPI wglGetExtensionsStringEXT(void) {
659 TRACE("() returning \"%s\"\n", WGL_extensions);
661 return WGL_extensions;
664 static void process_detach(void)
666 glXDestroyContext(default_display, default_cx);
669 /***********************************************************************
670 * wglGetExtensionsStringARB(OPENGL32.@)
672 const char * WINAPI wglGetExtensionsStringARB(HDC hdc) {
674 return wglGetExtensionsStringEXT();
678 /***********************************************************************
679 * OpenGL initialisation routine
681 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
685 case DLL_PROCESS_ATTACH:
686 DisableThreadLibraryCalls(hinst);
687 return process_attach();
688 case DLL_PROCESS_DETACH: