x11drv/opengl: Pixel format rewrite.
[wine/wine64.git] / dlls / opengl32 / wgl.c
blob45f629729e4334a36d4efe81bbd916bf4f9b0d1c
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
37 #include "wgl_ext.h"
38 #include "opengl_ext.h"
39 #ifdef HAVE_GL_GLU_H
40 #undef far
41 #undef near
42 #include <GL/glu.h>
43 #endif
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 {
51 unsigned version;
52 /** SGIX / 1.3 */
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);
56 /** 1.3 */
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);
60 } wine_glx_t;
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 {
95 HDC hdc;
96 Display *display;
97 XVisualInfo *vis;
98 GLXFBConfig fb_conf;
99 GLXContext ctx;
100 BOOL do_escape;
101 struct wine_glcontext *next;
102 struct wine_glcontext *prev;
103 } Wine_GLContext;
104 static Wine_GLContext *context_list;
106 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
108 Wine_GLContext *ret;
109 if (!ctx) return NULL;
110 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
111 return ret;
114 void enter_gl(void)
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();
125 return;
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)
139 Wine_GLContext *ret;
141 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
143 ret->next = context_list;
144 if (context_list) context_list->prev = ret;
145 context_list = ret;
147 return ret;
150 inline static BOOL is_valid_context( Wine_GLContext *ctx )
152 Wine_GLContext *ptr;
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 )
160 Display *display;
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;
165 return display;
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;
177 return drawable;
180 /** for use of wglGetCurrentReadDCARB */
181 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
183 Wine_GLContext *ret;
184 for (ret = context_list; ret; ret = ret->next) {
185 if (d == get_drawable( ret->hdc )) {
186 return ret->hdc;
189 return NULL;
192 /* retrieve the X font to use on a given DC */
193 inline static Font get_font( HDC hdc )
195 Font font;
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;
200 return font;
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)
211 int res = FALSE;
212 int i = 0;
213 GLXFBConfig* cfgs = NULL;
214 int nCfgs = 0;
215 int tmp_fmt_id = 0;
216 int tmp_vis_id = 0;
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);
231 return FALSE;
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) {
241 *fmt_index = i;
242 TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", tmp_fmt_id, *fmt_index, tmp_vis_id);
243 res = TRUE;
245 /* We found an offscreen rendering format :) */
246 else if(tmp_vis_id == 0) {
247 nFormats++;
248 TRACE("Checking offscreen format FBCONFIG_ID 0x%x at index %d\n", tmp_fmt_id, i);
250 if(iPixelFormat == nFormats) {
251 *fmt_index = i;
252 TRACE("Found offscreen format FBCONFIG_ID 0x%x corresponding to iPixelFormat %d at GLX index %d\n", tmp_fmt_id, iPixelFormat, i);
253 res = TRUE;
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);
262 return res;
265 /***********************************************************************
266 * wglCreateContext (OPENGL32.@)
268 HGLRC WINAPI wglCreateContext(HDC hdc)
270 Wine_GLContext *ret;
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 */
273 int tmp = 0;
274 int fmt_index = 0;
275 GLXFBConfig cur_cfg;
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);
287 return NULL;
291 int nCfgs_fmt = 0;
292 GLXFBConfig* cfgs_fmt = NULL;
293 int value;
294 int gl_test = 0;
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);
299 return NULL;
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);
304 return NULL;
306 cur_cfg = cfgs_fmt[fmt_index];
307 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
308 if (gl_test) {
309 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
310 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
311 return NULL;
313 XFree(cfgs_fmt);
316 /* The context will be allocated in the wglMakeCurrent call */
317 ENTER_GL();
318 ret = alloc_context();
319 LEAVE_GL();
320 ret->hdc = hdc;
321 ret->display = display;
322 ret->fb_conf = cur_cfg;
323 /*ret->vis = vis;*/
324 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
326 TRACE(" creating context %p (GL context creation delayed)\n", ret);
327 return (HGLRC) ret;
330 /***********************************************************************
331 * wglCreateLayerContext (OPENGL32.@)
333 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
334 int iLayerPlane) {
335 TRACE("(%p,%d)\n", hdc, iLayerPlane);
337 if (iLayerPlane == 0) {
338 return wglCreateContext(hdc);
340 FIXME(" no handler for layer %d\n", iLayerPlane);
342 return NULL;
345 /***********************************************************************
346 * wglCopyContext (OPENGL32.@)
348 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
349 HGLRC hglrcDst,
350 UINT mask) {
351 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
353 return FALSE;
356 /***********************************************************************
357 * wglDeleteContext (OPENGL32.@)
359 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
361 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
362 BOOL ret = TRUE;
364 TRACE("(%p)\n", hglrc);
366 ENTER_GL();
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);
372 free_context(ctx);
374 else
376 WARN("Error deleting context !\n");
377 SetLastError(ERROR_INVALID_HANDLE);
378 ret = FALSE;
380 LEAVE_GL();
382 return ret;
385 /***********************************************************************
386 * wglDescribeLayerPlane (OPENGL32.@)
388 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
389 int iPixelFormat,
390 int iLayerPlane,
391 UINT nBytes,
392 LPLAYERPLANEDESCRIPTOR plpd) {
393 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
395 return FALSE;
398 /***********************************************************************
399 * wglGetCurrentContext (OPENGL32.@)
401 HGLRC WINAPI wglGetCurrentContext(void) {
402 GLXContext gl_ctx;
403 Wine_GLContext *ret;
405 TRACE("()\n");
407 ENTER_GL();
408 gl_ctx = glXGetCurrentContext();
409 ret = get_context_from_GLXContext(gl_ctx);
410 LEAVE_GL();
412 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
414 return (HGLRC)ret;
417 /***********************************************************************
418 * wglGetCurrentDC (OPENGL32.@)
420 HDC WINAPI wglGetCurrentDC(void) {
421 GLXContext gl_ctx;
422 Wine_GLContext *ret;
424 TRACE("()\n");
426 ENTER_GL();
427 gl_ctx = glXGetCurrentContext();
428 ret = get_context_from_GLXContext(gl_ctx);
429 LEAVE_GL();
431 if (ret) {
432 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
433 return ret->hdc;
434 } else {
435 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
436 return 0;
440 /***********************************************************************
441 * wglGetLayerPaletteEntries (OPENGL32.@)
443 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
444 int iLayerPlane,
445 int iStart,
446 int cEntries,
447 const COLORREF *pcr) {
448 FIXME("(): stub !\n");
450 return 0;
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) {
467 void *local_func;
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);
476 return local_func;
479 if (p_glXGetProcAddressARB == NULL) {
480 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
481 return NULL;
484 /* After that, search in the thunks to find the real name of the extension */
485 ext.name = lpszProc;
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 :-) */
499 ENTER_GL();
500 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
501 LEAVE_GL();
502 if (local_func != NULL) {
503 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
504 return NULL;
507 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
508 return NULL;
509 } else {
510 void *ret = NULL;
512 if (wgl_ext_ret->func_init != NULL) {
513 const char *err_msg;
514 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
515 wgl_ext_ret->context)) == NULL) {
516 ret = wgl_ext_ret->func_address;
517 } else {
518 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
519 return NULL;
521 } else {
522 ret = wgl_ext_ret->func_address;
525 if (ret)
526 TRACE(" returning WGL function (%p)\n", ret);
527 return ret;
529 } else {
530 const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
531 ENTER_GL();
532 local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
533 LEAVE_GL();
535 /* After that, look at the extensions defined in the Linux OpenGL library */
536 if (local_func == NULL) {
537 char buf[256];
538 void *ret = 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);
552 if (ret != NULL) {
553 TRACE(" found function in main OpenGL library (%p) !\n", ret);
554 } else {
555 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
558 return ret;
559 } else {
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) {
569 int tmp;
570 int ctx_vis_id;
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);
576 ctx_vis_id = tmp;
577 return ctx_vis_id;
580 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
581 int tmp;
582 int nElements;
583 int attribList[3] = { GLX_FBCONFIG_ID, 0, None };
584 GLXFBConfig *fbCfgs;
586 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
587 /** glXQueryDrawable not available so returns not supported */
588 return -1;
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);
599 attribList[1] = tmp;
600 fbCfgs = wine_glx.p_glXChooseFBConfig(ctx->display, DefaultScreen(ctx->display), attribList, &nElements);
601 if (fbCfgs == NULL) {
602 return -1;
605 wine_glx.p_glXGetFBConfigAttrib(ctx->display, fbCfgs[0], GLX_VISUAL_ID, &tmp);
606 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
608 XFree(fbCfgs);
610 return tmp;
613 /***********************************************************************
614 * wglMakeCurrent (OPENGL32.@)
616 BOOL WINAPI wglMakeCurrent(HDC hdc,
617 HGLRC hglrc) {
618 BOOL ret;
619 DWORD type = GetObjectType(hdc);
621 TRACE("(%p,%p)\n", hdc, hglrc);
623 ENTER_GL();
624 if (hglrc == NULL) {
625 ret = glXMakeCurrent(default_display, None, NULL);
626 NtCurrentTeb()->glContext = NULL;
627 } else {
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;
642 XVisualInfo *vis;
643 int num;
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);
649 } else {
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);
664 LEAVE_GL();
665 TRACE(" returning %s\n", (ret ? "True" : "False"));
666 return ret;
669 /***********************************************************************
670 * wglMakeContextCurrentARB (OPENGL32.@)
672 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
674 BOOL ret;
675 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
677 ENTER_GL();
678 if (hglrc == NULL) {
679 ret = glXMakeCurrent(default_display, None, NULL);
680 } else {
681 if (NULL == wine_glx.p_glXMakeContextCurrent) {
682 ret = FALSE;
683 } else {
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);
695 LEAVE_GL();
697 TRACE(" returning %s\n", (ret ? "True" : "False"));
698 return ret;
701 /***********************************************************************
702 * wglGetCurrentReadDCARB (OPENGL32.@)
704 HDC WINAPI wglGetCurrentReadDCARB(void)
706 GLXDrawable gl_d;
707 HDC ret;
709 TRACE("()\n");
711 ENTER_GL();
712 gl_d = glXGetCurrentReadDrawable();
713 ret = get_hdc_from_Drawable(gl_d);
714 LEAVE_GL();
716 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
717 return ret;
722 /***********************************************************************
723 * wglRealizeLayerPalette (OPENGL32.@)
725 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
726 int iLayerPlane,
727 BOOL bRealize) {
728 FIXME("()\n");
730 return FALSE;
733 /***********************************************************************
734 * wglSetLayerPaletteEntries (OPENGL32.@)
736 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
737 int iLayerPlane,
738 int iStart,
739 int cEntries,
740 const COLORREF *pcr) {
741 FIXME("(): stub !\n");
743 return 0;
746 /***********************************************************************
747 * wglShareLists (OPENGL32.@)
749 BOOL WINAPI wglShareLists(HGLRC hglrc1,
750 HGLRC hglrc2) {
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");
758 return FALSE;
759 } else {
760 if (org->ctx == NULL) {
761 ENTER_GL();
762 describeContext(org);
763 org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
764 LEAVE_GL();
765 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
767 if (NULL != dest) {
768 ENTER_GL();
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);
772 LEAVE_GL();
773 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
774 return TRUE;
777 return FALSE;
780 /***********************************************************************
781 * wglSwapLayerBuffers (OPENGL32.@)
783 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
784 UINT fuPlanes) {
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;
792 if (fuPlanes) {
793 WARN("Following layers unhandled : %08x\n", fuPlanes);
796 return TRUE;
799 static BOOL internal_wglUseFontBitmaps(HDC hdc,
800 DWORD first,
801 DWORD count,
802 DWORD listBase,
803 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
805 /* We are running using client-side rendering fonts... */
806 GLYPHMETRICS gm;
807 unsigned int glyph;
808 int size = 0;
809 void *bitmap = NULL, *gl_bitmap = NULL;
810 int org_alignment;
812 ENTER_GL();
813 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
814 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
815 LEAVE_GL();
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);
824 goto error;
825 } else {
826 TRACE(" - needed size : %d\n", needed_size);
829 if (needed_size > size) {
830 size = needed_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++) {
847 TRACE(" ");
848 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
849 if (bitmask == 0) {
850 bitmap_ += 1;
851 bitmask = 0x80;
853 if (*bitmap_ & bitmask)
854 TRACE("*");
855 else
856 TRACE(" ");
858 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
859 TRACE("\n");
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++) {
870 int width;
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];
878 ENTER_GL();
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,
884 gl_bitmap);
885 } else {
886 /* This is the case of 'empty' glyphs like the space character */
887 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
889 glEndList();
890 LEAVE_GL();
893 ENTER_GL();
894 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
895 LEAVE_GL();
897 HeapFree(GetProcessHeap(), 0, bitmap);
898 HeapFree(GetProcessHeap(), 0, gl_bitmap);
899 return TRUE;
901 error:
902 ENTER_GL();
903 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
904 LEAVE_GL();
906 HeapFree(GetProcessHeap(), 0, bitmap);
907 HeapFree(GetProcessHeap(), 0, gl_bitmap);
908 return FALSE;
911 /***********************************************************************
912 * wglUseFontBitmapsA (OPENGL32.@)
914 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
915 DWORD first,
916 DWORD count,
917 DWORD listBase)
919 Font fid = get_font( hdc );
921 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
923 if (fid == 0) {
924 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
927 ENTER_GL();
928 /* I assume that the glyphs are at the same position for X and for Windows */
929 glXUseXFont(fid, first, count, listBase);
930 LEAVE_GL();
931 return TRUE;
934 /***********************************************************************
935 * wglUseFontBitmapsW (OPENGL32.@)
937 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
938 DWORD first,
939 DWORD count,
940 DWORD listBase)
942 Font fid = get_font( hdc );
944 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
946 if (fid == 0) {
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");
952 ENTER_GL();
953 /* I assume that the glyphs are at the same position for X and for Windows */
954 glXUseXFont(fid, first, count, listBase);
955 LEAVE_GL();
956 return TRUE;
959 #ifdef HAVE_GL_GLU_H
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;
965 vertex[2] = 0.0;
968 static void tess_callback_vertex(GLvoid *vertex)
970 GLdouble *dbl = vertex;
971 TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
972 glVertex3dv(vertex);
975 static void tess_callback_begin(GLenum which)
977 TRACE("%d\n", which);
978 glBegin(which);
981 static void tess_callback_end(void)
983 TRACE("\n");
984 glEnd();
987 /***********************************************************************
988 * wglUseFontOutlines_common
990 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
991 DWORD first,
992 DWORD count,
993 DWORD listBase,
994 FLOAT deviation,
995 FLOAT extrusion,
996 int format,
997 LPGLYPHMETRICSFLOAT lpgmf,
998 BOOL unicode)
1000 UINT glyph;
1001 const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
1002 GLUtesselator *tess;
1003 LOGFONTW lf;
1004 HFONT old_font, unscaled_font;
1005 UINT em_size = 1024;
1006 RECT rc;
1008 TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
1009 listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
1012 ENTER_GL();
1013 tess = gluNewTess();
1014 if(tess)
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);
1020 LEAVE_GL();
1022 if(!tess) return FALSE;
1024 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
1025 rc.left = rc.right = rc.bottom = 0;
1026 rc.top = em_size;
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++)
1035 DWORD needed;
1036 GLYPHMETRICS gm;
1037 BYTE *buf;
1038 TTPOLYGONHEADER *pph;
1039 TTPOLYCURVE *ppc;
1040 GLdouble *vertices;
1042 if(unicode)
1043 needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1044 else
1045 needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
1047 if(needed == GDI_ERROR)
1048 goto error;
1050 buf = HeapAlloc(GetProcessHeap(), 0, needed);
1051 vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
1053 if(unicode)
1054 GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1055 else
1056 GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
1058 TRACE("glyph %d\n", glyph);
1060 if(lpgmf)
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);
1071 lpgmf++;
1074 ENTER_GL();
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);
1087 vertices += 3;
1089 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1090 while((char*)ppc < (char*)pph + pph->cb)
1092 int i;
1094 switch(ppc->wType) {
1095 case TT_PRIM_LINE:
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);
1101 vertices += 3;
1103 break;
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);
1114 vertices += 3;
1115 fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
1116 gluTessVertex(tess, vertices, vertices);
1117 vertices += 3;
1119 break;
1120 default:
1121 ERR("\t\tcurve type = %d\n", ppc->wType);
1122 gluTessEndContour(tess);
1123 goto error_in_list;
1126 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1127 (ppc->cpfx - 1) * sizeof(POINTFX));
1129 gluTessEndContour(tess);
1130 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1133 error_in_list:
1134 gluTessEndPolygon(tess);
1135 glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
1136 glEndList();
1137 LEAVE_GL();
1138 HeapFree(GetProcessHeap(), 0, buf);
1139 HeapFree(GetProcessHeap(), 0, vertices);
1142 error:
1143 DeleteObject(SelectObject(hdc, old_font));
1144 gluDeleteTess(tess);
1145 return TRUE;
1149 #else /* HAVE_GL_GLU_H */
1151 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1152 DWORD first,
1153 DWORD count,
1154 DWORD listBase,
1155 FLOAT deviation,
1156 FLOAT extrusion,
1157 int format,
1158 LPGLYPHMETRICSFLOAT lpgmf,
1159 BOOL unicode)
1161 FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1162 return FALSE;
1165 #endif /* HAVE_GL_GLU_H */
1167 /***********************************************************************
1168 * wglUseFontOutlinesA (OPENGL32.@)
1170 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1171 DWORD first,
1172 DWORD count,
1173 DWORD listBase,
1174 FLOAT deviation,
1175 FLOAT extrusion,
1176 int format,
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,
1186 DWORD first,
1187 DWORD count,
1188 DWORD listBase,
1189 FLOAT deviation,
1190 FLOAT extrusion,
1191 int format,
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");
1210 return NULL;
1211 } else {
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;
1217 char ThisExtn[256];
1219 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1220 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1221 GL_Extensions++;
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);
1230 TRACE(" active\n");
1231 } else {
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);*/
1248 /**
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) {
1254 *params = 32;
1256 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1258 if (pname == GL_ALPHA_BITS) {
1259 GLint tmp;
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);
1264 *params = 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"
1274 #endif
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 *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1281 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1282 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1283 const char *glx_extensions = glXQueryExtensionsString(display, screen);
1286 memset(&wine_glx, 0, sizeof(wine_glx));
1288 if (!strcmp("1.2", server_glx_version)) {
1289 wine_glx.version = 2;
1290 } else {
1291 wine_glx.version = 3;
1294 if (2 < wine_glx.version) {
1295 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1296 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1297 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1299 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1300 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1301 } else {
1302 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1303 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1304 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1305 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1306 } else {
1307 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1310 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1311 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1312 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1315 /* This is for brain-dead applications that use OpenGL functions before even
1316 creating a rendering context.... */
1317 static BOOL process_attach(void)
1319 XWindowAttributes win_attr;
1320 Visual *rootVisual;
1321 int num;
1322 XVisualInfo template;
1323 HDC hdc;
1324 XVisualInfo *vis = NULL;
1325 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1326 HMODULE mod = GetModuleHandleA( "winex11.drv" );
1327 void *opengl_handle;
1328 DWORD size = sizeof(internal_gl_disabled_extensions);
1329 HKEY hkey = 0;
1331 if (!root || !mod)
1333 ERR("X11DRV not loaded. Cannot create default context.\n");
1334 return FALSE;
1337 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1338 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1340 hdc = GetDC(0);
1341 default_display = get_display( hdc );
1342 ReleaseDC( 0, hdc );
1343 if (!default_display)
1345 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1346 return FALSE;
1349 ENTER_GL();
1351 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1352 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1353 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1354 with mismatched visuals. Note that the Root Window visual may not be double
1355 buffered, so apps actually attempting to render this way may flicker */
1356 if (XGetWindowAttributes( default_display, root, &win_attr ))
1358 rootVisual = win_attr.visual;
1360 else
1362 /* Get the default visual, since we can't seem to get the attributes from the
1363 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1364 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1367 template.visualid = XVisualIDFromVisual(rootVisual);
1368 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1369 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1370 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1371 XFree(vis);
1372 LEAVE_GL();
1374 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1375 if (opengl_handle != NULL) {
1376 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1377 wine_dlclose(opengl_handle, NULL, 0);
1378 if (p_glXGetProcAddressARB == NULL)
1379 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1382 internal_gl_disabled_extensions[0] = 0;
1383 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1384 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1385 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1387 RegCloseKey(hkey);
1390 if (default_cx == NULL) {
1391 ERR("Could not create default context.\n");
1393 else
1395 /* After context initialize also the list of supported WGL extensions. */
1396 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1397 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1399 return TRUE;
1403 /**********************************************************************/
1405 static void process_detach(void)
1407 glXDestroyContext(default_display, default_cx);
1409 /* Do not leak memory... */
1410 wgl_ext_finalize_extensions();
1411 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1414 /***********************************************************************
1415 * OpenGL initialisation routine
1417 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1419 switch(reason)
1421 case DLL_PROCESS_ATTACH:
1422 opengl32_handle = hinst;
1423 DisableThreadLibraryCalls(hinst);
1424 return process_attach();
1425 case DLL_PROCESS_DETACH:
1426 process_detach();
1427 break;
1429 return TRUE;