Hi,
Since the WM rewrite we can only use the visual which was created by x11drv at
x11drv initialization. In general this is a simple 32bit RGBA visual or when
that's not available it is some 16bit visual.
The problem is that the opengl code advertises more formats than this single
format. The problem which this can cause is that a 'bad' format is set by
SetPixelFormat. In the end when we create a context using wglCreateContext this
'bad' pixelformat is used. When some time later glXMakeCurrent is called we
will get a BadMatch. (Note that in a few cases we catch the 'BadMatch' before
it happens and create a new GLX Context; this is when context is NULL)
The proposed patch which I attached to this email rewrites the pixel format
code. First I'll give a short introduction and then I will explain my changes.
The functions
ChoosePixelFormat/GetPixelFormat/SetPixelFormat/DescribePixelFormat
all work with a parameter 'iPixelFormat'. This variable is an index into the
table of supported pixel formats. At the moment the index is a direct mapping
to the FB config table exported by GLX.
I have changed ChoosePixelFormat to only return the format of the main visual.
Further this function needs to find a 'closest match' to the requested format,
before it tried to find an exact match. I changed the function to look for a
close match. Further because only 1 format is supported, the max index the
function can return is 1. This kills the direct mapping of the index to the
index in the GLX FB config table.
All the opengl calls in x11drv got changed to only accept our single format. As
I mentioned earlier the opengl calls used the specified iPixelFormat as an
index in the GLX FB config table. Because the 1:1 mapping of iPixelFormat to
this table got lost I have added a function to retrieve the index of the main
visual.
Further I had to change our wglMakeCurrent call to retrieve the pixel format to
use from the main visual instead of getting it from a GetPixelFormat call. This
was done because wglMakeCurrent needs an index into the GLX FB Config table and
not in our 'win32 opengl format table' (which only contains 1 format).
I have tested the patch in several programs. Before Halflife1 didn't work in
16bit because ChoosePixelFormat was too strict, the game works fine now.
Further the patch also fixes the BadMatch error Nvidia users received in World
Of Warcraft when using the OpenGL renderer.
I think the patch is a correct fix for the BadMatch / ChoosePixelFormat issues.
The patch isn't 100% complete yet as I haven't updated the WGL extensions for
pbuffer and wglChoosePixelFormat to work with the new pixelformats yet (that's
why you see a line WoW hack). I will fix that part when you guys think that the
patch is correct.
Regards,
Roderick Colenbrander
--
Der GMX SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen!
Ideal für Modem und ISDN: http://www.gmx.net/de/go/smartsurfer
Index: dlls/opengl32/wgl.c
===================================================================
RCS file: /home/wine/wine/dlls/opengl32/wgl.c,v
retrieving revision 1.86
diff -u -r1.86 wgl.c
--- dlls/opengl32/wgl.c 2 Aug 2006 11:50:40 -0000 1.86
+++ dlls/opengl32/wgl.c 14 Aug 2006 14:20:55 -0000
@@ -200,6 +200,36 @@
return font;
}
+static BOOL get_fbconfig_from_visual(Display *display, XVisualInfo *visual, int *fmt_id, int *fmt_index)
+{
+ int nCfgs = 0;
+ int tmp_fmt_id = 0;
+ int tmp_vis_id = 0;
+ int i = 0;
+ GLXFBConfig* cfgs = NULL;
+
+ cfgs = wine_glx.p_glXChooseFBConfig(display, DefaultScreen(display), NULL, &nCfgs);
+ if (NULL == cfgs || 0 == nCfgs) {
+ ERR("glXChooseFBConfig returns NULL\n");
+ if(cfgs != NULL) XFree(cfgs);
+ return FALSE;
+ }
+
+ /* Walk through all FB configurations to retrieve the FB configuration matching our visual */
+ for(i=0; i<nCfgs; i++) {
+ wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_FBCONFIG_ID, &tmp_fmt_id);
+ wine_glx.p_glXGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &tmp_vis_id);
+ if(tmp_vis_id == visual->visualid) {
+ *fmt_id = tmp_fmt_id;
+ *fmt_index = i;
+ TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", *fmt_id, *fmt_index, tmp_vis_id);
+ if(cfgs != NULL) XFree(cfgs);
+ return TRUE;
+ }
+ }
+ if(cfgs != NULL) XFree(cfgs);
+ return FALSE;
+}
/***********************************************************************
* wglCreateContext (OPENGL32.@)
@@ -211,7 +241,8 @@
XVisualInfo template;
XVisualInfo *vis = NULL;
Display *display = get_display( hdc );
- int hdcPF = GetPixelFormat(hdc);
+ int hdcPF = 0;
+ int tmp = 0;
GLXFBConfig cur_cfg;
TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
@@ -220,6 +251,12 @@
if (!display) return 0;
template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
+
+ /* Get the pixel format to use from our desktop's visual */
+ if(!get_fbconfig_from_visual(display, vis, &tmp, &hdcPF)) {
+ ERR("Can't receive the pixel format to use!\n");
+ return NULL;
+ }
if (vis == NULL) {
ERR("NULL visual !!!\n");
Index: dlls/opengl32/wgl_ext.c
===================================================================
RCS file: /home/wine/wine/dlls/opengl32/wgl_ext.c,v
retrieving revision 1.20
diff -u -r1.20 wgl_ext.c
--- dlls/opengl32/wgl_ext.c 2 Aug 2006 11:50:40 -0000 1.20
+++ dlls/opengl32/wgl_ext.c 14 Aug 2006 14:20:56 -0000
@@ -918,6 +918,8 @@
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto create_failed; /* unespected error */
}
+ /* Temp WoW hack; this will be fixed in the proper patch */
+ iPixelFormat = 3;
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLPBuffer));
if (NULL == object) {
Index: dlls/winex11.drv/opengl.c
===================================================================
RCS file: /home/wine/wine/dlls/winex11.drv/opengl.c,v
retrieving revision 1.4
diff -u -r1.4 opengl.c
--- dlls/winex11.drv/opengl.c 7 Jul 2006 16:11:36 -0000 1.4
+++ dlls/winex11.drv/opengl.c 14 Aug 2006 14:21:01 -0000
@@ -172,10 +172,60 @@
return FALSE;
}
-#define TEST_AND_ADD1(t,a) if (t) att_list[att_pos++] = (a)
-#define TEST_AND_ADD2(t,a,b) if (t) { att_list[att_pos++] = (a); att_list[att_pos++] = (b); }
-#define NULL_TEST_AND_ADD2(tv,a,b) att_list[att_pos++] = (a); att_list[att_pos++] = ((tv) == 0 ? 0 : (b))
-#define ADD2(a,b) att_list[att_pos++] = (a); att_list[att_pos++] = (b)
+static BOOL get_fbconfig_from_visual(XVisualInfo *visual, int *fmt_id, int *fmt_index)
+{
+ int nCfgs = 0;
+ int tmp_fmt_id = 0;
+ int tmp_vis_id = 0;
+ int i = 0;
+ GLXFBConfig* cfgs = NULL;
+
+ cfgs = pglXChooseFBConfig(gdi_display, DefaultScreen(gdi_display), NULL, &nCfgs);
+ if (NULL == cfgs || 0 == nCfgs) {
+ ERR("glXChooseFBConfig returns NULL (glError: %d)\n", pglGetError());
+ if(cfgs != NULL) XFree(cfgs);
+ return FALSE;
+ }
+
+ /* Walk through all FB configurations to retrieve the FB configuration matching our visual */
+ for(i=0; i<nCfgs; i++) {
+ pglXGetFBConfigAttrib(gdi_display, cfgs[i], GLX_FBCONFIG_ID, &tmp_fmt_id);
+ pglXGetFBConfigAttrib(gdi_display, cfgs[i], GLX_VISUAL_ID, &tmp_vis_id);
+ if(tmp_vis_id == visual->visualid) {
+ *fmt_id = tmp_fmt_id;
+ *fmt_index = i;
+ TRACE("Found FBCONFIG_ID 0x%x at index %d for VISUAL_ID 0x%x\n", *fmt_id, *fmt_index, tmp_vis_id);
+ if(cfgs != NULL) XFree(cfgs);
+ return TRUE;
+ }
+ }
+ if(cfgs != NULL) XFree(cfgs);
+ return FALSE;
+}
+
+static BOOL get_pixel_format_index_from_main_visual(int *index)
+{
+ XVisualInfo *visual;
+ int fmt_id = 0;
+ int fmt_index = 0;
+ int res = FALSE;
+
+ visual = X11DRV_setup_opengl_visual(gdi_display);
+ if(!visual) {
+ ERR("Can't get an opengl visual, expect problems!\n");
+ return FALSE;
+ }
+
+ if(get_fbconfig_from_visual(visual, &fmt_id, &fmt_index)) {
+ *index = fmt_index + 1; /* Use a one based index, iPixelFormat uses that too */
+ res = TRUE;
+ } else {
+ ERR("Can't find a matching FBCONFIG_ID for VISUAL_ID 0x%lx!\n", visual->visualid);
+ }
+
+ if(visual != NULL) XFree(visual);
+ return res;
+}
/**
* X11DRV_ChoosePixelFormat
@@ -184,142 +234,112 @@
*/
int X11DRV_ChoosePixelFormat(X11DRV_PDEVICE *physDev,
const PIXELFORMATDESCRIPTOR *ppfd) {
- int att_list[64];
- int att_pos = 0;
- int att_pos_fac = 0;
GLXFBConfig* cfgs = NULL;
int ret = 0;
+ int nCfgs = 0;
+ int fmt_id = 0;
+ int fmt_index = 0;
+ XVisualInfo *visual = NULL;
if (!has_opengl()) {
ERR("No libGL on this box - disabling OpenGL support !\n");
return 0;
}
-
+
if (TRACE_ON(opengl)) {
TRACE("(%p,%p)\n", physDev, ppfd);
dump_PIXELFORMATDESCRIPTOR((const PIXELFORMATDESCRIPTOR *) ppfd);
}
- /* Now, build the request to GLX */
-
- if (ppfd->iPixelType == PFD_TYPE_COLORINDEX) {
- ADD2(GLX_BUFFER_SIZE, ppfd->cColorBits);
- }
- if (ppfd->iPixelType == PFD_TYPE_RGBA) {
- ADD2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
- if (ppfd->dwFlags & PFD_DEPTH_DONTCARE) {
- ADD2(GLX_DEPTH_SIZE, GLX_DONT_CARE);
- } else {
- if (32 == ppfd->cDepthBits) {
- /**
- * for 32 bpp depth buffers force to use 24.
- * needed as some drivers don't support 32bpp
- */
- TEST_AND_ADD2(ppfd->cDepthBits, GLX_DEPTH_SIZE, 24);
- } else {
- TEST_AND_ADD2(ppfd->cDepthBits, GLX_DEPTH_SIZE, ppfd->cDepthBits);
- }
- }
- if (32 == ppfd->cColorBits) {
- ADD2(GLX_RED_SIZE, 8);
- ADD2(GLX_GREEN_SIZE, 8);
- ADD2(GLX_BLUE_SIZE, 8);
- ADD2(GLX_ALPHA_SIZE, 8);
- } else {
- ADD2(GLX_BUFFER_SIZE, ppfd->cColorBits);
- /* Some broken apps try to ask for more than 8 bits of alpha */
- TEST_AND_ADD2(ppfd->cAlphaBits, GLX_ALPHA_SIZE, min(ppfd->cAlphaBits,8));
- }
- }
- TEST_AND_ADD2(ppfd->cStencilBits, GLX_STENCIL_SIZE, ppfd->cStencilBits);
- TEST_AND_ADD2(ppfd->cAuxBuffers, GLX_AUX_BUFFERS, ppfd->cAuxBuffers);
-
- /* These flags are not supported yet...
- ADD2(GLX_ACCUM_SIZE, ppfd->cAccumBits);
- */
-
- /** facultative flags now */
- att_pos_fac = att_pos;
- if (ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) {
- ADD2(GLX_DOUBLEBUFFER, GLX_DONT_CARE);
- } else {
- ADD2(GLX_DOUBLEBUFFER, (ppfd->dwFlags & PFD_DOUBLEBUFFER) ? TRUE : FALSE);
+ wine_tsx11_lock();
+ visual = X11DRV_setup_opengl_visual(gdi_display);
+ if(!visual) {
+ ERR("Can't get an opengl visual!\n");
+ goto choose_exit;
}
- if (ppfd->dwFlags & PFD_STEREO_DONTCARE) {
- ADD2(GLX_STEREO, GLX_DONT_CARE);
- } else {
- ADD2(GLX_STEREO, (ppfd->dwFlags & PFD_STEREO) ? TRUE : FALSE);
+
+ /* Get a list containing all supported FB configurations */
+ cfgs = pglXChooseFBConfig(gdi_display, DefaultScreen(gdi_display), NULL, &nCfgs);
+ if (NULL == cfgs || 0 == nCfgs) {
+ ERR("glXChooseFBConfig returns NULL (glError: %d)\n", pglGetError());
+ goto choose_exit;
}
-
- /** Attributes List End */
- att_list[att_pos] = None;
- wine_tsx11_lock();
- {
- int nCfgs = 0;
- int gl_test = 0;
- int fmt_id;
+ /* In case an fbconfig was found, check if it matches to the requirements of the ppfd */
+ if(!get_fbconfig_from_visual(visual, &fmt_id, &fmt_index)) {
+ ERR("Can't find a matching FBCONFIG_ID for VISUAL_ID 0x%lx!\n", visual->visualid);
+ } else {
+ int dwFlags = 0;
+ int iPixelType = 0;
+ int value = 0;
+
+ /* Color bits; what do with those?? */
+ /* pglXGetFBConfigAttrib(gdi_display, cfgs[cfg], GLX_BUFFER_SIZE, &value); */
+ /* ppfdCandidate.cColorBits = value; */
+
+ /* Pixel type */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_RENDER_TYPE, &value);
+ if (value & GLX_RGBA_BIT)
+ iPixelType = PFD_TYPE_RGBA;
+ else
+ iPixelType = PFD_TYPE_COLORINDEX;
- GLXFBConfig* cfgs_fmt = NULL;
- int nCfgs_fmt = 0;
- int tmp_fmt_id;
- UINT it_fmt;
+ if (ppfd->iPixelType != iPixelType) {
+ goto choose_exit;
+ }
- cfgs = pglXChooseFBConfig(gdi_display, DefaultScreen(gdi_display), att_list, &nCfgs);
- /**
- * if we have facultative flags and we failed, try without
- * as MSDN said
- *
- * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/ntopnglr_2qb8.asp
- */
- if ((NULL == cfgs || 0 == nCfgs) && att_pos > att_pos_fac) {
- att_list[att_pos_fac] = None;
- cfgs = pglXChooseFBConfig(gdi_display, DefaultScreen(gdi_display), att_list, &nCfgs);
+ /* Doublebuffer */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_DOUBLEBUFFER, &value); if (value) dwFlags |= PFD_DOUBLEBUFFER;
+ if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE)) {
+ if ((ppfd->dwFlags & PFD_DOUBLEBUFFER) != (dwFlags & PFD_DOUBLEBUFFER)) {
+ goto choose_exit;
+ }
}
- if (NULL == cfgs || 0 == nCfgs) {
- ERR("glXChooseFBConfig returns NULL (glError: %d)\n", pglGetError());
- ret = 0;
- goto choose_exit;
+ /* Stereo */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_STEREO, &value); if (value) dwFlags |= PFD_STEREO;
+ if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE)) {
+ if ((ppfd->dwFlags & PFD_STEREO) != (dwFlags & PFD_STEREO)) {
+ goto choose_exit;
+ }
}
-
- gl_test = pglXGetFBConfigAttrib(gdi_display, cfgs[0], GLX_FBCONFIG_ID, &fmt_id);
- if (gl_test) {
- ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
- ret = 0;
+
+ /* Alpha bits */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_ALPHA_SIZE, &value);
+ if (ppfd->iPixelType==PFD_TYPE_RGBA && ppfd->cAlphaBits && !value) {
goto choose_exit;
}
-
- cfgs_fmt = pglXGetFBConfigs(gdi_display, DefaultScreen(gdi_display), &nCfgs_fmt);
- if (NULL == cfgs_fmt) {
- ERR("Failed to get All FB Configs\n");
- ret = 0;
+
+ /* Depth bits */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_DEPTH_SIZE, &value);
+ if (ppfd->cDepthBits && !value) {
goto choose_exit;
}
- for (it_fmt = 0; it_fmt < nCfgs_fmt; ++it_fmt) {
- gl_test = pglXGetFBConfigAttrib(gdi_display, cfgs_fmt[it_fmt], GLX_FBCONFIG_ID, &tmp_fmt_id);
- if (gl_test) {
- ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
- XFree(cfgs_fmt);
- ret = 0;
- goto choose_exit;
- }
- if (fmt_id == tmp_fmt_id) {
- ret = it_fmt + 1;
- break ;
- }
+ /* Stencil bits */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_STENCIL_SIZE, &value);
+ if (ppfd->cStencilBits && !value) {
+ goto choose_exit;
}
- if (it_fmt == nCfgs_fmt) {
- ERR("Failed to get valid fmt for FBCONFIG_ID(%d)\n", fmt_id);
- ret = 0;
+
+ /* Aux buffers */
+ pglXGetFBConfigAttrib(gdi_display, cfgs[fmt_index], GLX_AUX_BUFFERS, &value);
+ if (ppfd->cAuxBuffers && !value) {
+ goto choose_exit;
}
- XFree(cfgs_fmt);
+
+ /* When we pass all the checks we have found a matching format :) */
+ ret = 1;
+ TRACE("Succesfully found a matching mode, returning index: %d\n", ret);
}
choose_exit:
+ if(!ret)
+ TRACE("No matching mode was found returning 0\n");
+
if (NULL != cfgs) XFree(cfgs);
+ if (NULL != visual) XFree(visual);
wine_tsx11_unlock();
return ret;
}
@@ -358,6 +378,14 @@
return 0; /* unespected error */
}
+ /* This function allways reports the total number of supported pixel formats.
+ * At the moment we only support the pixel format corresponding to the main
+ * visual which got created at x11drv initialization. More formats could be
+ * supported if there was a way to recreate x11 windows in x11drv.
+ * Because we only support one format nCfgs needs to be set to 1.
+ */
+ nCfgs = 1;
+
if (ppfd == NULL) {
/* The application is only querying the number of visuals */
wine_tsx11_lock();
@@ -377,6 +405,12 @@
return 0;
}
+ /* Retrieve the index in the FBConfig table corresponding to the visual ID from the main visual */
+ if(!get_pixel_format_index_from_main_visual(&iPixelFormat)) {
+ ERR("Can't find a valid pixel format index from the main visual, expect problems!\n");
+ return 0;
+ }
+
ret = nCfgs;
cur = cfgs[iPixelFormat - 1];
@@ -481,6 +515,15 @@
const PIXELFORMATDESCRIPTOR *ppfd) {
TRACE("(%p,%d,%p)\n", physDev, iPixelFormat, ppfd);
+ /* At the moment we only support the pixelformat corresponding to the main
+ * x11drv visual which got created at x11drv initialization. More formats
+ * can be supported if there was a way to recreate x11 windows in x11drv
+ */
+ if(iPixelFormat != 1) {
+ TRACE("Invalid iPixelFormat: %d\n", iPixelFormat);
+ return 0;
+ }
+
physDev->current_pf = iPixelFormat;
if (TRACE_ON(opengl)) {
@@ -490,6 +533,11 @@
int value;
int gl_test = 0;
+ if(!get_pixel_format_index_from_main_visual(&iPixelFormat)) {
+ ERR("Can't find a valid pixel format index from the main visual, expect problems!\n");
+ return TRUE; /* Return true because the SetPixelFormat stuff itself passed */
+ }
+
/*
* How to test if hdc current drawable is compatible (visual/FBConfig) ?
*
@@ -528,19 +576,13 @@
{
GLXPixmap ret;
XVisualInfo *vis;
- XVisualInfo template;
- int num;
- GLXFBConfig *cfgs;
wine_tsx11_lock();
- cfgs = pglXGetFBConfigs(gdi_display, DefaultScreen(gdi_display), &num);
- pglXGetFBConfigAttrib(gdi_display, cfgs[physDev->current_pf - 1], GLX_VISUAL_ID, (int *)&template.visualid);
-
- vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
+ /* At the moment we can only use our main visual for OpenGL stuff */
+ vis = X11DRV_setup_opengl_visual(gdi_display);
ret = pglXCreateGLXPixmap(gdi_display, vis, physDev->bitmap->pixmap);
XFree(vis);
- XFree(cfgs);
wine_tsx11_unlock();
TRACE("return %lx\n", ret);
return ret;