[PATCH] Native opengl32 seems to consider values set to 0 in the pixel format descriptor as DONTCARE. The attached test case proofs the behavior and this fixes a natsy bug in Serious Sam TSE.

Roderick Colenbrander thunderbird2k at gmx.net
Mon Mar 31 17:18:14 CDT 2008


---
 dlls/opengl32/tests/opengl.c |   75 +++++++++++++++++++
 dlls/winex11.drv/opengl.c    |  165 +++++++++++++++++++++++-------------------
 2 files changed, 164 insertions(+), 76 deletions(-)

diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c
index 0200dfd..4da7fd7 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 b6b3fc7..5a0469c 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;
+            }
         }
     }
 
-- 
1.5.3.4


--========GMX122311206994897638898--



More information about the wine-patches mailing list