Paul Gofman : winex11.drv: Prioritize smaller depth formats when zero depth is requested in X11DRV_wglChoosePixelFormatARB().

Alexandre Julliard julliard at winehq.org
Thu Mar 4 15:53:38 CST 2021


Module: wine
Branch: master
Commit: e392e0ac2846edc25610723c19d6a796372017e1
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e392e0ac2846edc25610723c19d6a796372017e1

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Wed Feb 24 17:04:53 2021 +0300

winex11.drv: Prioritize smaller depth formats when zero depth is requested in X11DRV_wglChoosePixelFormatARB().

Fixes Ancient Cities' black screen on Nvidia.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/opengl32/tests/opengl.c |  57 +++++++++++++++++++++
 dlls/winex11.drv/opengl.c    | 116 +++++++++++++++++++++++++++++++------------
 2 files changed, 142 insertions(+), 31 deletions(-)

diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c
index e93636ed75e..314fa11225d 100644
--- a/dlls/opengl32/tests/opengl.c
+++ b/dlls/opengl32/tests/opengl.c
@@ -1764,6 +1764,62 @@ static void test_swap_control(HDC oldhdc)
     wglMakeCurrent(oldhdc, oldctx);
 }
 
+static void test_wglChoosePixelFormatARB(HDC hdc)
+{
+    static int attrib_list[] =
+    {
+        WGL_DRAW_TO_WINDOW_ARB, 1,
+        WGL_SUPPORT_OPENGL_ARB, 1,
+        0
+    };
+
+    PIXELFORMATDESCRIPTOR fmt, last_fmt;
+    BYTE depth, last_depth;
+    UINT format_count;
+    int formats[1024];
+    unsigned int i;
+    int res;
+
+    if (!pwglChoosePixelFormatARB)
+    {
+        skip("wglChoosePixelFormatARB is not available\n");
+        return;
+    }
+
+    format_count = 0;
+    res = pwglChoosePixelFormatARB(hdc, attrib_list, NULL, ARRAY_SIZE(formats), formats, &format_count);
+    ok(res, "Got unexpected result %d.\n", res);
+
+    memset(&last_fmt, 0, sizeof(last_fmt));
+    last_depth = 0;
+
+    for (i = 0; i < format_count; ++i)
+    {
+        memset(&fmt, 0, sizeof(fmt));
+        if (!DescribePixelFormat(hdc, formats[i], sizeof(fmt), &fmt)
+                || (fmt.dwFlags & PFD_GENERIC_FORMAT))
+        {
+            memset(&fmt, 0, sizeof(fmt));
+            continue;
+        }
+
+        depth = fmt.cDepthBits;
+        fmt.cDepthBits = 0;
+        fmt.cStencilBits = 0;
+
+        if (memcmp(&fmt, &last_fmt, sizeof(fmt)))
+        {
+            last_fmt = fmt;
+            last_depth = depth;
+        }
+        else
+        {
+            ok(last_depth <= depth, "Got unexpected depth %u, last_depth %u, i %u, format %u.\n",
+                    depth, last_depth, i, formats[i]);
+        }
+    }
+}
+
 START_TEST(opengl)
 {
     HWND hwnd;
@@ -1858,6 +1914,7 @@ START_TEST(opengl)
         }
 
         test_choosepixelformat();
+        test_wglChoosePixelFormatARB(hdc);
         test_debug_message_callback();
         test_setpixelformat(hdc);
         test_destroy(hdc);
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 373182dec44..c44c587bf14 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -40,6 +40,7 @@
 #include "x11drv.h"
 #include "xcomposite.h"
 #include "winternl.h"
+#include "wine/heap.h"
 #include "wine/debug.h"
 
 #ifdef SONAME_LIBGL
@@ -2486,6 +2487,37 @@ static BOOL X11DRV_wglSetPbufferAttribARB( struct wgl_pbuffer *object, const int
     return ret;
 }
 
+struct choose_pixel_format_arb_format
+{
+    int format;
+    int original_index;
+    PIXELFORMATDESCRIPTOR pfd;
+    int depth, stencil;
+};
+
+static int compare_formats(const void *a, const void *b)
+{
+    /* Order formats so that onscreen formats go first. Then, if no depth bits requested,
+     * prioritize formats with smaller depth within the original sort order with respect to
+     * other attributes. */
+    const struct choose_pixel_format_arb_format *fmt_a = a, *fmt_b = b;
+    BOOL offscreen_a, offscreen_b;
+
+    offscreen_a = fmt_a->format > nb_onscreen_formats;
+    offscreen_b = fmt_b->format > nb_onscreen_formats;
+
+    if (offscreen_a != offscreen_b)
+        return offscreen_a - offscreen_b;
+    if (memcmp(&fmt_a->pfd, &fmt_b->pfd, sizeof(fmt_a->pfd)))
+        return fmt_a->original_index - fmt_b->original_index;
+    if (fmt_a->depth != fmt_b->depth)
+        return fmt_a->depth - fmt_b->depth;
+    if (fmt_a->stencil != fmt_b->stencil)
+        return fmt_a->stencil - fmt_b->stencil;
+
+    return fmt_a->original_index - fmt_b->original_index;
+}
+
 /**
  * X11DRV_wglChoosePixelFormatARB
  *
@@ -2494,17 +2526,15 @@ static BOOL X11DRV_wglSetPbufferAttribARB( struct wgl_pbuffer *object, const int
 static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList,
                                             UINT nMaxFormats, int *piFormats, UINT *nNumFormats )
 {
+    struct choose_pixel_format_arb_format *formats;
+    int it, i, format_count;
+    BYTE depth_bits = 0;
+    GLXFBConfig* cfgs;
+    DWORD dwFlags = 0;
     int attribs[256];
     int nAttribs = 0;
-    GLXFBConfig* cfgs;
     int nCfgs = 0;
-    int it;
     int fmt_id;
-    int start, end;
-    UINT pfmt_it = 0;
-    int run;
-    int i;
-    DWORD dwFlags = 0;
 
     TRACE("(%p, %p, %p, %d, %p, %p): hackish\n", hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats);
     if (NULL != pfAttribFList) {
@@ -2548,6 +2578,10 @@ static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, c
                 if(piAttribIList[i+1])
                     dwFlags |= PFD_SUPPORT_GDI;
                 break;
+            case WGL_DEPTH_BITS_ARB:
+                depth_bits = piAttribIList[i+1];
+                break;
+
         }
     }
 
@@ -2558,37 +2592,57 @@ static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, c
         return GL_FALSE;
     }
 
-    /* Loop through all matching formats and check if they are suitable.
-     * Note that this function should at max return nMaxFormats different formats */
-    for(run=0; run < 2; run++)
+    if (!(formats = heap_alloc(nCfgs * sizeof(*formats))))
+    {
+        ERR("No memory.\n");
+        XFree(cfgs);
+        return GL_FALSE;
+    }
+
+    format_count = 0;
+    for (it = 0; it < nCfgs; ++it)
     {
-        for (it = 0; it < nCfgs && pfmt_it < nMaxFormats; ++it)
+        struct choose_pixel_format_arb_format *format;
+
+        if (pglXGetFBConfigAttrib(gdi_display, cfgs[it], GLX_FBCONFIG_ID, &fmt_id))
         {
-            if (pglXGetFBConfigAttrib(gdi_display, cfgs[it], GLX_FBCONFIG_ID, &fmt_id))
-            {
-                ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
-                continue;
-            }
+            ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
+            continue;
+        }
 
-            /* During the first run we only want onscreen formats and during the second only offscreen */
-            start = run == 1 ? nb_onscreen_formats : 0;
-            end = run == 1 ? nb_pixel_formats : nb_onscreen_formats;
+        for (i = 0; i < nb_pixel_formats; ++i)
+            if (pixel_formats[i].fmt_id == fmt_id)
+                break;
 
-            for (i = start; i < end; i++)
-            {
-                if (pixel_formats[i].fmt_id == fmt_id && (pixel_formats[i].dwFlags & dwFlags) == dwFlags)
-                {
-                    piFormats[pfmt_it++] = i + 1;
-                    TRACE("at %d/%d found FBCONFIG_ID 0x%x (%d)\n",
-                          it + 1, nCfgs, fmt_id, i + 1);
-                    break;
-                }
-            }
+        if (i == nb_pixel_formats)
+            continue;
+
+        format = &formats[format_count];
+        format->format = i + 1;
+        format->original_index = it;
+
+        memset(&format->pfd, 0, sizeof(format->pfd));
+        if (!describe_pixel_format(format->format, &format->pfd, TRUE))
+            ERR("describe_pixel_format failed, format %d.\n", format->format);
+
+        format->depth = format->pfd.cDepthBits;
+        format->stencil = format->pfd.cStencilBits;
+        if (!depth_bits && !(format->pfd.dwFlags & PFD_GENERIC_FORMAT))
+        {
+            format->pfd.cDepthBits = 0;
+            format->pfd.cStencilBits = 0;
         }
+
+        ++format_count;
     }
 
-    *nNumFormats = pfmt_it;
-    /** free list */
+    qsort(formats, format_count, sizeof(*formats), compare_formats);
+
+    *nNumFormats = min(nMaxFormats, format_count);
+    for (i = 0; i < *nNumFormats; ++i)
+        piFormats[i] = formats[i].format;
+
+    heap_free(formats);
     XFree(cfgs);
     return GL_TRUE;
 }




More information about the wine-cvs mailing list