1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
4 * Copyright (c) 2005 Raphael Junqueira
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
38 #include "opengl_ext.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
50 typedef struct wine_glx_s {
53 GLXFBConfig* (*p_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
54 int (*p_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
55 XVisualInfo* (*p_glXGetVisualFromFBConfig) (Display *dpy, GLXFBConfig config);
57 GLXFBConfig* (*p_glXGetFBConfigs) (Display *dpy, int screen, int *nelements);
58 void (*p_glXQueryDrawable) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
59 Bool (*p_glXMakeContextCurrent) (Display *, GLXDrawable, GLXDrawable, GLXContext);
62 /** global glx object */
63 static wine_glx_t wine_glx;
65 /* x11drv GDI escapes */
66 #define X11DRV_ESCAPE 6789
67 enum x11drv_escape_codes
69 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
70 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
71 X11DRV_GET_FONT, /* get current X font for a DC */
72 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
73 X11DRV_START_EXPOSURES, /* start graphics exposures */
74 X11DRV_END_EXPOSURES, /* end graphics exposures */
75 X11DRV_GET_DCE, /* get the DCE pointer */
76 X11DRV_SET_DCE, /* set the DCE pointer */
77 X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */
78 X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */
81 void (*wine_tsx11_lock_ptr)(void) = NULL;
82 void (*wine_tsx11_unlock_ptr)(void) = NULL;
84 static GLXContext default_cx = NULL;
85 static Display *default_display; /* display to use for default context */
87 static HMODULE opengl32_handle;
89 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
91 static char internal_gl_disabled_extensions[512];
92 static char* internal_gl_extensions = NULL;
94 typedef struct wine_glcontext {
101 struct wine_glcontext *next;
102 struct wine_glcontext *prev;
104 static Wine_GLContext *context_list;
106 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
109 if (!ctx) return NULL;
110 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
116 Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
118 if (curctx && curctx->do_escape)
120 enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
121 ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
124 wine_tsx11_lock_ptr();
128 static inline void free_context(Wine_GLContext *context)
130 if (context->next != NULL) context->next->prev = context->prev;
131 if (context->prev != NULL) context->prev->next = context->next;
132 else context_list = context->next;
134 HeapFree(GetProcessHeap(), 0, context);
137 static inline Wine_GLContext *alloc_context(void)
141 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
143 ret->next = context_list;
144 if (context_list) context_list->prev = ret;
150 inline static BOOL is_valid_context( Wine_GLContext *ctx )
153 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
154 return (ptr != NULL);
157 /* retrieve the X display to use on a given DC */
158 inline static Display *get_display( HDC hdc )
161 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
163 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
164 sizeof(display), (LPSTR)&display )) display = NULL;
169 /* retrieve the GLX drawable to use on a given DC */
170 inline static Drawable get_drawable( HDC hdc )
172 GLXDrawable drawable;
173 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
175 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
176 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
180 /** for use of wglGetCurrentReadDCARB */
181 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
184 for (ret = context_list; ret; ret = ret->next) {
185 if (d == get_drawable( ret->hdc )) {
192 /* retrieve the X font to use on a given DC */
193 inline static Font get_font( HDC hdc )
196 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
198 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
199 sizeof(font), (LPSTR)&font )) font = 0;
203 /* GLX can advertise dozens of different pixelformats including offscreen and onscreen ones.
204 * In our WGL implementation we only support a subset of these formats namely the format of
205 * Wine's main visual and offscreen formats (if they are available).
206 * This function converts a WGL format to its corresponding GLX one. It returns the index (zero-based)
207 * into the GLX FB config table and it returns the number of supported WGL formats in fmt_count.
209 BOOL ConvertPixelFormatWGLtoGLX(Display *display, int iPixelFormat, int *fmt_index, int *fmt_count)
213 GLXFBConfig* cfgs = NULL;
217 int nFormats = 1; /* Start at 1 as we allways have a main visual */
218 VisualID visualid = 0;
220 /* Request to look up the format of the main visual when iPixelFormat = 1 */
221 if(iPixelFormat == 1) visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
223 /* As mentioned in various parts of the code only the format of the main visual can be used for onscreen rendering.
224 * Next to this format there are also so called offscreen rendering formats (used for pbuffers) which can be supported
225 * because they don't need a visual. Below we use glXGetFBConfigs instead of glXChooseFBConfig to enumerate the fb configurations
226 * bas this call lists both types of formats instead of only onscreen ones. */
227 cfgs = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs);
228 if (NULL == cfgs || 0 == nCfgs) {
229 ERR("glXChooseFBConfig returns NULL\n");
230 if(cfgs != NULL) XFree(cfgs);
234 /* Find the requested offscreen format and count the number of offscreen formats */
235 for(i=0; i<nCfgs; i++) {
236 wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &tmp_vis_id);
237 wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_FBCONFIG_ID, &tmp_fmt_id);
239 /* We are looking up the GLX index of our main visual and have found it :) */
240 if(iPixelFormat == 1 && visualid == tmp_vis_id) {
242 TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", tmp_fmt_id, *fmt_index, tmp_vis_id);
245 /* We found an offscreen rendering format :) */
246 else if(tmp_vis_id == 0) {
248 TRACE("Checking offscreen format FBCONFIG_ID 0x%x at index %d\n", tmp_fmt_id, i);
250 if(iPixelFormat == nFormats) {
252 TRACE("Found offscreen format FBCONFIG_ID 0x%x corresponding to iPixelFormat %d at GLX index %d\n", tmp_fmt_id, iPixelFormat, i);
257 *fmt_count = nFormats;
258 TRACE("Number of offscreen formats: %d; returning index: %d\n", *fmt_count, *fmt_index);
260 if(cfgs != NULL) XFree(cfgs);
265 /***********************************************************************
266 * wglCreateContext (OPENGL32.@)
268 HGLRC WINAPI wglCreateContext(HDC hdc)
271 Display *display = get_display( hdc );
272 int hdcPF = 1; /* We can only use the Wine's main visual which has an index of 1 */
277 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
279 /* First, get the visual in use by the X11DRV */
280 if (!display) return 0;
282 /* We can only render using the iPixelFormat (1) of Wine's Main visual, we need to get the correspondig GLX format.
283 * If this fails something is very wrong on the system. */
284 if(!ConvertPixelFormatWGLtoGLX(display, hdcPF, &tmp, &fmt_index)) {
285 ERR("Cannot get FB Config for main iPixelFormat 1, expect problems!\n");
286 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
292 GLXFBConfig* cfgs_fmt = NULL;
295 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
296 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
297 ERR("Cannot get FB Configs, expect problems.\n");
298 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
301 if (nCfgs_fmt < fmt_index) {
302 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, fmt_index, nCfgs_fmt);
303 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
306 cur_cfg = cfgs_fmt[fmt_index];
307 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
309 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
310 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
316 /* The context will be allocated in the wglMakeCurrent call */
318 ret = alloc_context();
321 ret->display = display;
322 ret->fb_conf = cur_cfg;
324 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
326 TRACE(" creating context %p (GL context creation delayed)\n", ret);
330 /***********************************************************************
331 * wglCreateLayerContext (OPENGL32.@)
333 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
335 TRACE("(%p,%d)\n", hdc, iLayerPlane);
337 if (iLayerPlane == 0) {
338 return wglCreateContext(hdc);
340 FIXME(" no handler for layer %d\n", iLayerPlane);
345 /***********************************************************************
346 * wglCopyContext (OPENGL32.@)
348 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
351 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
356 /***********************************************************************
357 * wglDeleteContext (OPENGL32.@)
359 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
361 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
364 TRACE("(%p)\n", hglrc);
367 /* A game (Half Life not to name it) deletes twice the same context,
368 * so make sure it is valid first */
369 if (is_valid_context( ctx ))
371 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
376 WARN("Error deleting context !\n");
377 SetLastError(ERROR_INVALID_HANDLE);
385 /***********************************************************************
386 * wglDescribeLayerPlane (OPENGL32.@)
388 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
392 LPLAYERPLANEDESCRIPTOR plpd) {
393 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
398 /***********************************************************************
399 * wglGetCurrentContext (OPENGL32.@)
401 HGLRC WINAPI wglGetCurrentContext(void) {
408 gl_ctx = glXGetCurrentContext();
409 ret = get_context_from_GLXContext(gl_ctx);
412 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
417 /***********************************************************************
418 * wglGetCurrentDC (OPENGL32.@)
420 HDC WINAPI wglGetCurrentDC(void) {
427 gl_ctx = glXGetCurrentContext();
428 ret = get_context_from_GLXContext(gl_ctx);
432 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
435 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
440 /***********************************************************************
441 * wglGetLayerPaletteEntries (OPENGL32.@)
443 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
447 const COLORREF *pcr) {
448 FIXME("(): stub !\n");
453 /***********************************************************************
454 * wglGetProcAddress (OPENGL32.@)
456 static int compar(const void *elt_a, const void *elt_b) {
457 return strcmp(((const OpenGL_extension *) elt_a)->name,
458 ((const OpenGL_extension *) elt_b)->name);
461 static int wgl_compar(const void *elt_a, const void *elt_b) {
462 return strcmp(((const WGL_extension *) elt_a)->func_name,
463 ((const WGL_extension *) elt_b)->func_name);
466 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
468 OpenGL_extension ext;
469 const OpenGL_extension *ext_ret;
471 TRACE("(%s)\n", lpszProc);
473 /* First, look if it's not already defined in the 'standard' OpenGL functions */
474 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
475 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
479 if (p_glXGetProcAddressARB == NULL) {
480 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
484 /* After that, search in the thunks to find the real name of the extension */
486 ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
487 extension_registry_size, sizeof(OpenGL_extension), compar);
489 if (ext_ret == NULL) {
490 WGL_extension wgl_ext, *wgl_ext_ret;
492 /* Try to find the function in the WGL extensions ... */
493 wgl_ext.func_name = (char *) lpszProc;
494 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
495 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
497 if (wgl_ext_ret == NULL) {
498 /* Some sanity checks :-) */
500 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
502 if (local_func != NULL) {
503 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
507 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
512 if (wgl_ext_ret->func_init != NULL) {
514 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
515 wgl_ext_ret->context)) == NULL) {
516 ret = wgl_ext_ret->func_address;
518 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
522 ret = wgl_ext_ret->func_address;
526 TRACE(" returning WGL function (%p)\n", ret);
530 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
532 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
535 /* After that, look at the extensions defined in the Linux OpenGL library */
536 if (local_func == NULL) {
540 /* Remove the 3 last letters (EXT, ARB, ...).
542 I know that some extensions have more than 3 letters (MESA, NV,
543 INTEL, ...), but this is only a stop-gap measure to fix buggy
544 OpenGL drivers (moreover, it is only useful for old 1.0 apps
545 that query the glBindTextureEXT extension).
547 memcpy(buf, glx_name, strlen(glx_name) - 3);
548 buf[strlen(glx_name) - 3] = '\0';
549 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
551 ret = GetProcAddress(opengl32_handle, buf);
553 TRACE(" found function in main OpenGL library (%p) !\n", ret);
555 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
560 TRACE(" returning function (%p)\n", ext_ret->func);
561 extension_funcs[ext_ret - extension_registry] = local_func;
563 return ext_ret->func;
568 static int describeContext(Wine_GLContext* ctx) {
571 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
572 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
573 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
574 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
575 TRACE(" - VISUAL_ID 0x%x\n", tmp);
580 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
583 int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
586 if (wine_glx.p_glXQueryDrawable == NULL) {
587 /** glXQueryDrawable not available so returns not supported */
591 TRACE(" Drawable %p have :\n", (void*) drawable);
592 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
593 TRACE(" - WIDTH as %d\n", tmp);
594 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
595 TRACE(" - HEIGHT as %d\n", tmp);
596 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
597 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
600 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
601 if (fbCfgs == NULL) {
605 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
606 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
613 /***********************************************************************
614 * wglMakeCurrent (OPENGL32.@)
616 BOOL WINAPI wglMakeCurrent(HDC hdc,
619 DWORD type = GetObjectType(hdc);
621 TRACE("(%p,%p)\n", hdc, hglrc);
625 ret = glXMakeCurrent(default_display, None, NULL);
626 NtCurrentTeb()->glContext = NULL;
628 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
629 Drawable drawable = get_drawable( hdc );
630 if (ctx->ctx == NULL) {
631 int draw_vis_id, ctx_vis_id;
632 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
633 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
634 draw_vis_id = describeDrawable(ctx, drawable);
635 ctx_vis_id = describeContext(ctx);
637 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
639 * Inherits from root window so reuse desktop visual
641 XVisualInfo template;
644 template.visualid = visualid;
645 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
647 TRACE(" Creating GLX Context\n");
648 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
650 TRACE(" Creating GLX Context\n");
651 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
653 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
655 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
656 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
657 NtCurrentTeb()->glContext = ctx;
658 if(ret && type == OBJ_MEMDC)
660 ctx->do_escape = TRUE;
661 glDrawBuffer(GL_FRONT_LEFT);
665 TRACE(" returning %s\n", (ret ? "True" : "False"));
669 /***********************************************************************
670 * wglMakeContextCurrentARB (OPENGL32.@)
672 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
675 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
679 ret = glXMakeCurrent(default_display, None, NULL);
681 if (NULL == wine_glx.p_glXMakeContextCurrent) {
684 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
685 Drawable d_draw = get_drawable( hDrawDC );
686 Drawable d_read = get_drawable( hReadDC );
688 if (ctx->ctx == NULL) {
689 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
690 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
692 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
697 TRACE(" returning %s\n", (ret ? "True" : "False"));
701 /***********************************************************************
702 * wglGetCurrentReadDCARB (OPENGL32.@)
704 HDC WINAPI wglGetCurrentReadDCARB(void)
712 gl_d = glXGetCurrentReadDrawable();
713 ret = get_hdc_from_Drawable(gl_d);
716 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
722 /***********************************************************************
723 * wglRealizeLayerPalette (OPENGL32.@)
725 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
733 /***********************************************************************
734 * wglSetLayerPaletteEntries (OPENGL32.@)
736 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
740 const COLORREF *pcr) {
741 FIXME("(): stub !\n");
746 /***********************************************************************
747 * wglShareLists (OPENGL32.@)
749 BOOL WINAPI wglShareLists(HGLRC hglrc1,
751 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
752 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
754 TRACE("(%p, %p)\n", org, dest);
756 if (NULL != dest && dest->ctx != NULL) {
757 ERR("Could not share display lists, context already created !\n");
760 if (org->ctx == NULL) {
762 describeContext(org);
763 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
765 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
769 describeContext(dest);
770 /* Create the destination context with display lists shared */
771 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
773 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
780 /***********************************************************************
781 * wglSwapLayerBuffers (OPENGL32.@)
783 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
785 TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
787 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
788 if (!SwapBuffers(hdc)) return FALSE;
789 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
793 WARN("Following layers unhandled : %08x\n", fuPlanes);
799 static BOOL internal_wglUseFontBitmaps(HDC hdc,
803 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
805 /* We are running using client-side rendering fonts... */
809 void *bitmap = NULL, *gl_bitmap = NULL;
813 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
814 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
817 for (glyph = first; glyph < first + count; glyph++) {
818 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
819 int height, width_int;
821 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
822 if (needed_size == GDI_ERROR) {
823 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
826 TRACE(" - needed size : %d\n", needed_size);
829 if (needed_size > size) {
831 HeapFree(GetProcessHeap(), 0, bitmap);
832 HeapFree(GetProcessHeap(), 0, gl_bitmap);
833 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
834 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
836 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
837 if (TRACE_ON(opengl)) {
838 unsigned int height, width, bitmask;
839 unsigned char *bitmap_ = (unsigned char *) bitmap;
841 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
842 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
843 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
844 if (needed_size != 0) {
845 TRACE(" - bitmap :\n");
846 for (height = 0; height < gm.gmBlackBoxY; height++) {
848 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
853 if (*bitmap_ & bitmask)
858 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
864 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
865 * glyph for it to be drawn properly.
867 if (needed_size != 0) {
868 width_int = (gm.gmBlackBoxX + 31) / 32;
869 for (height = 0; height < gm.gmBlackBoxY; height++) {
871 for (width = 0; width < width_int; width++) {
872 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
873 ((int *) bitmap)[height * width_int + width];
879 glNewList(listBase++, GL_COMPILE);
880 if (needed_size != 0) {
881 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
882 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
883 gm.gmCellIncX, gm.gmCellIncY,
886 /* This is the case of 'empty' glyphs like the space character */
887 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
894 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
897 HeapFree(GetProcessHeap(), 0, bitmap);
898 HeapFree(GetProcessHeap(), 0, gl_bitmap);
903 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
906 HeapFree(GetProcessHeap(), 0, bitmap);
907 HeapFree(GetProcessHeap(), 0, gl_bitmap);
911 /***********************************************************************
912 * wglUseFontBitmapsA (OPENGL32.@)
914 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
919 Font fid = get_font( hdc );
921 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
924 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
928 /* I assume that the glyphs are at the same position for X and for Windows */
929 glXUseXFont(fid, first, count, listBase);
934 /***********************************************************************
935 * wglUseFontBitmapsW (OPENGL32.@)
937 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
942 Font fid = get_font( hdc );
944 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
947 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
950 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
953 /* I assume that the glyphs are at the same position for X and for Windows */
954 glXUseXFont(fid, first, count, listBase);
961 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
963 vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
964 vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
968 static void tess_callback_vertex(GLvoid *vertex)
970 GLdouble *dbl = vertex;
971 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
975 static void tess_callback_begin(GLenum which)
977 TRACE("%d\n", which);
981 static void tess_callback_end(void)
987 /***********************************************************************
988 * wglUseFontOutlines_common
990 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
997 LPGLYPHMETRICSFLOAT lpgmf,
1001 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
1002 GLUtesselator *tess;
1004 HFONT old_font, unscaled_font;
1005 UINT em_size = 1024;
1008 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
1009 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
1013 tess = gluNewTess();
1016 gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
1017 gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
1018 gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
1022 if(!tess) return FALSE;
1024 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1025 rc.left = rc.right = rc.bottom = 0;
1027 DPtoLP(hdc, (POINT*)&rc, 2);
1028 lf.lfHeight = -abs(rc.top - rc.bottom);
1029 lf.lfOrientation = lf.lfEscapement = 0;
1030 unscaled_font = CreateFontIndirectW(&lf);
1031 old_font = SelectObject(hdc, unscaled_font);
1033 for (glyph = first; glyph < first + count; glyph++)
1038 TTPOLYGONHEADER *pph;
1043 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1045 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1047 if(needed == GDI_ERROR)
1050 buf = HeapAlloc(GetProcessHeap(), 0, needed);
1051 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
1054 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1056 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1058 TRACE("glyph %d\n", glyph);
1062 lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
1063 lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
1064 lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
1065 lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
1066 lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
1067 lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
1069 TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
1070 lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
1075 glNewList(listBase++, GL_COMPILE);
1076 gluTessBeginPolygon(tess, NULL);
1078 pph = (TTPOLYGONHEADER*)buf;
1079 while((BYTE*)pph < buf + needed)
1081 TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
1083 gluTessBeginContour(tess);
1085 fixed_to_double(pph->pfxStart, em_size, vertices);
1086 gluTessVertex(tess, vertices, vertices);
1089 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1090 while((char*)ppc < (char*)pph + pph->cb)
1094 switch(ppc->wType) {
1096 for(i = 0; i < ppc->cpfx; i++)
1098 TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1099 fixed_to_double(ppc->apfx[i], em_size, vertices);
1100 gluTessVertex(tess, vertices, vertices);
1105 case TT_PRIM_QSPLINE:
1106 for(i = 0; i < ppc->cpfx/2; i++)
1108 /* FIXME just connecting the control points for now */
1109 TRACE("\t\tcurve %d,%d %d,%d\n",
1110 ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
1111 ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1112 fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
1113 gluTessVertex(tess, vertices, vertices);
1115 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1116 gluTessVertex(tess, vertices, vertices);
1121 ERR("\t\tcurve type = %d\n", ppc->wType);
1122 gluTessEndContour(tess);
1126 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1127 (ppc->cpfx - 1) * sizeof(POINTFX));
1129 gluTessEndContour(tess);
1130 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1134 gluTessEndPolygon(tess);
1135 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
1138 HeapFree(GetProcessHeap(), 0, buf);
1139 HeapFree(GetProcessHeap(), 0, vertices);
1143 DeleteObject(SelectObject(hdc, old_font));
1144 gluDeleteTess(tess);
1149 #else /* HAVE_GL_GLU_H */
1151 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1158 LPGLYPHMETRICSFLOAT lpgmf,
1161 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1165 #endif /* HAVE_GL_GLU_H */
1167 /***********************************************************************
1168 * wglUseFontOutlinesA (OPENGL32.@)
1170 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1177 LPGLYPHMETRICSFLOAT lpgmf)
1179 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1182 /***********************************************************************
1183 * wglUseFontOutlinesW (OPENGL32.@)
1185 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1192 LPGLYPHMETRICSFLOAT lpgmf)
1194 return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1197 const GLubyte * internal_glGetString(GLenum name) {
1198 const char* GL_Extensions = NULL;
1200 if (GL_EXTENSIONS != name) {
1201 return glGetString(name);
1204 if (NULL == internal_gl_extensions) {
1205 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1207 TRACE("GL_EXTENSIONS reported:\n");
1208 if (NULL == GL_Extensions) {
1209 ERR("GL_EXTENSIONS returns NULL\n");
1212 size_t len = strlen(GL_Extensions);
1213 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1215 while (*GL_Extensions != 0x00) {
1216 const char* Start = GL_Extensions;
1219 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1220 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1223 memcpy(ThisExtn, Start, (GL_Extensions - Start));
1224 TRACE("- %s:", ThisExtn);
1226 /* test if supported API is disabled by config */
1227 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1228 strcat(internal_gl_extensions, " ");
1229 strcat(internal_gl_extensions, ThisExtn);
1232 TRACE(" deactived (by config)\n");
1235 if (*GL_Extensions == ' ') GL_Extensions++;
1239 return (const GLubyte *) internal_gl_extensions;
1242 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1243 glGetIntegerv(pname, params);
1244 if (pname == GL_DEPTH_BITS) {
1245 GLXContext gl_ctx = glXGetCurrentContext();
1246 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1247 /*TRACE("returns Wine Ctx as %p\n", ret);*/
1249 * if we cannot find a Wine Context
1250 * we only have the default wine desktop context,
1251 * so if we have only a 24 depth say we have 32
1253 if (NULL == ret && 24 == *params) {
1256 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1258 if (pname == GL_ALPHA_BITS) {
1260 GLXContext gl_ctx = glXGetCurrentContext();
1261 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1262 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1263 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1269 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1270 include all dependencies
1272 #ifndef SONAME_LIBGL
1273 #define SONAME_LIBGL "libGL.so"
1276 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
1278 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1279 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1280 const char *glx_extensions = NULL;
1281 BOOL glx_direct = glXIsDirect(display, default_cx);
1283 memset(&wine_glx, 0, sizeof(wine_glx));
1285 /* In case of GLX you have direct and indirect rendering. Most of the time direct rendering is used
1286 * as in general only that is hardware accelerated. In some cases like in case of remote X indirect
1287 * rendering is used.
1289 * The main problem for our OpenGL code is that we need certain GLX calls but their presence
1290 * depends on the reported GLX client / server version and on the client / server extension list.
1291 * Those don't have to be the same.
1293 * In general the server GLX information should be used in case of indirect rendering. When direct
1294 * rendering is used, the OpenGL client library is responsible for which GLX calls are available.
1295 * Nvidia's OpenGL drivers are the best in terms of GLX features. At the moment of writing their
1296 * 8762 drivers support 1.3 for the server and 1.4 for the client and they support lots of extensions.
1297 * Unfortunately it is much more complicated for Mesa/DRI-based drivers and ATI's drivers.
1298 * Both sets of drivers report a server version of 1.2 and the client version can be 1.3 or 1.4.
1299 * Further in case of atleast ATI's drivers one crucial extension needed for our pixel format code
1300 * is only available in the list of server extensions and not in the client list.
1302 * The versioning checks below try to take into account the comments from above.
1305 TRACE("Server GLX version: %s\n", server_glx_version);
1306 TRACE("Client GLX version: %s\n", client_glx_version);
1307 TRACE("Direct rendering eanbled: %s\n", glx_direct ? "True" : "False");
1309 /* Based on the default opengl context we decide whether direct or indirect rendering is used.
1310 * In case of indirect rendering we check if the GLX version of the server is 1.2 and else
1311 * the client version is checked.
1313 if ( (!glx_direct && !strcmp("1.2", server_glx_version)) || (glx_direct && !strcmp("1.2", client_glx_version)) ) {
1314 wine_glx.version = 2;
1316 wine_glx.version = 3;
1319 /* Depending on the use of direct or indirect rendering we need either the list of extensions
1320 * exported by the client or by the server.
1323 glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1325 glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1327 if (2 < wine_glx.version) {
1328 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1329 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1330 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1332 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1334 if (NULL != strstr(glx_extensions, "GLX_SGIX_fbconfig")) {
1335 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1336 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1337 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1339 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", client_glx_version);
1343 /* The mesa libGL client library seems to forward glXQueryDrawable to the Xserver, so only
1344 * enable this function when the Xserver understand GLX 1.3 or newer
1346 if (!strcmp("1.2", server_glx_version))
1347 wine_glx.p_glXQueryDrawable = NULL;
1349 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1351 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1352 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1353 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1356 /* This is for brain-dead applications that use OpenGL functions before even
1357 creating a rendering context.... */
1358 static BOOL process_attach(void)
1360 XWindowAttributes win_attr;
1363 XVisualInfo template;
1365 XVisualInfo *vis = NULL;
1366 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1367 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1368 void *opengl_handle;
1369 DWORD size = sizeof(internal_gl_disabled_extensions);
1374 ERR("X11DRV not loaded. Cannot create default context.\n");
1378 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1379 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1382 default_display = get_display( hdc );
1383 ReleaseDC( 0, hdc );
1384 if (!default_display)
1386 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1392 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1393 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1394 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1395 with mismatched visuals. Note that the Root Window visual may not be double
1396 buffered, so apps actually attempting to render this way may flicker */
1397 if (XGetWindowAttributes( default_display, root, &win_attr ))
1399 rootVisual = win_attr.visual;
1403 /* Get the default visual, since we can't seem to get the attributes from the
1404 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1405 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1408 template.visualid = XVisualIDFromVisual(rootVisual);
1409 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1410 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1411 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1415 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1416 if (opengl_handle != NULL) {
1417 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1418 wine_dlclose(opengl_handle, NULL, 0);
1419 if (p_glXGetProcAddressARB == NULL)
1420 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1423 internal_gl_disabled_extensions[0] = 0;
1424 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1425 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1426 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1431 if (default_cx == NULL) {
1432 ERR("Could not create default context.\n");
1436 /* After context initialize also the list of supported WGL extensions. */
1437 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1438 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1444 /**********************************************************************/
1446 static void process_detach(void)
1448 glXDestroyContext(default_display, default_cx);
1450 /* Do not leak memory... */
1451 wgl_ext_finalize_extensions();
1452 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1455 /***********************************************************************
1456 * OpenGL initialisation routine
1458 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1462 case DLL_PROCESS_ATTACH:
1463 opengl32_handle = hinst;
1464 DisableThreadLibraryCalls(hinst);
1465 return process_attach();
1466 case DLL_PROCESS_DETACH: