[PATCH v2 0/21] MR10567: wined3d: fix vk swapchain rendering too dark by supporting UNORM to SRGB...
wined3d: fix vk swapchain rendering too dark by supporting UNORM to SRGB conversion for brightness similar to gl This merge request addresses: https://bugs.winehq.org/show_bug.cgi?id=45364 Frostpunk is very dark Very dark rendering issues for Frostpunk seem to match the same problem for Vulkan renderer for "Against the Storm": - https://bugs.winehq.org/show_bug.cgi?id=58632 - https://bugs.winehq.org/attachment.cgi?id=80656 Running both games with gl renderer seems to fix excessive darkness: - https://bugs.winehq.org/attachment.cgi?id=80654 - https://bugs.winehq.org/attachment.cgi?id=80690 Vulkan renderer seems to be missing SRGB conversion handling availiable for GL renderer. GL renderer can be forced to render darker the same as Vulkan by bypassing EXT_TEXTURE_SRGB support for ./dlls/wined3d/utils.c: ``` @@ -3133,7 +3146,7 @@ static BOOL init_format_texture_info(struct wined3d_adapter *adapter, struct win continue; copy_format(adapter, &srgb_format->f, &format->f); +#if 000 if (gl_info->supported[EXT_TEXTURE_SRGB] && !(adapter->d3d_info.wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)) { @@ -3142,6 +3155,7 @@ static BOOL init_format_texture_info(struct wined3d_adapter *adapter, struct win format_set_caps(&srgb_format->f, WINED3D_FORMAT_CAP_SRGB_READ | WINED3D_FORMAT_CAP_SRGB_WRITE); query_internal_format(adapter, srgb_format, &format_texture_info[i], gl_info, TRUE); } +#endif } ``` This merge request patch allows Vulkan renderer to perform SRGB conversion for wined3d_swapchain_vk_select_vk_format() to mimic the GL capability. Changing VkSwapchainCreateInfoKHR imageColorSpace from VK_COLOR_SPACE_SRGB_NONLINEAR_KHR for `wined3d_swapchain_vk_create_vulkan_swapchain()` had no effect despite enabling VK_EXT_swapchain_colorspace for dlls/win32u/vulkan.c `convert_instance_create_info():` https://docs.vulkan.org/refpages/latest/refpages/source/VkColorSpaceKHR.html Therefore converting UNORM to SRGB was chosen similar to how the GL renderer seems to handle it: ``` static const struct wined3d_format_srgb_info format_srgb_info[] = { {WINED3DFMT_R8G8B8A8_UNORM_SRGB, WINED3DFMT_R8G8B8A8_UNORM}, {WINED3DFMT_BC1_UNORM_SRGB, WINED3DFMT_BC1_UNORM}, {WINED3DFMT_BC2_UNORM_SRGB, WINED3DFMT_BC2_UNORM}, {WINED3DFMT_BC3_UNORM_SRGB, WINED3DFMT_BC3_UNORM}, {WINED3DFMT_B8G8R8A8_UNORM_SRGB, WINED3DFMT_B8G8R8A8_UNORM}, {WINED3DFMT_B8G8R8X8_UNORM_SRGB, WINED3DFMT_B8G8R8X8_UNORM}, {WINED3DFMT_BC7_UNORM_SRGB, WINED3DFMT_BC7_UNORM}, }; ``` Its unclear whether SRGB conversion should always happen or only for particular games so the patch leaves the Vulkan renderer without SRGB conversion by default. Therefore the patch adds a new WINE_D3D_CONFIG flag named "vk_swap_srgb" to force the Vulkan renderer to perform SRGB conversion for the swapchain. By default vk_swap_srgb is set to FALSE or 0: `WINE_D3D_CONFIG=vk_swap_srgb=0,renderer=vulkan` To force vk_swap_srgb to TRUE or 1: `WINE_D3D_CONFIG=vk_swap_srgb=1,renderer=vulkan` For example, launching Frostpunk via the following after the patch fixes the dark rendering for Vulkan and appears brighter similar to the GL renderer: `WINEDEBUG=-all mangohud --dlsym WINE_D3D_CONFIG=csmt=0x1,renderer=vulkan,vk_swap_srgb=1 WINEPREFIX=/home/any/wine_stianlow_wow64_new_pfx ~/tmp/wine_stianlow_wow64_new_install/bin/wine /home/any/wine_stianlow_wow64_new_pfx/drive_c/GOG\ Games/Frostpunk/Frostpunk.exe` Some SRGB handling was added several years ago but not for mapping UNORM to SRGB that this patch adds: ``` 6f55c8d1c56 * wined3d: Use an sRGB fallback format for sRGB formats in wined3d_swapchain_vk_select_vk_format(). Author: Henri Verbeet <hverbeet@codeweavers.com> CommitDate: Wed Dec 9 16:29:28 2020 +0100 ``` If UNORM to SRGB should be enabled by default then this patch may be changed so that vk_swap_srgb defaults to TRUE. -- v2: wined3d: fix vk swapchain rendering too dark by supporting rtvs for swapchain back_buffers > 1 vbscript: Implement DateDiff built-in function. vbscript: Support assignment to chained array index expressions. vbscript: Coerce VT_EMPTY operands before Var* calls. vbscript/tests: Cover Dim/Sub shadowing of host members. server: Store the client page size in the process struct. msxml3/tests: Add some tests for selecting from detached nodes. msxml3/tests: Add a basic test for replaceChild() on attributes. msxml3/tests: Remove some refcount tests. msxml3: Handle baseName property for entity references. kernel32/tests: Avoid unused variables. advapi32/tests: Remove unused variable. msv1_0: Handle SEC_WINNT_AUTH_IDENTITY_EX. winhttp: Always queue async writes. win32u: Support OBJID_CLASSNAMEIDX in scrollbar controls. mf/session: Support asynchronous transforms. mf/tests: Add asynchronous transform tests. ntdll: Use debugstr_wn instead of debugstr_w in nt_to_unix_file_name. kernelbase: Run conhost.exe from c:\windows\system32 directory. Revert "wined3d: fix vk swapchain rendering too dark by supporting UNORM to SRGB conversion for brightness similar to gl" wined3d: fix vk swapchain rendering too dark by supporting UNORM to SRGB conversion for brightness similar to gl This merge request has too many patches to be relayed via email. Please visit the URL below to see the contents of the merge request. https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
Latest commit message more accurately reflects the problem of DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 unsupported vs vulkan sRGB mishandling which seems caused by it. sRGB mishandling fixed by handling DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 applies to swapchain generally for both vulkan and gl renderers vs prior patch which only applied specifically to vulkan renderer which did not consider supporting DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 as part of the solution. DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 support fixes vulkan rendering too dark but broke gl renderer with ARB_FRAMEBUFFER_SRGB=TRUE by causing opposite problem of rendering too bright. gl renderer with ARB_FRAMEBUFFER_SRGB=TRUE rendering too bright was fixed by calling glDisable(GL_FRAMEBUFFER_SRGB); before swapchain_blit() for swapchain_gl_present to prevent sRGB correction from being applied twice which redundantly causes rendering too bright. gl renderer with ARB_FRAMEBUFFER_SRGB=FALSE seems to correctly render regardless of DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 support and seems unaffected by this patch. Flickering occurred when supporting swapchain backbuffer_count > 1 for wined3d_render_target_view_gl_cs_init() and wined3d_render_target_view_vk_cs_init() which was fixed by removing calls to wined3d_swapchain_gl_rotate() and wined3d_swapchain_vk_rotate(). "Against the Storm" for win8 calls dxgi_factory_CreateSwapChainForHwnd() with format DXGI_FORMAT_R8G8B8A8_UNORM_SRGB but for win10 it calls with format DXGI_FORMAT_R8G8B8A8_UNORM. "Frostpunk" calls dxgi_factory_CreateSwapChainForHwnd() with format DXGI_FORMAT_R8G8B8A8_UNORM regardless of windows version. For both games, d3d11_device_CreateRenderTargetView() is called with the opposite sRGB compatible format of dxgi_factory_CreateSwapChainForHwnd. So swapchain with UNORM format has rendertarget SRGB format and vice versa. Without the patch d3d11_device_CreateRenderTargetView() fails for both games for win10 which results in darker graphics for vulkan. According to MS docs, buffercount >= 2 is required for DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3: https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/for-best-perfor... There seems to be some ambiguity about the meaning of DXGI_SWAP_CHAIN_DESC BufferCount. Many articles claim BufferCount = 1 corresponds to double buffering, but this official Microsoft doc shows BufferCount = 2 with comment explicitly stating that it corresponds to double buffering: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_e... It may be more complicated with the meaning varying across d3d versions and swap_effects. For example, wine d3d9 implementation seems to use wined3d_swapchain.front_buffer but d3d10+ seems to only ever use wined3d_swapchain.back_buffers which seems to imply that one is considered to replace wined3d_swapchain.front_buffer. Removal of wined3d_swapchain_gl_rotate() and wined3d_swapchain_vk_rotate() by the latest patch is concerning but unclear when they would every apply since wined3d_render_target_view_gl_cs_init() and wined3d_render_target_view_gl_cs_init() always prevented rtvs with backbuffer_count > 1. Plenty of articles mentioned that the backbuffers resources are automatically managed despite only index 0 ever referenced for swapchain rtv: https://stackoverflow.com/questions/71138727/how-to-create-render-target-vie... I tried to implement an automagical rotation of the backbuffer resources based on d3d12 which requires explicit indexing of the back_buffers by guessing that it may have been the way Microsoft handled it before exposing that hidden logic via d3d12 but it unfortunately still resulted in flickering for frostpunk.exe only and some laggy graphics. swapchain_gl_present() and swapchain_vk_present() both seem to ultimately perform blitting regardless of DXGI_SWAP_EFFECT FLIP so perhaps handling FLIP at wined3d level is less important than handling it at the vk and gl backend levels? swapchain_vk_present() calls wined3d_swapchain_vk_blit() which calls vkAcquireNextImageKHR() which always blits back_buffers[0] to vk_images[image_idx] so vk_images may handle back_buffer > 1 at that level. Likewise swapchain_gl_present() calls swapchain_blit() and wglSwapBuffers() which may handle similar back_buffer > 1 for gl. If anyone has more insight about why wined3d_swapchain_gl_rotate() and wined3d_swapchain_vk_rotate() are necessary, please let me know because docs seems limited. I noticed that DXVK has a similarly named function for rotating backbuffer resources and seems to have been based on Wine. Git logs indicate that wined3d_swapchain_gl_rotate() existed a while before wined3d_swapchain_vk_rotate() was added. wine-staging seems to only have one patch which may be related to DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL=0x3 support: wine-staging/patches/wined3d-rotate-WINED3D_SWAP_EFFECT_DISCARD/0001-wined3d-Do-not-rotate-WINED3D_SWAP_EFFECT_DISCARD-sw.patch ``` From 7df284bcf76788b078b4c43ce2de0c338b557e8a Mon Sep 17 00:00:00 2001 From: Henri Verbeet <hverbeet@codeweavers.com> Date: Thu, 13 May 2021 17:58:12 +0200 Subject: [PATCH] wined3d: Do not rotate WINED3D_SWAP_EFFECT_DISCARD swapchains. RenderDoc/Qt creates swapchains with 2 buffers, a front buffer and a back buffer, and the DISCARD swap effect. It doesn't redraw the back buffer after a Present(), seemingly expecting that the back buffer will only be copied to the front buffer, and otherwise remain unmodified. Incidentally, CEF seems to behave in a similar way. --- dlls/wined3d/swapchain.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 6b2ad8d6954..c0721067bd1 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -523,8 +523,9 @@ static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, str unsigned int i; static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE; - if (swapchain->state.desc.backbuffer_count < 2) - return; + if (swapchain->state.desc.swap_effect == WINED3D_SWAP_EFFECT_DISCARD + || swapchain->state.desc.backbuffer_count < 2) + return; texture_prev = wined3d_texture_gl(swapchain->back_buffers[0]); @@ -1177,7 +1178,8 @@ static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, str static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE; - if (swapchain->state.desc.backbuffer_count < 2) + if (swapchain->state.desc.swap_effect == WINED3D_SWAP_EFFECT_DISCARD + || swapchain->state.desc.backbuffer_count < 2) return; texture_prev = wined3d_texture_vk(swapchain->back_buffers[0]); -- ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139243
swapchain_vk_present() calls wined3d_swapchain_vk_blit() which calls vkAcquireNextImageKHR() which always blits back_buffers\[0\] to vk_images\[image_idx\] so vk_images may handle back_buffer \> 1 at that level.
These logs seem to indicate triple buffering handled at vulkan level which blits back_buffers[0] onto vulkan swapchain backbuffers and may fulfill wined3d_swapchain_vk_rotate(): 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 0 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 1 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 2 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 0 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 1 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 2 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139249
On Fri May 8 18:35:26 2026 +0000, Stian Low wrote:
swapchain_vk_present() calls wined3d_swapchain_vk_blit() which calls vkAcquireNextImageKHR() which always blits back_buffers\[0\] to vk_images\[image_idx\] so vk_images may handle back_buffer \> 1 at that level. These logs seem to indicate triple buffering handled at vulkan level which blits back_buffers[0] onto vulkan swapchain backbuffers and may fulfill wined3d_swapchain_vk_rotate()
01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 0 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 1 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 2 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 0 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 1 01e8:trace:d3d:wined3d_swapchain_vk_blit image_idx 2I attached screenshots of Frostpunk running via RenderDoc at https://bugs.winehq.org/show_bug.cgi?id=45364#c16 with and without the patch since it was mentioned by:
wine-staging/patches/wined3d-rotate-WINED3D_SWAP_EFFECT_DISCARD/0001-wined3d-Do-not-rotate-WINED3D_SWAP_EFFECT_DISCARD-sw.patch @hverbeet do you remember how to reproduce whatever bug the wine-staging patch was supposed to fix? RenderDoc v1.44 .exe seems to work the same regardless of this merge request patch with the only differences being the corrected graphics addressed by this patch. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139273
participants (1)
-
Stian Low (@stianlow)