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