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