624a73bc
by Zhiyi Zhang at 2026-04-21T21:40:31+02:00
win32u: Reject DDBs that are not 1-bit or 32-bit for GetDIBits().
SDL3 applications depend on this to not overwrite the depth of its internal display mode. Fix SDL3
applications using the native display mode instead of the specified display mode when restoring to
fullscreen from focus loss for the first time and the specific display mode is 16-bit.
Please see `WIN_UpdateDisplayMode()` in the SDL3 source code.
```c
static void WIN_UpdateDisplayMode(SDL_VideoDevice *_this, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *mode)
{
...
if (index == ENUM_CURRENT_SETTINGS && (hdc = CreateDCW(deviceName, NULL, NULL, NULL)) != NULL) {
char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
LPBITMAPINFO bmi;
HBITMAP hbm;
SDL_zeroa(bmi_data);
bmi = (LPBITMAPINFO)bmi_data;
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
hbm = CreateCompatibleBitmap(hdc, 1, 1);
GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
DeleteObject(hbm);
DeleteDC(hdc);
if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
switch (*(Uint32 *)bmi->bmiColors) {
...
case 0x7C00:
mode->format = SDL_PIXELFORMAT_XRGB1555;
break;
}
...
```
When entering a 16-bit display mode, `WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode);`
is called in `WIN_SetDisplayMode()`. The second `GetDIBits()` call in `WIN_UpdateDisplayMode()`
succeeds and ends up overwriting the format to SDL_PIXELFORMAT_XRGB1555, which is a 15-bit display
mode. So when SDL3 tries to enter the 16-bit display mode again, it won't be found because it's now
15-bit. Tests show that the second `GetDIBits()` should fail and thus leave the display mode format
unchanged.