msi: Change some FIXME messages to comments.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blob5af2c2925deafe721a344a284a44aee72765003d
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
35 #include "wgl_ext.h"
36 #include "opengl_ext.h"
37 #include "wine/library.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
42 /** global glx object */
43 wine_glx_t wine_glx;
45 /* x11drv GDI escapes */
46 #define X11DRV_ESCAPE 6789
47 enum x11drv_escape_codes
49 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
50 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
51 X11DRV_GET_FONT, /* get current X font for a DC */
52 X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
53 X11DRV_START_EXPOSURES, /* start graphics exposures */
54 X11DRV_END_EXPOSURES, /* end graphics exposures */
55 X11DRV_GET_DCE, /* get the DCE pointer */
56 X11DRV_SET_DCE, /* set the DCE pointer */
57 X11DRV_GET_GLX_DRAWABLE /* get current glx drawable for a DC */
60 void (*wine_tsx11_lock_ptr)(void) = NULL;
61 void (*wine_tsx11_unlock_ptr)(void) = NULL;
63 static GLXContext default_cx = NULL;
64 static Display *default_display; /* display to use for default context */
66 static HMODULE opengl32_handle;
68 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
70 static char internal_gl_disabled_extensions[512];
71 static char* internal_gl_extensions = NULL;
73 typedef struct wine_glcontext {
74 HDC hdc;
75 Display *display;
76 XVisualInfo *vis;
77 GLXFBConfig fb_conf;
78 GLXContext ctx;
79 struct wine_glcontext *next;
80 struct wine_glcontext *prev;
81 } Wine_GLContext;
82 static Wine_GLContext *context_list;
84 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
86 Wine_GLContext *ret;
87 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
88 return ret;
91 static inline void free_context(Wine_GLContext *context)
93 if (context->next != NULL) context->next->prev = context->prev;
94 if (context->prev != NULL) context->prev->next = context->next;
95 else context_list = context->next;
97 HeapFree(GetProcessHeap(), 0, context);
100 static inline Wine_GLContext *alloc_context(void)
102 Wine_GLContext *ret;
104 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
106 ret->next = context_list;
107 if (context_list) context_list->prev = ret;
108 context_list = ret;
110 return ret;
113 inline static BOOL is_valid_context( Wine_GLContext *ctx )
115 Wine_GLContext *ptr;
116 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
117 return (ptr != NULL);
120 /* retrieve the X display to use on a given DC */
121 inline static Display *get_display( HDC hdc )
123 Display *display;
124 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
126 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
127 sizeof(display), (LPSTR)&display )) display = NULL;
128 return display;
132 /* retrieve the GLX drawable to use on a given DC */
133 inline static Drawable get_drawable( HDC hdc )
135 GLXDrawable drawable;
136 enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
138 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
139 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
140 return drawable;
143 /** for use of wglGetCurrentReadDCARB */
144 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
146 Wine_GLContext *ret;
147 for (ret = context_list; ret; ret = ret->next) {
148 if (d == get_drawable( ret->hdc )) {
149 return ret->hdc;
152 return NULL;
155 /* retrieve the X font to use on a given DC */
156 inline static Font get_font( HDC hdc )
158 Font font;
159 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
161 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
162 sizeof(font), (LPSTR)&font )) font = 0;
163 return font;
167 /***********************************************************************
168 * wglCreateContext (OPENGL32.@)
170 HGLRC WINAPI wglCreateContext(HDC hdc)
172 Wine_GLContext *ret;
173 int num;
174 XVisualInfo template;
175 XVisualInfo *vis = NULL;
176 Display *display = get_display( hdc );
177 int hdcPF = GetPixelFormat(hdc);
178 GLXFBConfig cur_cfg;
180 TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
182 /* First, get the visual in use by the X11DRV */
183 if (!display) return 0;
184 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
185 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
187 if (vis == NULL) {
188 ERR("NULL visual !!!\n");
189 /* Need to set errors here */
190 return NULL;
192 if (0 >= hdcPF) {
193 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
194 return NULL;
198 int nCfgs_fmt = 0;
199 GLXFBConfig* cfgs_fmt = NULL;
200 int value;
201 int gl_test = 0;
202 cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
203 if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
204 ERR("Cannot get FB Configs, expect problems.\n");
205 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
206 return NULL;
208 if (nCfgs_fmt < hdcPF) {
209 ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
210 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
211 return NULL;
213 cur_cfg = cfgs_fmt[hdcPF - 1];
214 gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
215 if (gl_test) {
216 ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
217 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
218 return NULL;
220 XFree(cfgs_fmt);
223 /* The context will be allocated in the wglMakeCurrent call */
224 ENTER_GL();
225 ret = alloc_context();
226 LEAVE_GL();
227 ret->hdc = hdc;
228 ret->display = display;
229 ret->fb_conf = cur_cfg;
230 /*ret->vis = vis;*/
231 ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
233 TRACE(" creating context %p (GL context creation delayed)\n", ret);
234 return (HGLRC) ret;
237 /***********************************************************************
238 * wglCreateLayerContext (OPENGL32.@)
240 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
241 int iLayerPlane) {
242 TRACE("(%p,%d)\n", hdc, iLayerPlane);
244 if (iLayerPlane == 0) {
245 return wglCreateContext(hdc);
247 FIXME(" no handler for layer %d\n", iLayerPlane);
249 return NULL;
252 /***********************************************************************
253 * wglCopyContext (OPENGL32.@)
255 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
256 HGLRC hglrcDst,
257 UINT mask) {
258 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
260 return FALSE;
263 /***********************************************************************
264 * wglDeleteContext (OPENGL32.@)
266 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
268 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
269 BOOL ret = TRUE;
271 TRACE("(%p)\n", hglrc);
273 ENTER_GL();
274 /* A game (Half Life not to name it) deletes twice the same context,
275 * so make sure it is valid first */
276 if (is_valid_context( ctx ))
278 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
279 free_context(ctx);
281 else
283 WARN("Error deleting context !\n");
284 SetLastError(ERROR_INVALID_HANDLE);
285 ret = FALSE;
287 LEAVE_GL();
289 return ret;
292 /***********************************************************************
293 * wglDescribeLayerPlane (OPENGL32.@)
295 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
296 int iPixelFormat,
297 int iLayerPlane,
298 UINT nBytes,
299 LPLAYERPLANEDESCRIPTOR plpd) {
300 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
302 return FALSE;
305 /***********************************************************************
306 * wglGetCurrentContext (OPENGL32.@)
308 HGLRC WINAPI wglGetCurrentContext(void) {
309 GLXContext gl_ctx;
310 Wine_GLContext *ret;
312 TRACE("()\n");
314 ENTER_GL();
315 gl_ctx = glXGetCurrentContext();
316 ret = get_context_from_GLXContext(gl_ctx);
317 LEAVE_GL();
319 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
321 return (HGLRC)ret;
324 /***********************************************************************
325 * wglGetCurrentDC (OPENGL32.@)
327 HDC WINAPI wglGetCurrentDC(void) {
328 GLXContext gl_ctx;
329 Wine_GLContext *ret;
331 TRACE("()\n");
333 ENTER_GL();
334 gl_ctx = glXGetCurrentContext();
335 ret = get_context_from_GLXContext(gl_ctx);
336 LEAVE_GL();
338 if (ret) {
339 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
340 return ret->hdc;
341 } else {
342 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
343 return 0;
347 /***********************************************************************
348 * wglGetLayerPaletteEntries (OPENGL32.@)
350 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
351 int iLayerPlane,
352 int iStart,
353 int cEntries,
354 const COLORREF *pcr) {
355 FIXME("(): stub !\n");
357 return 0;
360 /***********************************************************************
361 * wglGetProcAddress (OPENGL32.@)
363 static int compar(const void *elt_a, const void *elt_b) {
364 return strcmp(((const OpenGL_extension *) elt_a)->name,
365 ((const OpenGL_extension *) elt_b)->name);
368 static int wgl_compar(const void *elt_a, const void *elt_b) {
369 return strcmp(((const WGL_extension *) elt_a)->func_name,
370 ((const WGL_extension *) elt_b)->func_name);
373 PROC WINAPI wglGetProcAddress(LPCSTR lpszProc) {
374 void *local_func;
375 OpenGL_extension ext;
376 OpenGL_extension *ext_ret;
378 TRACE("(%s)\n", lpszProc);
380 /* First, look if it's not already defined in the 'standard' OpenGL functions */
381 if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
382 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
383 return local_func;
386 if (p_glXGetProcAddressARB == NULL) {
387 ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
388 return NULL;
391 /* After that, search in the thunks to find the real name of the extension */
392 ext.name = (char *) lpszProc;
393 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
394 extension_registry_size, sizeof(OpenGL_extension), compar);
396 if (ext_ret == NULL) {
397 WGL_extension wgl_ext, *wgl_ext_ret;
399 /* Try to find the function in the WGL extensions ... */
400 wgl_ext.func_name = (char *) lpszProc;
401 wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
402 wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
404 if (wgl_ext_ret == NULL) {
405 /* Some sanity checks :-) */
406 ENTER_GL();
407 local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
408 LEAVE_GL();
409 if (local_func != NULL) {
410 WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
411 return NULL;
414 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
415 return NULL;
416 } else {
417 void *ret = NULL;
419 if (wgl_ext_ret->func_init != NULL) {
420 const char *err_msg;
421 if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
422 wgl_ext_ret->context)) == NULL) {
423 ret = wgl_ext_ret->func_address;
424 } else {
425 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
426 return NULL;
428 } else {
429 ret = wgl_ext_ret->func_address;
432 if (ret)
433 TRACE(" returning WGL function (%p)\n", ret);
434 return ret;
436 } else {
437 ENTER_GL();
438 local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
439 LEAVE_GL();
441 /* After that, look at the extensions defined in the Linux OpenGL library */
442 if (local_func == NULL) {
443 char buf[256];
444 void *ret = NULL;
446 /* Remove the 3 last letters (EXT, ARB, ...).
448 I know that some extensions have more than 3 letters (MESA, NV,
449 INTEL, ...), but this is only a stop-gap measure to fix buggy
450 OpenGL drivers (moreover, it is only useful for old 1.0 apps
451 that query the glBindTextureEXT extension).
453 memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
454 buf[strlen(ext_ret->glx_name) - 3] = '\0';
455 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
457 ret = GetProcAddress(opengl32_handle, buf);
458 if (ret != NULL) {
459 TRACE(" found function in main OpenGL library (%p) !\n", ret);
460 } else {
461 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
464 return ret;
465 } else {
466 TRACE(" returning function (%p)\n", ext_ret->func);
467 *(ext_ret->func_ptr) = local_func;
469 return ext_ret->func;
474 static int describeContext(Wine_GLContext* ctx) {
475 int tmp;
476 int ctx_vis_id;
477 TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
478 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
479 TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
480 wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
481 TRACE(" - VISUAL_ID 0x%x\n", tmp);
482 ctx_vis_id = tmp;
483 return ctx_vis_id;
486 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
487 int tmp;
488 int draw_vis_id;
489 if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable) {
490 /** glXQueryDrawable not available so returns not supported */
491 return -1;
493 TRACE(" Drawable %p have :\n", (void*) drawable);
494 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
495 TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
496 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
497 TRACE(" - VISUAL_ID as 0x%x\n", tmp);
498 draw_vis_id = tmp;
499 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
500 TRACE(" - WIDTH as %d\n", tmp);
501 wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
502 TRACE(" - HEIGHT as %d\n", tmp);
503 return draw_vis_id;
506 /***********************************************************************
507 * wglMakeCurrent (OPENGL32.@)
509 BOOL WINAPI wglMakeCurrent(HDC hdc,
510 HGLRC hglrc) {
511 BOOL ret;
512 DWORD type = GetObjectType(hdc);
514 TRACE("(%p,%p)\n", hdc, hglrc);
516 ENTER_GL();
517 if (hglrc == NULL) {
518 ret = glXMakeCurrent(default_display, None, NULL);
519 } else {
520 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
521 Drawable drawable = get_drawable( hdc );
522 if (ctx->ctx == NULL) {
523 int draw_vis_id, ctx_vis_id;
524 VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
525 TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
526 draw_vis_id = describeDrawable(ctx, drawable);
527 ctx_vis_id = describeContext(ctx);
529 if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
531 * Inherits from root window so reuse desktop visual
533 XVisualInfo template;
534 XVisualInfo *vis;
535 int num;
536 template.visualid = visualid;
537 vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
539 TRACE(" Creating GLX Context\n");
540 ctx->ctx = glXCreateContext(ctx->display, vis, NULL, True);
541 } else {
542 TRACE(" Creating GLX Context\n");
543 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
545 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
547 TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
548 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
549 if(ret && type == OBJ_MEMDC)
550 glDrawBuffer(GL_FRONT_LEFT);
552 LEAVE_GL();
553 TRACE(" returning %s\n", (ret ? "True" : "False"));
554 return ret;
557 /***********************************************************************
558 * wglMakeContextCurrentARB (OPENGL32.@)
560 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
562 BOOL ret;
563 TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
565 ENTER_GL();
566 if (hglrc == NULL) {
567 ret = glXMakeCurrent(default_display, None, NULL);
568 } else {
569 if (NULL == wine_glx.p_glXMakeContextCurrent) {
570 ret = FALSE;
571 } else {
572 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
573 Drawable d_draw = get_drawable( hDrawDC );
574 Drawable d_read = get_drawable( hReadDC );
576 if (ctx->ctx == NULL) {
577 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
578 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
580 ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
583 LEAVE_GL();
585 TRACE(" returning %s\n", (ret ? "True" : "False"));
586 return ret;
589 /***********************************************************************
590 * wglGetCurrentReadDCARB (OPENGL32.@)
592 HDC WINAPI wglGetCurrentReadDCARB(void)
594 GLXDrawable gl_d;
595 HDC ret;
597 TRACE("()\n");
599 ENTER_GL();
600 gl_d = glXGetCurrentReadDrawable();
601 ret = get_hdc_from_Drawable(gl_d);
602 LEAVE_GL();
604 TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
605 return ret;
610 /***********************************************************************
611 * wglRealizeLayerPalette (OPENGL32.@)
613 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
614 int iLayerPlane,
615 BOOL bRealize) {
616 FIXME("()\n");
618 return FALSE;
621 /***********************************************************************
622 * wglSetLayerPaletteEntries (OPENGL32.@)
624 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
625 int iLayerPlane,
626 int iStart,
627 int cEntries,
628 const COLORREF *pcr) {
629 FIXME("(): stub !\n");
631 return 0;
634 /***********************************************************************
635 * wglShareLists (OPENGL32.@)
637 BOOL WINAPI wglShareLists(HGLRC hglrc1,
638 HGLRC hglrc2) {
639 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
640 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
642 TRACE("(%p, %p)\n", org, dest);
644 if (NULL != dest && dest->ctx != NULL) {
645 ERR("Could not share display lists, context already created !\n");
646 return FALSE;
647 } else {
648 if (org->ctx == NULL) {
649 ENTER_GL();
650 describeContext(org);
651 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
652 LEAVE_GL();
653 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
655 if (NULL != dest) {
656 ENTER_GL();
657 describeContext(dest);
658 /* Create the destination context with display lists shared */
659 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
660 LEAVE_GL();
661 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
662 return TRUE;
665 return FALSE;
668 /***********************************************************************
669 * wglSwapLayerBuffers (OPENGL32.@)
671 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
672 UINT fuPlanes) {
673 TRACE("(%p, %08x)\n", hdc, fuPlanes);
675 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
676 if (!SwapBuffers(hdc)) return FALSE;
677 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
680 if (fuPlanes) {
681 WARN("Following layers unhandled : %08x\n", fuPlanes);
684 return TRUE;
687 static BOOL internal_wglUseFontBitmaps(HDC hdc,
688 DWORD first,
689 DWORD count,
690 DWORD listBase,
691 DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
693 /* We are running using client-side rendering fonts... */
694 GLYPHMETRICS gm;
695 unsigned int glyph;
696 int size = 0;
697 void *bitmap = NULL, *gl_bitmap = NULL;
698 int org_alignment;
700 ENTER_GL();
701 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
702 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
703 LEAVE_GL();
705 for (glyph = first; glyph < first + count; glyph++) {
706 unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
707 int height, width_int;
709 TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
710 if (needed_size == GDI_ERROR) {
711 TRACE(" - needed size : %d (GDI_ERROR)\n", needed_size);
712 goto error;
713 } else {
714 TRACE(" - needed size : %d\n", needed_size);
717 if (needed_size > size) {
718 size = needed_size;
719 HeapFree(GetProcessHeap(), 0, bitmap);
720 HeapFree(GetProcessHeap(), 0, gl_bitmap);
721 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
722 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
724 if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
725 if (TRACE_ON(opengl)) {
726 unsigned int height, width, bitmask;
727 unsigned char *bitmap_ = (unsigned char *) bitmap;
729 TRACE(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
730 TRACE(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
731 TRACE(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
732 if (needed_size != 0) {
733 TRACE(" - bitmap :\n");
734 for (height = 0; height < gm.gmBlackBoxY; height++) {
735 TRACE(" ");
736 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
737 if (bitmask == 0) {
738 bitmap_ += 1;
739 bitmask = 0x80;
741 if (*bitmap_ & bitmask)
742 TRACE("*");
743 else
744 TRACE(" ");
746 bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
747 TRACE("\n");
752 /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
753 * glyph for it to be drawn properly.
755 if (needed_size != 0) {
756 width_int = (gm.gmBlackBoxX + 31) / 32;
757 for (height = 0; height < gm.gmBlackBoxY; height++) {
758 int width;
759 for (width = 0; width < width_int; width++) {
760 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
761 ((int *) bitmap)[height * width_int + width];
766 ENTER_GL();
767 glNewList(listBase++, GL_COMPILE);
768 if (needed_size != 0) {
769 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
770 0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
771 gm.gmCellIncX, gm.gmCellIncY,
772 gl_bitmap);
773 } else {
774 /* This is the case of 'empty' glyphs like the space character */
775 glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
777 glEndList();
778 LEAVE_GL();
781 ENTER_GL();
782 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
783 LEAVE_GL();
785 HeapFree(GetProcessHeap(), 0, bitmap);
786 HeapFree(GetProcessHeap(), 0, gl_bitmap);
787 return TRUE;
789 error:
790 ENTER_GL();
791 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
792 LEAVE_GL();
794 HeapFree(GetProcessHeap(), 0, bitmap);
795 HeapFree(GetProcessHeap(), 0, gl_bitmap);
796 return FALSE;
799 /***********************************************************************
800 * wglUseFontBitmapsA (OPENGL32.@)
802 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
803 DWORD first,
804 DWORD count,
805 DWORD listBase)
807 Font fid = get_font( hdc );
809 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
811 if (fid == 0) {
812 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
815 ENTER_GL();
816 /* I assume that the glyphs are at the same position for X and for Windows */
817 glXUseXFont(fid, first, count, listBase);
818 LEAVE_GL();
819 return TRUE;
822 /***********************************************************************
823 * wglUseFontBitmapsW (OPENGL32.@)
825 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
826 DWORD first,
827 DWORD count,
828 DWORD listBase)
830 Font fid = get_font( hdc );
832 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
834 if (fid == 0) {
835 return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
838 WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
840 ENTER_GL();
841 /* I assume that the glyphs are at the same position for X and for Windows */
842 glXUseXFont(fid, first, count, listBase);
843 LEAVE_GL();
844 return TRUE;
847 /***********************************************************************
848 * wglUseFontOutlinesA (OPENGL32.@)
850 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
851 DWORD first,
852 DWORD count,
853 DWORD listBase,
854 FLOAT deviation,
855 FLOAT extrusion,
856 int format,
857 LPGLYPHMETRICSFLOAT lpgmf) {
858 FIXME("(): stub !\n");
860 return FALSE;
863 const GLubyte * internal_glGetString(GLenum name) {
864 const char* GL_Extensions = NULL;
866 if (GL_EXTENSIONS != name) {
867 return glGetString(name);
870 if (NULL == internal_gl_extensions) {
871 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
873 TRACE("GL_EXTENSIONS reported:\n");
874 if (NULL == GL_Extensions) {
875 ERR("GL_EXTENSIONS returns NULL\n");
876 return NULL;
877 } else {
878 size_t len = strlen(GL_Extensions);
879 internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
881 while (*GL_Extensions != 0x00) {
882 const char* Start = GL_Extensions;
883 char ThisExtn[256];
885 memset(ThisExtn, 0x00, sizeof(ThisExtn));
886 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
887 GL_Extensions++;
889 memcpy(ThisExtn, Start, (GL_Extensions - Start));
890 TRACE("- %s:", ThisExtn);
892 /* test if supported API is disabled by config */
893 if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
894 strcat(internal_gl_extensions, " ");
895 strcat(internal_gl_extensions, ThisExtn);
896 TRACE(" active\n");
897 } else {
898 TRACE(" deactived (by config)\n");
901 if (*GL_Extensions == ' ') GL_Extensions++;
905 return (const GLubyte *) internal_gl_extensions;
908 void internal_glGetIntegerv(GLenum pname, GLint* params) {
909 glGetIntegerv(pname, params);
910 if (pname == GL_DEPTH_BITS) {
911 GLXContext gl_ctx = glXGetCurrentContext();
912 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
913 /*TRACE("returns Wine Ctx as %p\n", ret);*/
914 /**
915 * if we cannot find a Wine Context
916 * we only have the default wine desktop context,
917 * so if we have only a 24 depth say we have 32
919 if (NULL == ret && 24 == *params) {
920 *params = 32;
922 TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
924 if (pname == GL_ALPHA_BITS) {
925 GLint tmp;
926 GLXContext gl_ctx = glXGetCurrentContext();
927 Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
928 glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
929 TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
930 *params = tmp;
935 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
936 include all dependencies
938 #ifndef SONAME_LIBGL
939 #define SONAME_LIBGL "libGL.so"
940 #endif
942 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc)
944 const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
945 const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
947 const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
948 const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
949 const char *glx_extensions = glXQueryExtensionsString(display, screen);
952 memset(&wine_glx, 0, sizeof(wine_glx));
954 if (!strcmp("1.2", server_glx_version)) {
955 wine_glx.version = 2;
956 } else {
957 wine_glx.version = 3;
960 if (2 < wine_glx.version) {
961 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
962 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
963 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
965 /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
966 wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
967 } else {
968 if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
969 wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
970 wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
971 wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
972 } else {
973 ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
976 /** try anyway to retrieve that calls, maybe they works using glx client tricks */
977 wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
978 wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
981 /* This is for brain-dead applications that use OpenGL functions before even
982 creating a rendering context.... */
983 static BOOL process_attach(void)
985 XWindowAttributes win_attr;
986 Visual *rootVisual;
987 int num;
988 XVisualInfo template;
989 HDC hdc;
990 XVisualInfo *vis = NULL;
991 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
992 HMODULE mod = GetModuleHandleA( "winex11.drv" );
993 void *opengl_handle;
994 DWORD size = sizeof(internal_gl_disabled_extensions);
995 HKEY hkey = 0;
997 if (!root || !mod)
999 ERR("X11DRV not loaded. Cannot create default context.\n");
1000 return FALSE;
1003 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1004 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1006 hdc = GetDC(0);
1007 default_display = get_display( hdc );
1008 ReleaseDC( 0, hdc );
1009 if (!default_display)
1011 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1012 return FALSE;
1015 ENTER_GL();
1017 /* Try to get the visual from the Root Window. We can't use the standard (presumably
1018 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1019 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1020 with mismatched visuals. Note that the Root Window visual may not be double
1021 buffered, so apps actually attempting to render this way may flicker */
1022 if (XGetWindowAttributes( default_display, root, &win_attr ))
1024 rootVisual = win_attr.visual;
1026 else
1028 /* Get the default visual, since we can't seem to get the attributes from the
1029 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
1030 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1033 template.visualid = XVisualIDFromVisual(rootVisual);
1034 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1035 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1036 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1037 XFree(vis);
1038 LEAVE_GL();
1040 opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1041 if (opengl_handle != NULL) {
1042 p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1043 wine_dlclose(opengl_handle, NULL, 0);
1044 if (p_glXGetProcAddressARB == NULL)
1045 TRACE("could not find glXGetProcAddressARB in libGL.\n");
1048 internal_gl_disabled_extensions[0] = 0;
1049 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1050 if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1051 TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1053 RegCloseKey(hkey);
1056 if (default_cx == NULL) {
1057 ERR("Could not create default context.\n");
1059 else
1061 /* After context initialize also the list of supported WGL extensions. */
1062 wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1063 wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1065 return TRUE;
1069 /**********************************************************************/
1071 static void process_detach(void)
1073 glXDestroyContext(default_display, default_cx);
1075 /* Do not leak memory... */
1076 wgl_ext_finalize_extensions();
1077 if (NULL != internal_gl_extensions) {
1078 HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1082 /***********************************************************************
1083 * OpenGL initialisation routine
1085 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1087 switch(reason)
1089 case DLL_PROCESS_ATTACH:
1090 opengl32_handle = hinst;
1091 DisableThreadLibraryCalls(hinst);
1092 return process_attach();
1093 case DLL_PROCESS_DETACH:
1094 process_detach();
1095 break;
1097 return TRUE;