[PATCH v5 0/3] 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. -- v5: wined3d: fix vk swapchain rendering too dark by supporting rtvs for swapchain back_buffers > 1 wined3d: revert fix vk swapchain rendering too dark by supporting UNORM to SRGB conversion for brightness similar to gl https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
From: Stian Low <wineryyyyy@gmail.com> --- dlls/wined3d/swapchain.c | 11 ++++++++--- dlls/wined3d/utils.c | 13 +++++++++++++ dlls/wined3d/wined3d_main.c | 6 ++++++ dlls/wined3d/wined3d_private.h | 2 ++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 4c20587b81d..ac61a6b64a0 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -755,6 +755,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v { struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device); const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc; + enum wined3d_format_id backbuffer_format; const struct wined3d_vk_info *vk_info; struct wined3d_adapter_vk *adapter_vk; const struct wined3d_format *format; @@ -768,7 +769,11 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v vk_physical_device = adapter_vk->physical_device; vk_info = &adapter_vk->vk_info; - if ((format = wined3d_get_format(&adapter_vk->a, desc->backbuffer_format, WINED3D_BIND_RENDER_TARGET))) + backbuffer_format = desc->backbuffer_format; + if (wined3d_settings.vk_swap_srgb) + backbuffer_format = wined3d_get_format_srgb(desc->backbuffer_format); + + if ((format = wined3d_get_format(&adapter_vk->a, backbuffer_format, WINED3D_BIND_RENDER_TARGET))) vk_format = wined3d_format_vk(format)->vk_format; else vk_format = VK_FORMAT_B8G8R8A8_UNORM; @@ -800,7 +805,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v { /* Try to create a swapchain with format conversion. */ vk_format = get_swapchain_fallback_format(vk_format); - WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format)); + WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(backbuffer_format)); for (i = 0; i < format_count; ++i) { if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) @@ -810,7 +815,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v free(vk_formats); if (i == format_count) { - FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format)); + FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(backbuffer_format)); return VK_FORMAT_UNDEFINED; } diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 0fb90ba3f18..1e2a3f09240 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1803,6 +1803,19 @@ static const struct wined3d_format_srgb_info format_srgb_info[] = {WINED3DFMT_BC7_UNORM_SRGB, WINED3DFMT_BC7_UNORM}, }; +enum wined3d_format_id wined3d_get_format_srgb(enum wined3d_format_id format_id) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(format_srgb_info); ++i) + { + if (format_srgb_info[i].base_format_id == format_id) + { + return format_srgb_info[i].srgb_format_id; + } + } + return format_id; +} + static inline int get_format_idx(enum wined3d_format_id format_id) { unsigned int i; diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 91d8dd567ff..402051ae2c3 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -129,6 +129,7 @@ struct wined3d_settings wined3d_settings = .max_sm_cs = UINT_MAX, .renderer = WINED3D_RENDERER_AUTO, .shader_backend = WINED3D_SHADER_BACKEND_AUTO, + .vk_swap_srgb = FALSE, }; enum wined3d_renderer CDECL wined3d_get_renderer(void) @@ -468,6 +469,11 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL) ERR_(winediag)("Using the HLSL-based FFP backend.\n"); wined3d_settings.ffp_hlsl = tmpvalue; } + if (!get_config_key_dword(hkey, appkey, env, "vk_swap_srgb", &tmpvalue) && tmpvalue) + { + TRACE("Forcing Vulkan Swapchain SRGB conversions.\n"); + wined3d_settings.vk_swap_srgb = TRUE; + } } if (appkey) RegCloseKey( appkey ); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index fa758c53cc1..5997a1d0ea4 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -485,6 +485,7 @@ struct wined3d_settings bool check_float_constants; bool cb_access_map_w; bool ffp_hlsl; + bool vk_swap_srgb; }; extern struct wined3d_settings wined3d_settings; @@ -4627,6 +4628,7 @@ struct wined3d_format enum wined3d_format_id typeless_id; }; +enum wined3d_format_id wined3d_get_format_srgb(enum wined3d_format_id format_id); const struct wined3d_format *wined3d_get_format(const struct wined3d_adapter *adapter, enum wined3d_format_id format_id, unsigned int bind_flags); enum wined3d_format_id wined3d_get_typed_format_id(const struct wined3d_adapter *adapter, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
From: Stian Low <wineryyyyy@gmail.com> This reverts commit cb7eb79780f633bddb75e4969300d2c921739213. --- dlls/wined3d/swapchain.c | 11 +++-------- dlls/wined3d/utils.c | 13 ------------- dlls/wined3d/wined3d_main.c | 6 ------ dlls/wined3d/wined3d_private.h | 2 -- 4 files changed, 3 insertions(+), 29 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index ac61a6b64a0..4c20587b81d 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -755,7 +755,6 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v { struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device); const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc; - enum wined3d_format_id backbuffer_format; const struct wined3d_vk_info *vk_info; struct wined3d_adapter_vk *adapter_vk; const struct wined3d_format *format; @@ -769,11 +768,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v vk_physical_device = adapter_vk->physical_device; vk_info = &adapter_vk->vk_info; - backbuffer_format = desc->backbuffer_format; - if (wined3d_settings.vk_swap_srgb) - backbuffer_format = wined3d_get_format_srgb(desc->backbuffer_format); - - if ((format = wined3d_get_format(&adapter_vk->a, backbuffer_format, WINED3D_BIND_RENDER_TARGET))) + if ((format = wined3d_get_format(&adapter_vk->a, desc->backbuffer_format, WINED3D_BIND_RENDER_TARGET))) vk_format = wined3d_format_vk(format)->vk_format; else vk_format = VK_FORMAT_B8G8R8A8_UNORM; @@ -805,7 +800,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v { /* Try to create a swapchain with format conversion. */ vk_format = get_swapchain_fallback_format(vk_format); - WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(backbuffer_format)); + WARN("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format)); for (i = 0; i < format_count; ++i) { if (vk_formats[i].format == vk_format && vk_formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) @@ -815,7 +810,7 @@ static VkFormat wined3d_swapchain_vk_select_vk_format(struct wined3d_swapchain_v free(vk_formats); if (i == format_count) { - FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(backbuffer_format)); + FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_d3dformat(desc->backbuffer_format)); return VK_FORMAT_UNDEFINED; } diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 1e2a3f09240..0fb90ba3f18 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1803,19 +1803,6 @@ static const struct wined3d_format_srgb_info format_srgb_info[] = {WINED3DFMT_BC7_UNORM_SRGB, WINED3DFMT_BC7_UNORM}, }; -enum wined3d_format_id wined3d_get_format_srgb(enum wined3d_format_id format_id) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(format_srgb_info); ++i) - { - if (format_srgb_info[i].base_format_id == format_id) - { - return format_srgb_info[i].srgb_format_id; - } - } - return format_id; -} - static inline int get_format_idx(enum wined3d_format_id format_id) { unsigned int i; diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 402051ae2c3..91d8dd567ff 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -129,7 +129,6 @@ struct wined3d_settings wined3d_settings = .max_sm_cs = UINT_MAX, .renderer = WINED3D_RENDERER_AUTO, .shader_backend = WINED3D_SHADER_BACKEND_AUTO, - .vk_swap_srgb = FALSE, }; enum wined3d_renderer CDECL wined3d_get_renderer(void) @@ -469,11 +468,6 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL) ERR_(winediag)("Using the HLSL-based FFP backend.\n"); wined3d_settings.ffp_hlsl = tmpvalue; } - if (!get_config_key_dword(hkey, appkey, env, "vk_swap_srgb", &tmpvalue) && tmpvalue) - { - TRACE("Forcing Vulkan Swapchain SRGB conversions.\n"); - wined3d_settings.vk_swap_srgb = TRUE; - } } if (appkey) RegCloseKey( appkey ); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 5997a1d0ea4..fa758c53cc1 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -485,7 +485,6 @@ struct wined3d_settings bool check_float_constants; bool cb_access_map_w; bool ffp_hlsl; - bool vk_swap_srgb; }; extern struct wined3d_settings wined3d_settings; @@ -4628,7 +4627,6 @@ struct wined3d_format enum wined3d_format_id typeless_id; }; -enum wined3d_format_id wined3d_get_format_srgb(enum wined3d_format_id format_id); const struct wined3d_format *wined3d_get_format(const struct wined3d_adapter *adapter, enum wined3d_format_id format_id, unsigned int bind_flags); enum wined3d_format_id wined3d_get_typed_format_id(const struct wined3d_adapter *adapter, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
From: Stian Low <wineryyyyy@gmail.com> --- dlls/wined3d/swapchain.c | 13 +++++++++---- dlls/wined3d/view.c | 12 ------------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 4c20587b81d..d2f540c547e 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -645,8 +645,10 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, wined3d_texture_load_location(back_buffer, 0, context, back_buffer->resource.draw_binding); - swapchain_blit(swapchain, context, src_rect, dst_rect); + if (gl_info->supported[ARB_FRAMEBUFFER_SRGB]) + gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB); + swapchain_blit(swapchain, context, src_rect, dst_rect); if (swapchain->device->context_count > 1) { WARN_(d3d_perf)("Multiple contexts, calling glFinish() to enforce ordering.\n"); @@ -660,7 +662,9 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, if (context->d3d_info->fences) wined3d_context_gl_submit_command_fence(context_gl); - wined3d_swapchain_gl_rotate(swapchain, context); + /* Skip wined3d_swapchain_gl_rotate() to fix flickering for swapchain buffer_count > 1 + * required for support of DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 0x3 + * https://gitlab.winehq.org/wine/wine/-/merge_requests/10567 */ TRACE("SwapBuffers called, Starting new frame\n"); @@ -1286,8 +1290,9 @@ static void swapchain_vk_present(struct wined3d_swapchain *swapchain, const RECT } } - wined3d_swapchain_vk_rotate(swapchain, context_vk); - + /* Skip wined3d_swapchain_vk_rotate() to fix flickering for swapchain buffer_count > 1 + * required for support of DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 0x3 + * https://gitlab.winehq.org/wine/wine/-/merge_requests/10567 */ wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE); wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE); diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c index a506b0c6f18..79e06e706ae 100644 --- a/dlls/wined3d/view.c +++ b/dlls/wined3d/view.c @@ -620,12 +620,6 @@ static void wined3d_render_target_view_gl_cs_init(void *object) debug_d3dformat(resource->format->id), debug_d3dformat(view_gl->v.format->id)); return; } - if (texture_gl->t.swapchain && texture_gl->t.swapchain->state.desc.backbuffer_count > 1) - { - FIXME("Swapchain views not supported.\n"); - return; - } - create_texture_view(&view_gl->gl_view, texture_gl->target, desc, texture_gl, view_gl->v.format); } } @@ -930,12 +924,6 @@ static void wined3d_render_target_view_vk_cs_init(void *object) return; } - if (texture_vk->t.swapchain && texture_vk->t.swapchain->state.desc.backbuffer_count > 1) - { - FIXME("Swapchain views not supported.\n"); - return; - } - if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET) vk_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
@hverbeet do you remember how to reproduce whatever bug the wine-staging patch was supposed to fix?
It addressed the UI flashing/flickering in some (mainly Qt based) applications like the Steam store/library page when using D3D to render/composite the UI. I'm not entirely sure whether that change is still needed; I haven't tried in a while, and these applications update all the time. It should be noted that the patch isn't entirely correct/complete either though; it will make test_flip() from d3d9/tests/visual.c fail. That's also the reason the wined3d_swapchain_gl_rotate()/wined3d_swapchain_vk_rotate() can't simply be removed; we have tests that show rotation is required in at least some cases. For d3d10/11 that's test_swapchain_flip() in d3d11/tests/d3d11.c and d3d10core/tests/d3d10core.c. It seems likely that the exact conditions under which rotation is supposed to happen will need some tweaking, but it also seems likely that swapchain views will just need to deal with rotation in one way or another. This will be a bit annoying, but perhaps ultimately not too hard; I imagine we could create multiple GL/Vulkan views for RTVs on swapchain resources, and rotate among them when needed using a mechanism similar to the wined3d_bo_user list. Taking a bit of a step back, there's a lot of text in both this MR and the associated bug reports, and I'm afraid I haven't quite kept up with reading all of it. For the benefit of my understanding, could you answer the following questions for me? - These are all Direct3D 11 applications, right? So Direct3D 9 state like WINED3D_RS_SRGBWRITEENABLE and WINED3D_SAMP_SRGB_TEXTURE shouldn't apply, correct? - With current upstream Wine, the applications print the "Swapchain views not supported." FIXME with both the GL renderer and the Vulkan renderer, correct? I.e., the basic issue is that the applications end up rendering to the texture's "default" view, which differs from the RTV's format in terms of sRGB. - In the GL case, which blitter ends up being used for swapchain_blit(), and why? I think you're hinting it's the GLSL blitter, but we'd normally expect the FBO blitter (fbo_blitter_blit()) to be used here. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139804
These are all Direct3D 11 applications, right? So Direct3D 9 state like WINED3D_RS_SRGBWRITEENABLE and WINED3D_SAMP_SRGB_TEXTURE shouldn't apply, correct?
Yes, D3D11 games so far and WINED3D_RS_SRGBWRITEENABLE and WINED3D_SAMP_SRGB_TEXTURE seems not to apply because focus was changed from srgb handling for vulkan to properly supporting flip swap_effect which applies to both gl and vulkan.
With current upstream Wine, the applications print the "Swapchain views not supported." FIXME with both the GL renderer and the Vulkan renderer, correct? I.e., the basic issue is that the applications end up rendering to the texture's "default" view, which differs from the RTV's format in terms of sRGB.
Yes, both GL and Vulkan log "Swapchain views not supported." FIXMEs which was kept for this patch until a solution is approved. Indeed the textures swapchain "default" view format is UNORM for flip swap_effect which requires RTV with SRGB format but creation is skipped because of the buffer_count > 1 FIXME constraint.
In the GL case, which blitter ends up being used for swapchain_blit(), and why? I think you're hinting it's the GLSL blitter, but we'd normally expect the FBO blitter (fbo_blitter_blit()) to be used here.
fbo_blitter_blit() is called by swapchain_blit() via raw_blitter_blit() forwarding according to Frostpunk splashscreen which flickers when wined3d_swapchain_gl_rotate() is not skipped: ``` 0194:trace:d3d:raw_blitter_blit Forwarding to blitter 00007FF9CFA74B50. 0194:trace:d3d:fbo_blitter_blit blitter 00007FF9CFA74B50, op 0, context 00007FF9CFA6F400, src_texture 00007FF968D79810, src_sub_resource_idx 0, src_location WINED3D_LOCATION_TEXTURE_RGB, src_rect (0,0)-(1280,960), dst_texture 00007FF968D79810, dst_sub_resource_idx 0, dst_location WINED3D_LOCATION_DRAWABLE, dst_rect (0,0)-(1280,960), colour_key 0000000000000000, filter WINED3D_TEXF_NONE, resolve_format 0000000000000000. ``` wglSwapBuffers has Steam overlay comment which seems related to UI flickering addressed by your staging patch: ``` /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc); ``` Without wglSwapBuffers the screen never updates and remains the initial clear color which is all white for Frostpunk and all black for others. Thanks for pointers to existing tests that need to be tested. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139827
On Thu May 14 14:27:16 2026 +0000, Stian Low wrote:
These are all Direct3D 11 applications, right? So Direct3D 9 state like WINED3D_RS_SRGBWRITEENABLE and WINED3D_SAMP_SRGB_TEXTURE shouldn't apply, correct? Yes, D3D11 games so far and WINED3D_RS_SRGBWRITEENABLE and WINED3D_SAMP_SRGB_TEXTURE seems not to apply because focus was changed from srgb handling for vulkan to properly supporting flip swap_effect which applies to both gl and vulkan. With current upstream Wine, the applications print the "Swapchain views not supported." FIXME with both the GL renderer and the Vulkan renderer, correct? I.e., the basic issue is that the applications end up rendering to the texture's "default" view, which differs from the RTV's format in terms of sRGB. Yes, both GL and Vulkan log "Swapchain views not supported." FIXMEs. Indeed the textures swapchain "default" view format is UNORM for flip swap_effect which requires RTV with SRGB format but creation is skipped because of the buffer_count > 1 FIXME constraint. In the GL case, which blitter ends up being used for swapchain_blit(), and why? I think you're hinting it's the GLSL blitter, but we'd normally expect the FBO blitter (fbo_blitter_blit()) to be used here. fbo_blitter_blit() is called by swapchain_blit() via raw_blitter_blit() forwarding according to Frostpunk splashscreen which flickers when wined3d_swapchain_gl_rotate() is not skipped:
0194:trace:d3d:raw_blitter_blit Forwarding to blitter 00007FF9CFA74B50. 0194:trace:d3d:fbo_blitter_blit blitter 00007FF9CFA74B50, op 0, context 00007FF9CFA6F400, src_texture 00007FF968D79810, src_sub_resource_idx 0, src_location WINED3D_LOCATION_TEXTURE_RGB, src_rect (0,0)-(1280,960), dst_texture 00007FF968D79810, dst_sub_resource_idx 0, dst_location WINED3D_LOCATION_DRAWABLE, dst_rect (0,0)-(1280,960), colour_key 0000000000000000, filter WINED3D_TEXF_NONE, resolve_format 0000000000000000.wglSwapBuffers has Steam overlay comment which seems related to UI flickering addressed by your staging patch: ``` /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc); ``` Without wglSwapBuffers the screen never updates and remains the initial clear color which is all white for Frostpunk and all black for others. Thanks for pointers to existing tests that need to be tested. These logs were kept for the patch until considered fully resolved:
``` 0190:fixme:d3d:wined3d_swapchain_init The application requested more than one back buffer, this is not properly supported. Please configure the application to use double buffering (1 back buffer) if possible. 0190:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3. ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139828
On Thu May 14 14:36:17 2026 +0000, Stian Low wrote:
These logs were kept for the patch until considered fully resolved: ``` 0190:fixme:d3d:wined3d_swapchain_init The application requested more than one back buffer, this is not properly supported. Please configure the application to use double buffering (1 back buffer) if possible. 0190:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3. ``` This MS example has a comment referring to BufferCount = 2 as double buffering: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_e... d3d9/tests/visual.c indeed fails with this patch. I will consider modding to only skip wined3d_swapchain_gl_rotate() for particular cases such as d3d11 flip swap_effect and leaving d3d9 in place.
I'm also reviewing d3d tests for correctness because despite d3d9/tests/visual.c failing, d3d9 games tested so far that use flip swap_effect work with the patch without any issues. However these d3d9 games do not render darker for vulkan even without the patch. List of d3d9 games using swap_effect to test: https://www.pcgamingwiki.com/wiki/Topic:Xqqq11z22nvv8vpk So far only "Hotline Miami 2: Wrong Number" has been tested which has these logs which confirms the flip effect and buffer_count > 1 FIXME condition: ``` 0024:fixme:d3d9:device_init present_parameters->BackBufferCount 4, SwapEffect 5 0024:fixme:d3d:wined3d_swapchain_init The application requested more than one back buffer, this is not properly supported. Please configure the application to use double buffering (1 back buffer) if possible. 0024:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3. ``` D3DSWAPEFFECT_FLIPEX = 5 maps to WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL 0x3 via wined3dswapeffect_from_d3dswapeffect() for ./dlls/d3d9/device.c Desipte similar logs being spammed, vulkan is not rendered darker `0024:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3.` Note "Hotline Miami 2: Wrong Number" requires latest vkd3d reported here: https://bugs.winehq.org/show_bug.cgi?id=50182#c3 gl renderer for "Hotline Miami 2: Wrong Number" seems to work for all cases. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139900
With current upstream Wine, the applications print the "Swapchain views not supported." FIXME with both the GL renderer and the Vulkan renderer, correct? I.e., the basic issue is that the applications end up rendering to the texture's "default" view, which differs from the RTV's format in terms of sRGB.
Yes, both GL and Vulkan log "Swapchain views not supported." FIXMEs. Indeed the textures swapchain "default" view format is UNORM for flip swap_effect which requires RTV with SRGB format but creation is skipped because of the buffer_count \> 1 FIXME constraint.
In the GL case, which blitter ends up being used for swapchain_blit(), and why? I think you're hinting it's the GLSL blitter, but we'd normally expect the FBO blitter (fbo_blitter_blit()) to be used here.
fbo_blitter_blit() is called by swapchain_blit() via raw_blitter_blit() forwarding according to Frostpunk splashscreen which flickers when wined3d_swapchain_gl_rotate() is not skipped:
Right, the reason for the "backbuffer_count" check and FIXME is that if there's more than one buffer in the swapchain we need to handle rotating the views created on them as well. That's also the reason there's flickering when rotation isn't disabled; the underlying backbuffer resource essentially ends up being rotated out from under the view. Instead of disabling GL_FRAMEBUFFER_SRGB in swapchain_gl_present(), I think we need to disable it in texture2d_blt_fbo(), somewhat like we're doing in wined3d_context_gl_apply_blit_state(): ```diff diff --git a/dlls/wined3d/texture_gl.c b/dlls/wined3d/texture_gl.c index 311ee954c23..68a731f3710 100644 --- a/dlls/wined3d/texture_gl.c +++ b/dlls/wined3d/texture_gl.c @@ -913,6 +913,12 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); context_invalidate_state(context, STATE_RASTERIZER); + if (gl_info->supported[ARB_FRAMEBUFFER_SRGB]) + { + gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB); + context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL)); + } + gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter); checkGLcall("glBlitFramebuffer()"); ``` I'm a little surprised not having that hasn't been more of an issue before.
wglSwapBuffers has Steam overlay comment which seems related to UI flickering addressed by your staging patch:
``` /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc); ```
Without wglSwapBuffers the screen never updates and remains the initial clear color which is all white for Frostpunk and all black for others.
No, that's a different issue; the "Steam overlay" here refers to the in-game Steam overlay that can be brought up by pressing some key combination. Also, as you've found, you can't just remove the wglSwapBuffers() call; the alternative here would be doing a normal wglSwapBuffers() call, as opposed to going through the function pointer we retrieved in wined3d_adapter_gl_init().
These logs were kept for the patch until considered fully resolved:
``` 0190:fixme:d3d:wined3d_swapchain_init The application requested more than one back buffer, this is not properly supported. Please configure the application to use double buffering (1 back buffer) if possible. 0190:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3. ```
This MS example has a comment referring to BufferCount = 2 as double buffering: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_e...
The "more than one back buffer" FIXME should have been removed long ago, but never was. The terminology can be a bit confusing at times though; some places consider a swapchain containing three images to have one front buffer and two back buffers, while other places would say the swapchain has three back buffers, one of which is currently the front buffer. The d3d10/dxgi documentation cleaned that up a little by explicitly saying "BufferCount" includes the front buffer, and is simply the total number of images in the swapchain.
I'm also reviewing d3d tests for correctness because despite d3d9/tests/visual.c failing, d3d9 games tested so far that use flip swap_effect work with the patch without any issues. However these d3d9 games do not render darker for vulkan even without the patch.
You're unlikely to notice a difference with a typical game. Typical games clear and redraw the entire render target / back buffer each frame, at the display's refresh rate. Where swapchain rotation matters is applications doing "damage tracking", only redrawing the parts of the screen that changed, as needed. Typically that's desktop applications, although IIRC there were a couple of games as well. @stefan may remember specific applications. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139947
On Fri May 15 11:37:21 2026 +0000, Henri Verbeet wrote:
With current upstream Wine, the applications print the "Swapchain views not supported." FIXME with both the GL renderer and the Vulkan renderer, correct? I.e., the basic issue is that the applications end up rendering to the texture's "default" view, which differs from the RTV's format in terms of sRGB.
Yes, both GL and Vulkan log "Swapchain views not supported." FIXMEs. Indeed the textures swapchain "default" view format is UNORM for flip swap_effect which requires RTV with SRGB format but creation is skipped because of the buffer_count \> 1 FIXME constraint.
In the GL case, which blitter ends up being used for swapchain_blit(), and why? I think you're hinting it's the GLSL blitter, but we'd normally expect the FBO blitter (fbo_blitter_blit()) to be used here.
fbo_blitter_blit() is called by swapchain_blit() via raw_blitter_blit() forwarding according to Frostpunk splashscreen which flickers when wined3d_swapchain_gl_rotate() is not skipped: Right, the reason for the "backbuffer_count" check and FIXME is that if there's more than one buffer in the swapchain we need to handle rotating the views created on them as well. That's also the reason there's flickering when rotation isn't disabled; the underlying backbuffer resource essentially ends up being rotated out from under the view. Instead of disabling GL_FRAMEBUFFER_SRGB in swapchain_gl_present(), I think we need to disable it in texture2d_blt_fbo(), somewhat like we're doing in wined3d_context_gl_apply_blit_state():
diff --git a/dlls/wined3d/texture_gl.c b/dlls/wined3d/texture_gl.c index 311ee954c23..68a731f3710 100644 --- a/dlls/wined3d/texture_gl.c +++ b/dlls/wined3d/texture_gl.c @@ -913,6 +913,12 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); context_invalidate_state(context, STATE_RASTERIZER); + if (gl_info->supported[ARB_FRAMEBUFFER_SRGB]) + { + gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB); + context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL)); + } + gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter); checkGLcall("glBlitFramebuffer()");I'm a little surprised not having that hasn't been more of an issue before.
wglSwapBuffers has Steam overlay comment which seems related to UI flickering addressed by your staging patch:
``` /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */ gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc); ```
Without wglSwapBuffers the screen never updates and remains the initial clear color which is all white for Frostpunk and all black for others. No, that's a different issue; the "Steam overlay" here refers to the in-game Steam overlay that can be brought up by pressing some key combination. Also, as you've found, you can't just remove the wglSwapBuffers() call; the alternative here would be doing a normal wglSwapBuffers() call, as opposed to going through the function pointer we retrieved in wined3d_adapter_gl_init(). These logs were kept for the patch until considered fully resolved:
``` 0190:fixme:d3d:wined3d_swapchain_init The application requested more than one back buffer, this is not properly supported. Please configure the application to use double buffering (1 back buffer) if possible. 0190:fixme:d3d:wined3d_swapchain_init Unimplemented swap effect 0x3. ```
This MS example has a comment referring to BufferCount = 2 as double buffering: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_e... The "more than one back buffer" FIXME should have been removed long ago, but never was. The terminology can be a bit confusing at times though; some places consider a swapchain containing three images to have one front buffer and two back buffers, while other places would say the swapchain has three back buffers, one of which is currently the front buffer. The d3d10/dxgi documentation cleaned that up a little by explicitly saying "BufferCount" includes the front buffer, and is simply the total number of images in the swapchain. I'm also reviewing d3d tests for correctness because despite d3d9/tests/visual.c failing, d3d9 games tested so far that use flip swap_effect work with the patch without any issues. However these d3d9 games do not render darker for vulkan even without the patch. You're unlikely to notice a difference with a typical game. Typical games clear and redraw the entire render target / back buffer each frame, at the display's refresh rate. Where swapchain rotation matters is applications doing "damage tracking", only redrawing the parts of the screen that changed, as needed. Typically that's desktop applications, although IIRC there were a couple of games as well. @stefan may remember specific applications. This post might show up twice. I think Gitlab ate my first one, or I posted it elsewhere by accident.
I don't know of any d3d9 games that depend on the flip swap effect. This was mostly a thing in the DirectDraw days. Prince of Persia 3D and Empire Earth 1 are two games that recycle the frontbuffer contents. Pop3d in the main menu and Empire Earth for the in-game HUD - but only with some graphics settings. But even for these two games I don't expect a visual difference between copy and flip. The DirectX 7 SDK has a ddraw sample that differentiates between "odd framebuffer" and "even framebuffer". -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139997
On Fri May 15 11:37:21 2026 +0000, Stefan Dösinger wrote:
This post might show up twice. I think Gitlab ate my first one, or I posted it elsewhere by accident. I don't know of any d3d9 games that depend on the flip swap effect. This was mostly a thing in the DirectDraw days. Prince of Persia 3D and Empire Earth 1 are two games that recycle the frontbuffer contents. Pop3d in the main menu and Empire Earth for the in-game HUD - but only with some graphics settings. But even for these two games I don't expect a visual difference between copy and flip. The DirectX 7 SDK has a ddraw sample that differentiates between "odd framebuffer" and "even framebuffer". Oh and I also believe I took care of swapchain texture shader resource views when I implemented swapchain rotation. But that was 10 years ago, so maybe my memory is wrong. Or we decided to ignore the issue until we spot a game that actually needs it.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_139998
On Fri May 15 11:39:20 2026 +0000, Stefan Dösinger wrote:
Oh and I also believe I took care of swapchain texture shader resource views when I implemented swapchain rotation. But that was 10 years ago, so maybe my memory is wrong. Or we decided to ignore the issue until we spot a game that actually needs it. Thanks for feedback and additional games/cases to test.
@hverbeet, I'll make the changes you recommend for next push. @stefan, Empire Earth has issues with cursor not clearing after window loses and regains focus which may be related to swap rotation: https://bugs.winehq.org/show_bug.cgi?id=58308 https://bugs.winehq.org/buglist.cgi?quicksearch=Empire%20Earth%20 I'll revisit these and seek out similar games to expand test cases for next push. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_140039
On Fri May 15 15:41:12 2026 +0000, Stian Low wrote:
Thanks for feedback and additional games/cases to test. @hverbeet, I'll make the changes you recommend for next push. @stefan, Empire Earth has issues with cursor not clearing after window loses and regains focus which may be related to swap rotation: https://bugs.winehq.org/show_bug.cgi?id=58308 https://bugs.winehq.org/buglist.cgi?quicksearch=Empire%20Earth%20 I'll revisit these and seek out similar games to expand test cases for next push. Bug 58308 is unlikely to be related to swapchain flipping. Minimizing and restoring fullscreen games is very complicated, especially in ddraw.
A possible symptom of flipping (or lack thereof) is the in-game resource count or building descriptions in the HUD jumping between an old and new content. But I think the game should be content with an accidental copy swapeffect instead of flip. If the resource count changes it'll redraw the text the next two frames. If the text remains static it stops drawing it because IDirectDrawSurface7::GetDC is very expensive. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_140071
Linking bug report fix for Battle.net flicker via this patch caused by latest dcomp-DCompositionCreateDevice2 added to wine-staging: https://bugs.winehq.org/show_bug.cgi?id=59631#c33 dcomp staging patch only requires 1 line fix to always use swapchain backbuffer_idx=0 in order to be compatible with this patch. More tests ongoing. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_140357
This patch also fixes CPU-based rendering via LIBGL_ALWAYS_SOFTWARE that otherwise renders blackscreen: https://bugs.winehq.org/show_bug.cgi?id=45364#c23 I tried to test cpu_blit cases but unable to successfully force it by simply commenting out other blitters for `device_gl_create_primary_opengl_context_cs` because it seems to break things. CPU-based rendering with backbuffers > 1 seems very edge case but wanted to test all cases (LIBGL_ALWAYS_SOFTWARE is as slow as watching grass grow). Please let me know if there are older CPU-based rendering games/cases that this MR may impact. So far patches still seems to fix more than break. Thanks to @alesliehughes it is now part of staging for even wider testing. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_141802
participants (4)
-
Henri Verbeet (@hverbeet) -
Stefan Dösinger (@stefan) -
Stian Low -
Stian Low (@stianlow)