diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 0200dfdedaf..29f9ccec7d8 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -176,6 +176,80 @@ static void test_pbuffers(HDC hdc) else skip("Pbuffer test for offscreen pixelformat skipped as no offscreen-only format with pbuffer capabilities has been found\n"); } +static void test_choosepixelformat(HDC hdc) +{ + int iPixelFormat; + int nFormats; + BOOL found=FALSE; + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, /* version */ + PFD_DRAW_TO_WINDOW | + PFD_SUPPORT_OPENGL | + PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, /* 32-bit color depth */ + 0, 0, 0, 0, 0, 0, /* color bits */ + 0, /* alpha buffer */ + 0, /* shift bit */ + 0, /* accumulation buffer */ + 0, 0, 0, 0, /* accum bits */ + 0, /* z-buffer */ + 0, /* stencil buffer */ + 0, /* auxiliary buffer */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* layer masks */ + }; + + /* Below we test the behavior of ChoosePixelFormat. As documented on MSDN this + * function doesn't give any guarantees about its outcome. Programs should not + * rely on weird behavior of the function but unfortunately a few programs like + * e.g. Serious Sam TSE rely on it. + * + * MSDN documents of a few flags like double buffering / stereo that they can be set to DONTCARE. + * It appears that a 0 value on other options like alpha, red, .. means DONTCARE. The hypothesis + * is that ChoosePixelFormat returns the first available format which matches the criteria. + * + * This test tries to proof the DONTCARE behavior by passing an almost 'empty' pfd to + * ChoosePixelFormat. The pfd only has some really needed flags (RGBA, window, double buffer) set. + * Further a 32 bit color buffer has been requested. The idea is that when a format with e.g. depth or stencil bits + * is returned, while there are also 'better' candidates in the list wihtout them (but located AFTER the returned one) + * that an option set to zero means DONTCARE. We try to proof this by checking the aux/depth/stencil bits. + * Proofing this behavior for the color bits isn't possible as all formats have red/green/blue/(alpha), so we assume + * that if it holds for aux/depth/stencil it also holds for the others. + * + * The test below passes at least on various ATI cards (rv250, r300) and Nvidia cards. + */ + + iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if(iPixelFormat) { + PIXELFORMATDESCRIPTOR pfd_tmp; + BOOL res; + int i; + + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + res = DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + nFormats = DescribePixelFormat(hdc, 0, 0, NULL); + /* Start testing from iPixelFormat, second formats start counting from index=1, so use '<=' */ + for(i=iPixelFormat; i<=nFormats; i++) { + memset(&pfd_tmp, 0, sizeof(PIXELFORMATDESCRIPTOR)); + res = DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd_tmp); + if(!res) + continue; + + /* Check if there is a format which better matches the requirements */ + if((pfd_tmp.cAuxBuffers < pfd.cAuxBuffers) || (pfd_tmp.cDepthBits < pfd.cDepthBits) || (pfd_tmp.cStencilBits < pfd.cStencilBits)) + found = TRUE; + } + + /* When found=TRUE we were able to confirm our hypothesis */ + ok(found == TRUE, "Unable to confirm DONTCARE behavior of unset pixelformatdescriptor flags\n"); + } + +} + static void test_setpixelformat(HDC winhdc) { int res = 0; @@ -398,6 +472,7 @@ START_TEST(opengl) ok(res, "wglMakeCurrent failed!\n"); init_functions(); + test_choosepixelformat(hdc); test_setpixelformat(hdc); test_colorbits(hdc); test_gdi_dbuf(hdc); diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index b6b3fc7b30e..5a0469c994b 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1145,96 +1145,109 @@ int X11DRV_ChoosePixelFormat(X11DRV_PDEVICE *physDev, /* Below we will do a number of checks to select the 'best' pixelformat. * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers. * The code works by trying to match the most important options as close as possible. - * When a reasonable format is found, we will try to match more options. */ + * When a reasonable format is found, we will try to match more options. + * It appears (see the opengl32 test) that Windows opengl drivers ignore options + * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered + * as DONTCARE. At least Serious Sam TSE relies on this behavior. */ /* Color bits */ - if( ((ppfd->cColorBits > bestColor) && (color > bestColor)) || - ((color >= ppfd->cColorBits) && (color < bestColor)) ) - { - bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; - bestStereo = dwFlags & PFD_STEREO; - bestAlpha = alpha; - bestColor = color; - bestDepth = depth; - bestStencil = stencil; - bestAux = aux; - bestFormat = i; - continue; - } else if(bestColor != color) { /* Do further checks if the format is compatible */ - TRACE("color mismatch for iPixelFormat=%d\n", i+1); - continue; + if(ppfd->cColorBits) { + if( ((ppfd->cColorBits > bestColor) && (color > bestColor)) || + ((color >= ppfd->cColorBits) && (color < bestColor)) ) + { + bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; + bestStereo = dwFlags & PFD_STEREO; + bestAlpha = alpha; + bestColor = color; + bestDepth = depth; + bestStencil = stencil; + bestAux = aux; + bestFormat = i; + continue; + } else if(bestColor != color) { /* Do further checks if the format is compatible */ + TRACE("color mismatch for iPixelFormat=%d\n", i+1); + continue; + } } /* Alpha bits */ - if( ((ppfd->cAlphaBits > bestAlpha) && (alpha > bestAlpha)) || - ((alpha >= ppfd->cAlphaBits) && (alpha < bestAlpha)) ) - { - bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; - bestStereo = dwFlags & PFD_STEREO; - bestAlpha = alpha; - bestColor = color; - bestDepth = depth; - bestStencil = stencil; - bestAux = aux; - bestFormat = i; - continue; - } else if(bestAlpha != alpha) { - TRACE("alpha mismatch for iPixelFormat=%d\n", i+1); - continue; + if(ppfd->cAlphaBits) { + if( ((ppfd->cAlphaBits > bestAlpha) && (alpha > bestAlpha)) || + ((alpha >= ppfd->cAlphaBits) && (alpha < bestAlpha)) ) + { + bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; + bestStereo = dwFlags & PFD_STEREO; + bestAlpha = alpha; + bestColor = color; + bestDepth = depth; + bestStencil = stencil; + bestAux = aux; + bestFormat = i; + continue; + } else if(bestAlpha != alpha) { + TRACE("alpha mismatch for iPixelFormat=%d\n", i+1); + continue; + } } /* Depth bits */ - if( ((ppfd->cDepthBits > bestDepth) && (depth > bestDepth)) || - ((depth >= ppfd->cDepthBits) && (depth < bestDepth)) ) - { - bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; - bestStereo = dwFlags & PFD_STEREO; - bestAlpha = alpha; - bestColor = color; - bestDepth = depth; - bestStencil = stencil; - bestAux = aux; - bestFormat = i; - continue; - } else if(bestDepth != depth) { - TRACE("depth mismatch for iPixelFormat=%d\n", i+1); - continue; + if(ppfd->cDepthBits) { + if( ((ppfd->cDepthBits > bestDepth) && (depth > bestDepth)) || + ((depth >= ppfd->cDepthBits) && (depth < bestDepth)) ) + { + bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; + bestStereo = dwFlags & PFD_STEREO; + bestAlpha = alpha; + bestColor = color; + bestDepth = depth; + bestStencil = stencil; + bestAux = aux; + bestFormat = i; + continue; + } else if(bestDepth != depth) { + TRACE("depth mismatch for iPixelFormat=%d\n", i+1); + continue; + } } /* Stencil bits */ - if( ((ppfd->cStencilBits > bestStencil) && (stencil > bestStencil)) || - ((stencil >= ppfd->cStencilBits) && (stencil < bestStencil)) ) - { - bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; - bestStereo = dwFlags & PFD_STEREO; - bestAlpha = alpha; - bestColor = color; - bestDepth = depth; - bestStencil = stencil; - bestAux = aux; - bestFormat = i; - continue; - } else if(bestStencil != stencil) { - TRACE("stencil mismatch for iPixelFormat=%d\n", i+1); - continue; + if(ppfd->cStencilBits) { + if( ((ppfd->cStencilBits > bestStencil) && (stencil > bestStencil)) || + ((stencil >= ppfd->cStencilBits) && (stencil < bestStencil)) ) + { + bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; + bestStereo = dwFlags & PFD_STEREO; + bestAlpha = alpha; + bestColor = color; + bestDepth = depth; + bestStencil = stencil; + bestAux = aux; + bestFormat = i; + continue; + } else if(bestStencil != stencil) { + TRACE("stencil mismatch for iPixelFormat=%d\n", i+1); + continue; + } } /* Aux buffers */ - if( ((ppfd->cAuxBuffers > bestAux) && (aux > bestAux)) || - ((aux >= ppfd->cAuxBuffers) && (aux < bestAux)) ) - { - bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; - bestStereo = dwFlags & PFD_STEREO; - bestAlpha = alpha; - bestColor = color; - bestDepth = depth; - bestStencil = stencil; - bestAux = aux; - bestFormat = i; - continue; - } else if(bestAux != aux) { - TRACE("aux mismatch for iPixelFormat=%d\n", i+1); - continue; + if(ppfd->cAuxBuffers) { + if( ((ppfd->cAuxBuffers > bestAux) && (aux > bestAux)) || + ((aux >= ppfd->cAuxBuffers) && (aux < bestAux)) ) + { + bestDBuffer = dwFlags & PFD_DOUBLEBUFFER; + bestStereo = dwFlags & PFD_STEREO; + bestAlpha = alpha; + bestColor = color; + bestDepth = depth; + bestStencil = stencil; + bestAux = aux; + bestFormat = i; + continue; + } else if(bestAux != aux) { + TRACE("aux mismatch for iPixelFormat=%d\n", i+1); + continue; + } } }