Skip to content

Accept a 24 bpp desktop when a 32 bpp mode is requested - #11

Open
f1nalspace wants to merge 1 commit into
JHRobotics:mainfrom
f1nalspace:pr/fullscreen-24bpp
Open

f1nalspace wants to merge 1 commit into
JHRobotics:mainfrom
f1nalspace:pr/fullscreen-24bpp

Conversation

@f1nalspace

Copy link
Copy Markdown

Creating a fullscreen DirectDraw or Direct3D device fails on a display driver whose
desktop runs at 24 bpp and that has no 32 bpp mode at all. The application usually does
not survive it: ddraw_create_swapchain() fails, ddraw7_SetCooperativeLevel() only
logs the error and carries on, and the next CreateSurface() for the primary surface
dereferences the swapchain that was never created.

wined3d_set_adapter_display_mode() derives the depth to set from the format:

new_mode.dmBitsPerPel = format->byte_count * CHAR_BIT;

For WINED3DFMT_B8G8R8X8_UNORM that is always 32. But pixelformat_for_depth() maps
both 24 and 32 bpp to that same format:

case 24: return WINED3DFMT_B8G8R8X8_UNORM;
case 32: return WINED3DFMT_B8G8R8X8_UNORM;

So on a 24 bpp desktop the "only change the mode if necessary" test compares 24 against
32, decides a mode change is needed, and calls ChangeDisplaySettingsEx() with a depth
the driver does not offer. It answers DISP_CHANGE_BADMODE, and the swapchain is gone.

This changes two things:

  • the redundancy test compares the format rather than the raw bit count, so a 24 bpp
    desktop and a 32 bpp request count as the same mode and no change is attempted;
  • where a mode change really is needed, DISP_CHANGE_BADMODE at 32 bpp is retried at
    24 bpp, since both carry the same D3D format.

Found under QEMU with the Cirrus GD5446 driver on Windows XP, whose modes are 8/16/24 bpp.
Before the change every fullscreen DirectDraw application crashed on the primary surface;
after it the same test program enumerates the HAL and renders at 9739 FPS. The relevant
lines from a build with logging enabled:

warn:d3d:wined3d_set_adapter_display_mode Setting mode on "\\.\DISPLAY1":
    want 800x600 32bpp @0Hz fields 0x1c0000, current 800x600 24bpp @60Hz.
warn:d3d:wined3d_set_adapter_display_mode ChangeDisplaySettingsEx returned -2.
warn:d3d:swapchain_init Failed to set display mode, hr 0x8876086a.
warn:d3d:wined3d_device_init_3d Failed to create implicit swapchain

How to reproduce, without the qemu-3dfx pieces: a Windows 2000/XP guest on QEMU's
-device cirrus-vga, whose XP driver offers 8/16/24 bpp and no 32 bpp at all, so the
desktop sits at 24 bpp. Any application that creates a fullscreen device through
wined3d.dll runs into it — the mode change is attempted in
wined3d_set_adapter_display_mode(), below both winedd.dll and wined8.dll, so
DirectDraw and Direct3D 8 are affected alike. A windowed device never gets there,
which is why the same DLLs pass every windowed test.

What was observed here is a small DirectDraw/Direct3D 7 test program rather than a game:
https://github.com/f1nalspace/qemu-3dfx/tree/master/tools/ddcube. It enumerates the
driver and then creates a fullscreen device — without this change it never gets a
swapchain and dies on the primary surface, with it the same binary renders at 9739 FPS.

Both depths map to WINED3DFMT_B8G8R8X8_UNORM, so a mode change is neither
needed nor possible on a driver that offers only one of them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant