From: Zhiyi Zhang <zzhang@codeweavers.com> 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. --- dlls/gdi32/tests/bitmap.c | 6 ------ dlls/win32u/dib.c | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index 9040f6c0f41..63fe5eae16a 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -2447,19 +2447,15 @@ static void test_GetDIBits(void) } else { - todo_wine ok(lines == 0, "GetDIBits succeeded.\n"); - todo_wine_if(depths[i] == 15 || depths[i] == 16) ok(*(unsigned int *)bi->bmiColors == 0, "Got unexpected bmiColors %#x\n", *(unsigned int *)bi->bmiColors); /* lines > 0. Still fails */ lines = GetDIBits(hdc, hbmp, 0, 1, NULL, bi, DIB_RGB_COLORS); - todo_wine ok(lines == 0, "GetDIBits failed.\n"); /* buf != NULL. Still fails */ lines = GetDIBits(hdc, hbmp, 0, 1, buf, bi, DIB_RGB_COLORS); - todo_wine ok(lines == 0, "GetDIBits failed.\n"); /* Reset biBitCount to 0. Now it succeeds */ @@ -2479,7 +2475,6 @@ static void test_GetDIBits(void) if (depths[i] == 1 || depths[i] == 32) ok(lines == 1, "GetDIBits failed.\n"); else - todo_wine_if(depths[i] != 2 && depths[i] != 15) ok(lines == 0, "GetDIBits succeeded.\n"); /* Same result when using a memory DC so it's not related the display DC */ @@ -2495,7 +2490,6 @@ static void test_GetDIBits(void) if (depths[i] == 1 || depths[i] == 32) ok(lines == 1, "GetDIBits failed.\n"); else - todo_wine_if(depths[i] != 2 && depths[i] != 15) ok(lines == 0, "GetDIBits succeeded.\n"); DeleteDC(mem_dc); diff --git a/dlls/win32u/dib.c b/dlls/win32u/dib.c index 8a0d064cd90..8473ae3c429 100644 --- a/dlls/win32u/dib.c +++ b/dlls/win32u/dib.c @@ -1348,6 +1348,9 @@ INT WINAPI NtGdiGetDIBitsInternal( HDC hdc, HBITMAP hbitmap, UINT startscan, UIN if (err) goto done; + if (!is_bitmapobj_dib( bmp ) && (src_info->bmiHeader.biBitCount != 1 && src_info->bmiHeader.biBitCount != 32)) + goto done; + /* fill out the src colour table, if it needs one */ if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0) fill_default_color_table( src_info ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10697