[PATCH v33 0/2] MR10567: wined3d: fix SRGB RTV fail for UNORM swapchain backbuffers > 1 for d3d10/11
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. -- v33: wined3d: fix SRGB RTV fail for UNORM swapchain backbuffers > 1 for d3d10/11 https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
From: Stian Low <wineryyyyy@gmail.com> --- dlls/d3d10core/tests/d3d10core.c | 48 +++++++++++++++++++++++++++----- dlls/d3d11/tests/d3d11.c | 29 ++++++++++++++++--- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/dlls/d3d10core/tests/d3d10core.c b/dlls/d3d10core/tests/d3d10core.c index a949b14837e..fb5482c484c 100644 --- a/dlls/d3d10core/tests/d3d10core.c +++ b/dlls/d3d10core/tests/d3d10core.c @@ -11028,6 +11028,7 @@ static void test_swapchain_views(void) ID3D10RenderTargetView *rtv; ID3D10Device *device; ULONG refcount; + UINT flags; HRESULT hr; if (!init_test_context(&test_context)) @@ -11041,9 +11042,13 @@ static void test_swapchain_views(void) rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; rtv_desc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D; rtv_desc.Texture2D.MipSlice = 0; + + hr = ID3D10Device_CheckFormatSupport(device, rtv_desc.Format, &flags); + ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr); hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)test_context.backbuffer, &rtv_desc, &rtv); - /* This seems to work only on Windows 7. */ - ok(hr == S_OK || broken(hr == E_INVALIDARG), "Failed to create render target view, hr %#lx.\n", hr); + flags &= D3D10_FORMAT_SUPPORT_BACK_BUFFER_CAST; + flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); + todo_wine ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D10RenderTargetView_Release(rtv); @@ -11061,12 +11066,14 @@ static void test_swapchain_views(void) static void test_swapchain_flip(void) { + ID3D10RenderTargetView *backbuffer_0_rtv, *backbuffer_0_rtv_srgb, *offscreen_rtv; ID3D10Texture2D *backbuffer_0, *backbuffer_1, *backbuffer_2, *offscreen; ID3D10ShaderResourceView *backbuffer_0_srv, *backbuffer_1_srv; - ID3D10RenderTargetView *backbuffer_0_rtv, *offscreen_rtv; + D3D10_RENDER_TARGET_VIEW_DESC rtv_desc; unsigned int color, stride, offset; D3D10_TEXTURE2D_DESC texture_desc; ID3D10InputLayout *input_layout; + struct swapchain_desc desc; IDXGISwapChain *swapchain; ID3D10VertexShader *vs; ID3D10PixelShader *ps; @@ -11074,6 +11081,7 @@ static void test_swapchain_flip(void) ID3D10Buffer *vb; ULONG refcount; HWND window; + UINT flags; HRESULT hr; RECT rect; @@ -11139,7 +11147,8 @@ static void test_swapchain_flip(void) static const float red[] = {1.0f, 0.0f, 0.0f, 0.5f}; static const float green[] = {0.0f, 1.0f, 0.0f, 0.5f}; static const float blue[] = {0.0f, 0.0f, 1.0f, 0.5f}; - struct swapchain_desc desc; + static const float grey[] = {0.5, 0.5f, 0.5f, 0.5f}; + if (!(device = create_device())) { @@ -11184,7 +11193,7 @@ static void test_swapchain_flip(void) ok(texture_desc.Usage == D3D10_USAGE_DEFAULT, "Got unexpected usage %u.\n", texture_desc.Usage); hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)backbuffer_1, NULL, &offscreen_rtv); - todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D10RenderTargetView_Release(offscreen_rtv); @@ -11227,11 +11236,31 @@ static void test_swapchain_flip(void) ok(SUCCEEDED(hr), "Failed to create pixel shader, hr %#lx.\n", hr); ID3D10Device_PSSetShader(device, ps); + /* Test SRGB rtv for UNORM swapchain common for Unity games for Win10 (bug #45364, MR #10567) */ + rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + rtv_desc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D; + rtv_desc.Texture2D.MipSlice = 0; + hr = ID3D10Device_CheckFormatSupport(device, rtv_desc.Format, &flags); + ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr); + hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)backbuffer_0, &rtv_desc, &backbuffer_0_rtv_srgb); + flags &= D3D10_FORMAT_SUPPORT_BACK_BUFFER_CAST; + flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); + todo_wine ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + ID3D10Device_ClearRenderTargetView(device, backbuffer_0_rtv_srgb, grey); + color = get_texture_color(backbuffer_0, 320, 240); /* red */ + todo_wine ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08x.\n", color); + ID3D10RenderTargetView_Release(backbuffer_0_rtv_srgb); + } + ID3D10Device_ClearRenderTargetView(device, backbuffer_0_rtv, red); ID3D10Device_Draw(device, 4, 0); - color = get_texture_color(offscreen, 120, 240); + color = get_texture_color(offscreen, 120, 240); /* red, buf 0 */ ok(compare_color(color, 0x7f0000ff, 1), "Got unexpected color 0x%08x.\n", color); + color = get_texture_color(offscreen, 320, 240); /* black (untouched default), buf 1 */ + ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color); /* DXGI moves buffers in the same direction as earlier versions. Buffer 2 becomes buffer 1, * buffer 1 becomes the new buffer 0, and buffer 0 becomes buffer n - 1. However, only buffer @@ -11247,12 +11276,17 @@ static void test_swapchain_flip(void) ID3D10Device_ClearRenderTargetView(device, backbuffer_0_rtv, green); ID3D10Device_Draw(device, 4, 0); + color = get_texture_color(offscreen, 120, 240); /* green, buf 0 */ ok(compare_color(color, 0x7f00ff00, 1), "Got unexpected color 0x%08x.\n", color); - /* Buffer 1 is still untouched. */ + color = get_texture_color(offscreen, 320, 240); /* black (untouched default), buf 1 */ + ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color); + /* Buffer 1 is still untouched. */ color = get_texture_color(backbuffer_0, 320, 240); /* green */ ok(compare_color(color, 0x7f00ff00, 1), "Got unexpected color 0x%08x.\n", color); + color = get_texture_color(backbuffer_1, 320, 240); /* black (untouched default) */ + ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color); color = get_texture_color(backbuffer_2, 320, 240); /* red */ ok(compare_color(color, 0x7f0000ff, 1), "Got unexpected color 0x%08x.\n", color); diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 00ec3b0d2b9..7b45dafbdb3 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -16013,9 +16013,10 @@ static void test_swapchain_views(void) static void test_swapchain_flip(void) { + ID3D11RenderTargetView *backbuffer_0_rtv, *offscreen_rtv, *backbuffer_0_rtv_srgb; ID3D11Texture2D *backbuffer_0, *backbuffer_1, *backbuffer_2, *offscreen; ID3D11ShaderResourceView *backbuffer_0_srv, *backbuffer_1_srv; - ID3D11RenderTargetView *backbuffer_0_rtv, *offscreen_rtv; + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc; D3D11_TEXTURE2D_DESC texture_desc; ID3D11InputLayout *input_layout; ID3D11DeviceContext *context; @@ -16029,6 +16030,7 @@ static void test_swapchain_flip(void) ULONG refcount; DWORD color; HWND window; + UINT flags; HRESULT hr; RECT rect; @@ -16094,6 +16096,7 @@ static void test_swapchain_flip(void) static const float red[] = {1.0f, 0.0f, 0.0f, 0.5f}; static const float green[] = {0.0f, 1.0f, 0.0f, 0.5f}; static const float blue[] = {0.0f, 0.0f, 1.0f, 0.5f}; + static const float grey[] = {0.5, 0.5f, 0.5f, 0.5f}; if (!(device = create_device(NULL))) { @@ -16118,6 +16121,8 @@ static void test_swapchain_flip(void) hr = IDXGISwapChain_GetBuffer(swapchain, 2, &IID_ID3D11Texture2D, (void **)&backbuffer_2); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Device_GetImmediateContext(device, &context); + hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_0, NULL, &backbuffer_0_rtv); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)backbuffer_0, NULL, &backbuffer_0_srv); @@ -16138,12 +16143,10 @@ static void test_swapchain_flip(void) ok(texture_desc.Usage == D3D11_USAGE_DEFAULT, "Got unexpected usage %u.\n", texture_desc.Usage); hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_1, NULL, &offscreen_rtv); - todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D11RenderTargetView_Release(offscreen_rtv); - ID3D11Device_GetImmediateContext(device, &context); - ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &backbuffer_0_srv); ID3D11DeviceContext_PSSetShaderResources(context, 1, 1, &backbuffer_1_srv); @@ -16183,6 +16186,23 @@ static void test_swapchain_flip(void) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0); + /* Test SRGB rtv for UNORM swapchain common for Unity games for Win10 (bug #45364, MR #10567) */ + rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + hr = ID3D11Device_CheckFormatSupport(device, rtv_desc.Format, &flags); + ok(SUCCEEDED(hr), "Got unexpected hr %#lx.\n", hr); + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtv_desc.Texture2D.MipSlice = 0; + hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_0, &rtv_desc, &backbuffer_0_rtv_srgb); + flags &= D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST; + flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); + todo_wine ok(flags, "Got unexpected for SRGB rtv vs swapchain UNORM, hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv_srgb, grey); + color = get_texture_color(backbuffer_0, 320, 240); /* grey */ + todo_wine ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08lx.\n", color); + } + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, red); ID3D11DeviceContext_Draw(context, 4, 0); @@ -16237,6 +16257,7 @@ static void test_swapchain_flip(void) ID3D11ShaderResourceView_Release(backbuffer_0_srv); ID3D11ShaderResourceView_Release(backbuffer_1_srv); ID3D11RenderTargetView_Release(backbuffer_0_rtv); + ID3D11RenderTargetView_Release(backbuffer_0_rtv_srgb); ID3D11RenderTargetView_Release(offscreen_rtv); ID3D11Texture2D_Release(offscreen); ID3D11Texture2D_Release(backbuffer_0); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
From: Stian Low <wineryyyyy@gmail.com> --- dlls/d3d10core/tests/d3d10core.c | 8 +- dlls/d3d11/device.c | 14 +++ dlls/d3d11/tests/d3d11.c | 6 +- dlls/d3d11/view.c | 36 +++++++- dlls/wined3d/adapter_gl.c | 54 ++++++++++- dlls/wined3d/adapter_vk.c | 52 +++++++++-- dlls/wined3d/swapchain.c | 92 ++++++++++++++++++- dlls/wined3d/view.c | 150 ++++++++++++++++++++++++------- dlls/wined3d/wined3d.spec | 1 + dlls/wined3d/wined3d_gl.h | 15 ++++ dlls/wined3d/wined3d_private.h | 23 +++-- dlls/wined3d/wined3d_vk.h | 15 ++++ include/wine/wined3d.h | 1 + 13 files changed, 413 insertions(+), 54 deletions(-) diff --git a/dlls/d3d10core/tests/d3d10core.c b/dlls/d3d10core/tests/d3d10core.c index fb5482c484c..ff78ac23b9e 100644 --- a/dlls/d3d10core/tests/d3d10core.c +++ b/dlls/d3d10core/tests/d3d10core.c @@ -11048,7 +11048,7 @@ static void test_swapchain_views(void) hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)test_context.backbuffer, &rtv_desc, &rtv); flags &= D3D10_FORMAT_SUPPORT_BACK_BUFFER_CAST; flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); - todo_wine ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); + ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D10RenderTargetView_Release(rtv); @@ -11193,7 +11193,7 @@ static void test_swapchain_flip(void) ok(texture_desc.Usage == D3D10_USAGE_DEFAULT, "Got unexpected usage %u.\n", texture_desc.Usage); hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)backbuffer_1, NULL, &offscreen_rtv); - todo_wine ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D10RenderTargetView_Release(offscreen_rtv); @@ -11245,12 +11245,12 @@ static void test_swapchain_flip(void) hr = ID3D10Device_CreateRenderTargetView(device, (ID3D10Resource *)backbuffer_0, &rtv_desc, &backbuffer_0_rtv_srgb); flags &= D3D10_FORMAT_SUPPORT_BACK_BUFFER_CAST; flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); - todo_wine ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); + ok(flags, "Got unexpected for SRGB rtv for UNORM swapchain, hr %#lx.\n", hr); if (SUCCEEDED(hr)) { ID3D10Device_ClearRenderTargetView(device, backbuffer_0_rtv_srgb, grey); color = get_texture_color(backbuffer_0, 320, 240); /* red */ - todo_wine ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08x.\n", color); + ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08x.\n", color); ID3D10RenderTargetView_Release(backbuffer_0_rtv_srgb); } diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index e1a846698e6..2757010dbe0 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -4703,6 +4703,20 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CheckFormatSupport(ID3D11Device5 * | D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD; } + switch (wined3d_format) + { + case WINED3DFMT_R10G10B10A2_UNORM: + case WINED3DFMT_R10G10B10_XR_BIAS_A2_UNORM: + case WINED3DFMT_R8G8B8A8_UNORM: + case WINED3DFMT_R8G8B8A8_UNORM_SRGB: + case WINED3DFMT_B8G8R8A8_UNORM: + case WINED3DFMT_B8G8R8X8_UNORM_SRGB: + /* d3d10/11 share saem FORMAT_SUPPORT_BACK_BUFFER_CAST flag value*/ + *format_support |= D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST; + default: + break; + } + return *format_support ? S_OK : E_FAIL; } diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 7b45dafbdb3..5adbf2c977c 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -16143,7 +16143,7 @@ static void test_swapchain_flip(void) ok(texture_desc.Usage == D3D11_USAGE_DEFAULT, "Got unexpected usage %u.\n", texture_desc.Usage); hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_1, NULL, &offscreen_rtv); - todo_wine ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Got unexpected for rtv for swapchain backbuffer_1, hr %#lx.\n", hr); if (SUCCEEDED(hr)) ID3D11RenderTargetView_Release(offscreen_rtv); @@ -16195,12 +16195,12 @@ static void test_swapchain_flip(void) hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_0, &rtv_desc, &backbuffer_0_rtv_srgb); flags &= D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST; flags = (FAILED(hr) && !flags) || (SUCCEEDED(hr) && flags); - todo_wine ok(flags, "Got unexpected for SRGB rtv vs swapchain UNORM, hr %#lx.\n", hr); + ok(flags, "Got unexpected for SRGB rtv vs swapchain UNORM, hr %#lx.\n", hr); if (SUCCEEDED(hr)) { ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv_srgb, grey); color = get_texture_color(backbuffer_0, 320, 240); /* grey */ - todo_wine ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08lx.\n", color); + ok(compare_color(color, 0x80bcbcbc, 1), "Got unexpected srgb color 0x%08lx.\n", color); } ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, red); diff --git a/dlls/d3d11/view.c b/dlls/d3d11/view.c index ec55dba5cf3..5acd410e2bb 100644 --- a/dlls/d3d11/view.c +++ b/dlls/d3d11/view.c @@ -1709,6 +1709,7 @@ static HRESULT d3d_rendertarget_view_init(struct d3d_rendertarget_view *view, st { struct wined3d_resource *wined3d_resource; struct wined3d_view_desc wined3d_desc; + struct wined3d_swapchain *swapchain; HRESULT hr; view->ID3D11RenderTargetView_iface.lpVtbl = &d3d11_rendertarget_view_vtbl; @@ -1732,10 +1733,43 @@ static HRESULT d3d_rendertarget_view_init(struct d3d_rendertarget_view *view, st { wined3d_mutex_unlock(); ERR("Failed to get wined3d resource for d3d11 resource %p.\n", resource); - return E_FAIL; + return E_INVALIDARG; } wined3d_rendertarget_view_desc_from_d3d11(&wined3d_desc, &view->desc); + + if ((swapchain = wined3d_swapchain_from_resource(wined3d_resource))) + { + if (wined3d_swapchain_get_back_buffer(swapchain, 0) != wined3d_texture_from_resource(wined3d_resource)) + { + wined3d_mutex_unlock(); + ERR("RTVs texture does not match swapchain back_buffers[0]\n"); + return E_INVALIDARG; + } + + if (desc) + { + UINT flags; + + if (FAILED(hr = ID3D11Device_CheckFormatSupport((ID3D11Device*)&device->ID3D11Device5_iface, desc->Format, &flags))) + { + wined3d_mutex_unlock(); + ERR("Failed to get format support\n"); + return hr; + } + + flags &= D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST; + if (!flags) + { + wined3d_mutex_unlock(); + ERR("Casting format for swapchain backbuffer not supported\n"); + return E_INVALIDARG; + } + } + + } + + if (FAILED(hr = wined3d_rendertarget_view_create(&wined3d_desc, wined3d_resource, view, &d3d_render_target_view_wined3d_parent_ops, &view->wined3d_view))) { diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c index 35f73b64497..1f6c0bc9e61 100644 --- a/dlls/wined3d/adapter_gl.c +++ b/dlls/wined3d/adapter_gl.c @@ -4561,19 +4561,29 @@ static HRESULT adapter_gl_create_rendertarget_view(const struct wined3d_view_des struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_rendertarget_view **view) { - struct wined3d_rendertarget_view_gl *view_gl; + struct wined3d_swapchain_rendertarget_view_gl *swap_view_gl = NULL; + struct wined3d_rendertarget_view_gl *view_gl = NULL; HRESULT hr; TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n", wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view); - if (!(view_gl = calloc(1, sizeof(*view_gl)))) + if (swapchain_from_resource(resource)) + { + if (!(swap_view_gl = calloc(1, sizeof(*swap_view_gl)))) + return E_OUTOFMEMORY; + view_gl = &swap_view_gl->view_gl; + } + else if (!(view_gl = calloc(1, sizeof(*view_gl)))) return E_OUTOFMEMORY; if (FAILED(hr = wined3d_rendertarget_view_gl_init(view_gl, desc, resource, parent, parent_ops))) { WARN("Failed to initialise view, hr %#lx.\n", hr); - free(view_gl); + if (swap_view_gl) + free(swap_view_gl); + else if (view_gl) + free(view_gl); return hr; } @@ -4649,12 +4659,48 @@ static void wined3d_view_gl_destroy(struct wined3d_device *device, const struct static void adapter_gl_destroy_rendertarget_view(struct wined3d_rendertarget_view *view) { struct wined3d_rendertarget_view_gl *view_gl = wined3d_rendertarget_view_gl(view); + struct wined3d_swapchain_rendertarget_view_gl *swap_view_gl; struct wined3d_resource *resource = view_gl->v.resource; + struct wined3d_swapchain *swapchain; + void *object = view_gl; TRACE("view_gl %p.\n", view_gl); wined3d_rendertarget_view_cleanup(&view_gl->v); - wined3d_view_gl_destroy(resource->device, &view_gl->gl_view, NULL, NULL, view_gl); + + if ((swapchain = wined3d_swapchain_from_resource(resource))) + { + if ((swap_view_gl = wined3d_swapchain_rendertarget_view_gl(view_gl))) + { + unsigned int i, count = swapchain->state.desc.backbuffer_count - 1; + struct wined3d_swapchain_rendertarget_view *view; + GLuint name = view_gl->gl_view.name; + + for (i = 0; i < count; i++) + { + view_gl->gl_view.name = swap_view_gl->gl_swap_views[i]; + wined3d_view_gl_destroy(resource->device, &view_gl->gl_view, NULL, NULL, NULL); + } + view_gl->gl_view.name = name; + object = swap_view_gl; + + LIST_FOR_EACH_ENTRY(view, &swapchain->back_buffer_rendertarget_views, struct wined3d_swapchain_rendertarget_view, entry) + { + if (view->view != &view_gl->v) + continue; + + list_remove(&view->entry); + break; + } + } + else + { + FIXME("Missing wined3d_swapchain_rendertarget_view_gl for view_gl %p which should not occur.\n", view_gl); + object = view_gl; + } + } + + wined3d_view_gl_destroy(resource->device, &view_gl->gl_view, NULL, NULL, object); } static HRESULT adapter_gl_create_shader_resource_view(const struct wined3d_view_desc *desc, diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index 79014b4c331..460afb4ecb3 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -1393,19 +1393,30 @@ static HRESULT adapter_vk_create_rendertarget_view(const struct wined3d_view_des struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_rendertarget_view **view) { - struct wined3d_rendertarget_view_vk *view_vk; + struct wined3d_swapchain_rendertarget_view_vk *swap_view_vk = NULL; + struct wined3d_rendertarget_view_vk *view_vk = NULL; + HRESULT hr; TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n", wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view); - if (!(view_vk = calloc(1, sizeof(*view_vk)))) + if (swapchain_from_resource(resource)) + { + if (!(swap_view_vk = calloc(1, sizeof(*swap_view_vk)))) + return E_OUTOFMEMORY; + view_vk = &swap_view_vk->view_vk; + } + else if (!(view_vk = calloc(1, sizeof(*view_vk)))) return E_OUTOFMEMORY; if (FAILED(hr = wined3d_rendertarget_view_vk_init(view_vk, desc, resource, parent, parent_ops))) { WARN("Failed to initialise view, hr %#lx.\n", hr); - free(view_vk); + if (swap_view_vk) + free(swap_view_vk); + else if (view_vk) + free(view_vk); return hr; } @@ -1518,13 +1529,44 @@ static void wined3d_view_vk_destroy(struct wined3d_device *device, VkBufferView static void adapter_vk_destroy_rendertarget_view(struct wined3d_rendertarget_view *view) { struct wined3d_rendertarget_view_vk *view_vk = wined3d_rendertarget_view_vk(view); + struct wined3d_swapchain_rendertarget_view_vk *swap_view_vk; struct wined3d_resource *resource = view_vk->v.resource; + struct wined3d_swapchain *swapchain; + void *object = view_vk; TRACE("view_vk %p.\n", view_vk); wined3d_rendertarget_view_cleanup(&view_vk->v); - wined3d_view_vk_destroy(resource->device, NULL, &view_vk->vk_image_view, - NULL, NULL, NULL, &view_vk->command_buffer_id, view_vk); + + if ((swapchain = wined3d_swapchain_from_resource(resource))) + { + if ((swap_view_vk = wined3d_swapchain_rendertarget_view_vk(view_vk))) + { + unsigned int i, count = swapchain->state.desc.backbuffer_count - 1; + struct wined3d_swapchain_rendertarget_view *view; + for (i = 0; i < count; i++) + { + wined3d_view_vk_destroy(resource->device, NULL, &swap_view_vk->vk_swap_views[i], NULL, NULL, NULL, &view_vk->command_buffer_id, NULL); + } + + LIST_FOR_EACH_ENTRY(view, &swapchain->back_buffer_rendertarget_views, struct wined3d_swapchain_rendertarget_view, entry) + { + if (view->view != &view_vk->v) + continue; + + list_remove(&view->entry); + break; + } + object = swap_view_vk; + } + else + { + WARN("Missing wined3d_swapchain_view_vk for view_vk %p.\n", view_vk); + object = view_vk; + } + } + + wined3d_view_vk_destroy(resource->device, NULL, &view_vk->vk_image_view, NULL, NULL, NULL, &view_vk->command_buffer_id, object); } static HRESULT adapter_vk_create_shader_resource_view(const struct wined3d_view_desc *desc, diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index c26df770cdb..1173703b764 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -145,6 +145,11 @@ void wined3d_swapchain_vk_cleanup(struct wined3d_swapchain_vk *swapchain_vk) wined3d_swapchain_cleanup(&swapchain_vk->s); } +struct wined3d_swapchain * __cdecl wined3d_swapchain_from_resource(struct wined3d_resource *resource) +{ + return swapchain_from_resource(resource); +} + ULONG CDECL wined3d_swapchain_incref(struct wined3d_swapchain *swapchain) { unsigned int refcount = InterlockedIncrement(&swapchain->ref); @@ -533,16 +538,51 @@ static void swapchain_gl_set_swap_interval(struct wined3d_swapchain *swapchain, } } +static void wined3d_swapchain_rendertarget_view_gl_rotate(struct wined3d_swapchain *swapchain) +{ + struct wined3d_swapchain_rendertarget_view_gl *swap_view_gl; + struct wined3d_swapchain_rendertarget_view *view; + struct wined3d_rendertarget_view_gl *view_gl; + unsigned int i, count; + GLuint name0; + + if (!swapchain || swapchain->state.desc.backbuffer_count < 2) + return; + + count = swapchain->state.desc.backbuffer_count - 2; + + LIST_FOR_EACH_ENTRY(view, &swapchain->back_buffer_rendertarget_views, struct wined3d_swapchain_rendertarget_view, entry) + { + if (!view->view) + continue; + + view_gl = wined3d_rendertarget_view_gl(view->view); + name0 = view_gl->gl_view.name; + if (!name0) + { + FIXME("Skipping rotate for view_gl %p with name 0 which should not occur.\n", view_gl); + continue; + } + + swap_view_gl = wined3d_swapchain_rendertarget_view_gl(view_gl); + view_gl->gl_view.name = swap_view_gl->gl_swap_views[0]; + for (i = 0; i < count; i++) + swap_view_gl->gl_swap_views[i] = swap_view_gl->gl_swap_views[i + 1]; + + swap_view_gl->gl_swap_views[i] = name0; + } +} + /* Context activation is done by the caller. */ static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context *context) { + static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE; struct wined3d_texture_sub_resource *sub_resource; struct wined3d_texture_gl *texture, *texture_prev; struct gl_texture tex0; - GLuint rb0; DWORD locations0; unsigned int i; - static const DWORD supported_locations = WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_RB_MULTISAMPLE; + GLuint rb0; if (swapchain->state.desc.backbuffer_count < 2) return; @@ -554,6 +594,7 @@ static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, str rb0 = texture_prev->rb_multisample; locations0 = texture_prev->t.sub_resources[0].locations; + for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i) { texture = wined3d_texture_gl(swapchain->back_buffers[i]); @@ -574,6 +615,8 @@ static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, str texture_prev->texture_rgb = tex0; texture_prev->rb_multisample = rb0; + wined3d_swapchain_rendertarget_view_gl_rotate(swapchain); + wined3d_texture_validate_location(&texture_prev->t, 0, locations0 & supported_locations); wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(locations0 & supported_locations)); @@ -645,6 +688,12 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, wined3d_texture_load_location(back_buffer, 0, context, back_buffer->resource.draw_binding); + 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)); + } + swapchain_blit(swapchain, context, src_rect, dst_rect); if (swapchain->device->context_count > 1) @@ -1195,6 +1244,41 @@ static VkResult wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain return vr; } +static void wined3d_swapchain_rendertarget_view_vk_rotate(struct wined3d_swapchain *swapchain) +{ + struct wined3d_swapchain_rendertarget_view_vk *swap_view_vk; + struct wined3d_swapchain_rendertarget_view *view; + struct wined3d_rendertarget_view_vk *view_vk; + VkImageView vk_image_view0; + unsigned int i, count; + + if (!swapchain || swapchain->state.desc.backbuffer_count < 2) + return; + + count = swapchain->state.desc.backbuffer_count - 2; + LIST_FOR_EACH_ENTRY(view, &swapchain->back_buffer_rendertarget_views, struct wined3d_swapchain_rendertarget_view, entry) + { + if (!view->view) + continue; + + view_vk = wined3d_rendertarget_view_vk(view->view); + if (!view_vk->vk_image_view) + { + FIXME("Skipping rotate for view_vk %p with name 0 which should not occur.\n", view_vk); + continue; + } + + swap_view_vk = wined3d_swapchain_rendertarget_view_vk(view_vk); + vk_image_view0 = view_vk->vk_image_view; + view_vk->vk_image_view = swap_view_vk->vk_swap_views[0]; + + for (i = 0; i < count; i++) + swap_view_vk->vk_swap_views[i] = swap_view_vk->vk_swap_views[i + 1]; + + swap_view_vk->vk_swap_views[i] = vk_image_view0; + } +} + static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context_vk *context_vk) { struct wined3d_texture_sub_resource *sub_resource; @@ -1244,6 +1328,8 @@ static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, str texture_prev->bind_mask = bind_mask0; texture_prev->default_image_info = vk_info0; + wined3d_swapchain_rendertarget_view_vk_rotate(swapchain); + wined3d_texture_validate_location(&texture_prev->t, 0, locations0 & supported_locations); wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(locations0 & supported_locations)); @@ -1633,6 +1719,8 @@ static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struc displaymode_set = TRUE; } + list_init(&swapchain->back_buffer_rendertarget_views); + if (swapchain->state.desc.backbuffer_count > 0) { if (!(swapchain->back_buffers = calloc(swapchain->state.desc.backbuffer_count, diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c index a506b0c6f18..dd2d1f9f822 100644 --- a/dlls/wined3d/view.c +++ b/dlls/wined3d/view.c @@ -587,48 +587,99 @@ void wined3d_rendertarget_view_get_box(struct wined3d_rendertarget_view *view, static void wined3d_render_target_view_gl_cs_init(void *object) { + struct wined3d_swapchain_rendertarget_view_gl *swap_view_gl; struct wined3d_rendertarget_view_gl *view_gl = object; + struct wined3d_swapchain_rendertarget_view *lview = NULL; struct wined3d_resource *resource = view_gl->v.resource; const struct wined3d_view_desc *desc = &view_gl->v.desc; + struct wined3d_texture_gl *texture_gl; + struct wined3d_swapchain *swapchain; + unsigned int depth_or_layer_count; + GLenum resource_class, view_class; + struct wined3d_context *context; + unsigned int i, count; + GLuint name; TRACE("view_gl %p.\n", view_gl); if (resource->type == WINED3D_RTYPE_BUFFER) { FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type)); + return; } + + texture_gl = wined3d_texture_gl(texture_from_resource(resource)); + + if (resource->type == WINED3D_RTYPE_TEXTURE_3D) + depth_or_layer_count = wined3d_texture_get_level_depth(&texture_gl->t, desc->u.texture.level_idx); else + depth_or_layer_count = texture_gl->t.layer_count; + + if (resource->format->id == view_gl->v.format->id + && (view_gl->v.layer_count == 1 && view_gl->v.layer_count == depth_or_layer_count)) { - struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture_from_resource(resource)); - unsigned int depth_or_layer_count; + TRACE("Skipping view init because format and layer_count matches underlying texture\n"); + return; + } - if (resource->type == WINED3D_RTYPE_TEXTURE_3D) - depth_or_layer_count = wined3d_texture_get_level_depth(&texture_gl->t, desc->u.texture.level_idx); - else - depth_or_layer_count = texture_gl->t.layer_count; + resource_class = wined3d_format_gl(resource->format)->view_class; + view_class = wined3d_format_gl(view_gl->v.format)->view_class; + if (resource_class != view_class) + { + FIXME("Render target view not supported, resource format %s, view format %s.\n", + debug_d3dformat(resource->format->id), debug_d3dformat(view_gl->v.format->id)); + return; + } - if (resource->format->id != view_gl->v.format->id - || (view_gl->v.layer_count != 1 && view_gl->v.layer_count != depth_or_layer_count)) - { - GLenum resource_class, view_class; + context = context_acquire(resource->device, NULL, 0); + create_texture_view(&view_gl->gl_view, texture_gl->target, desc, texture_gl, view_gl->v.format); + context_release(context); - resource_class = wined3d_format_gl(resource->format)->view_class; - view_class = wined3d_format_gl(view_gl->v.format)->view_class; - if (resource_class != view_class) - { - FIXME("Render target view not supported, resource format %s, view format %s.\n", - 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; - } + if (!view_gl->gl_view.name) + { + ERR("Failed to create render target view for resource %p\n", resource); + /* TODO: cleanup gl, mem? */ + return; + } + + if (!(swapchain = swapchain_from_resource(resource))) + return; - create_texture_view(&view_gl->gl_view, texture_gl->target, desc, texture_gl, view_gl->v.format); + if (!(swap_view_gl = wined3d_swapchain_rendertarget_view_gl(view_gl))) + { + WARN("Missing wined3d_swapchain_rendertarget_view_gl for view_gl %p.\n", view_gl); + return; + } + + context = context_acquire(resource->device, NULL, 0); + count = swapchain->state.desc.backbuffer_count - 1; + name = view_gl->gl_view.name; + for (i = 0; i < count; i++) + { + texture_gl = wined3d_texture_gl(swapchain->back_buffers[i + 1]); + create_texture_view(&view_gl->gl_view, texture_gl->target, desc, texture_gl, view_gl->v.format); + if (view_gl->gl_view.name) + { + swap_view_gl->gl_swap_views[i] = view_gl->gl_view.name; + continue; } + + ERR("Failed to create render target view for swapchain %p backbuffer[%u]\n", swapchain, i); + /* TODO: cleanup gl, mem? */ + context_release(context); + return; + } + view_gl->gl_view.name = name; + context_release(context); + + if (!(lview = calloc(1, sizeof(*lview)))) + { + ERR("Out of memory.\n"); + /* TODO: cleanup gl, mem? */ + return; } + list_add_head(&swapchain->back_buffer_rendertarget_views, &lview->entry); + lview->view = &view_gl->v; } static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, @@ -896,14 +947,18 @@ static VkImageView wined3d_view_vk_create_vk_image_view(struct wined3d_context_v static void wined3d_render_target_view_vk_cs_init(void *object) { + struct wined3d_swapchain_rendertarget_view_vk *swap_view_vk; + struct wined3d_swapchain_rendertarget_view *lview = NULL; struct wined3d_rendertarget_view_vk *view_vk = object; struct wined3d_view_desc *desc = &view_vk->v.desc; const struct wined3d_format_vk *format_vk; struct wined3d_texture_vk *texture_vk; + struct wined3d_swapchain *swapchain; struct wined3d_resource *resource; struct wined3d_context *context; VkImageUsageFlags vk_usage = 0; uint32_t default_flags = 0; + unsigned int i, count; TRACE("view_vk %p.\n", view_vk); @@ -930,12 +985,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) @@ -947,8 +996,48 @@ static void wined3d_render_target_view_vk_cs_init(void *object) context_release(context); if (!view_vk->vk_image_view) + { + ERR("Failed to create render target view for resource %p\n", resource); + /* TODO: cleanup gl, mem? */ + return; + } + + if (!(swapchain = swapchain_from_resource(resource))) return; + if (!(swap_view_vk = wined3d_swapchain_rendertarget_view_vk(view_vk))) + { + WARN("Missing wined3d_swapchain_view_vk for view_vk %p.\n", view_vk); + return; + } + + context = context_acquire(resource->device, NULL, 0); + count = swapchain->state.desc.backbuffer_count - 1; + for (i = 0; i < count; i++) + { + texture_vk = wined3d_texture_vk(swapchain->back_buffers[i + 1]); + swap_view_vk->vk_swap_views[i] = wined3d_view_vk_create_vk_image_view(wined3d_context_vk(context), + desc, texture_vk, format_vk, COLOR_FIXUP_IDENTITY, true, vk_usage); + if (view_vk->vk_image_view) + continue; + + ERR("Failed to create render target view for swapchain %p backbuffer[%u]\n", swapchain, i); + context_release(context); + /* TODO: cleanup gl, mem? */ + return; + } + context_release(context); + + if (!(lview = calloc(1, sizeof(*lview)))) + { + ERR("Out of memory.\n"); + /* TODO: cleanup gl, mem? */ + return; + } + + list_add_head(&swapchain->back_buffer_rendertarget_views, &lview->entry); + lview->view = &view_vk->v; + TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(view_vk->vk_image_view)); } @@ -979,6 +1068,7 @@ HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *d wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view); adapter_ops = resource->device->adapter->adapter_ops; + return adapter_ops->adapter_create_rendertarget_view(desc, resource, parent, parent_ops, view); } diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index e08dd089521..00438617093 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -306,6 +306,7 @@ @ cdecl wined3d_swapchain_get_parent(ptr) @ cdecl wined3d_swapchain_get_raster_status(ptr ptr) @ cdecl wined3d_swapchain_get_state(ptr) +@ cdecl wined3d_swapchain_from_resource(ptr) @ cdecl wined3d_swapchain_incref(ptr) @ cdecl wined3d_swapchain_present(ptr ptr ptr ptr long long) @ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long) diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index c9c7118c59e..709b7fafed5 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -1084,6 +1084,21 @@ struct wined3d_rendertarget_view_gl struct wined3d_gl_view gl_view; }; +struct wined3d_swapchain_rendertarget_view_gl +{ + struct wined3d_rendertarget_view_gl view_gl; + GLuint gl_swap_views[29]; /* D3DPRESENT_BACK_BUFFERS_MAX_EX - 1 for view_gl->gl_image_view */ +}; + +static inline struct wined3d_swapchain_rendertarget_view_gl *wined3d_swapchain_rendertarget_view_gl( + struct wined3d_rendertarget_view_gl *view_gl) +{ + if (!view_gl || !wined3d_swapchain_from_resource(view_gl->v.resource)) + return NULL; + + return CONTAINING_RECORD(view_gl, struct wined3d_swapchain_rendertarget_view_gl, view_gl); +} + static inline struct wined3d_rendertarget_view_gl *wined3d_rendertarget_view_gl( struct wined3d_rendertarget_view *view) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e4e0cf24dc7..d95dc35d3b3 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3563,8 +3563,7 @@ BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned struct wined3d_context *context, uint32_t location); void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain); -BOOL wined3d_texture_can_use_pbo(const struct wined3d_texture *texture, const struct wined3d_d3d_info *d3d_info) - ; +BOOL wined3d_texture_can_use_pbo(const struct wined3d_texture *texture, const struct wined3d_d3d_info *d3d_info); void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture); void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *texture, HWND window, RECT *rect); @@ -4094,6 +4093,12 @@ struct wined3d_swapchain_ops void (*swapchain_frontbuffer_updated)(struct wined3d_swapchain *swapchain); }; +struct wined3d_swapchain_rendertarget_view +{ + struct list entry; + struct wined3d_rendertarget_view *view; +}; + struct wined3d_swapchain { LONG ref; @@ -4101,16 +4106,16 @@ struct wined3d_swapchain const struct wined3d_parent_ops *parent_ops; const struct wined3d_swapchain_ops *swapchain_ops; struct wined3d_device *device; - struct wined3d_texture **back_buffers; struct wined3d_texture *front_buffer; + struct list back_buffer_rendertarget_views; + struct wined3d_gamma_ramp orig_gamma; bool reapply_mode; const struct wined3d_format *ds_format; struct wined3d_palette *palette; RECT front_buffer_update; - unsigned int swap_interval; - unsigned int max_frame_latency; + unsigned int swap_interval, max_frame_latency; /* Performance tracking */ LARGE_INTEGER last_present_time; @@ -4121,6 +4126,14 @@ struct wined3d_swapchain HDC dc; }; +static inline struct wined3d_swapchain *swapchain_from_resource(struct wined3d_resource *resource) +{ + if (!resource || resource->type != WINED3D_RTYPE_TEXTURE_2D) + return NULL; + + return texture_from_resource(resource)->swapchain; +} + void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate); void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain); struct wined3d_output * wined3d_swapchain_get_output(const struct wined3d_swapchain *swapchain); diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index 937a958760c..fafde8c0699 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -1039,6 +1039,21 @@ struct wined3d_rendertarget_view_vk uint64_t command_buffer_id; }; +struct wined3d_swapchain_rendertarget_view_vk +{ + struct wined3d_rendertarget_view_vk view_vk; + VkImageView vk_swap_views[29]; /* D3DPRESENT_BACK_BUFFERS_MAX_EX - 1 for view_vk->vk_image_view */ +}; + +static inline struct wined3d_swapchain_rendertarget_view_vk *wined3d_swapchain_rendertarget_view_vk( + struct wined3d_rendertarget_view_vk *view_vk) +{ + if (!view_vk || !wined3d_swapchain_from_resource(view_vk->v.resource)) + return NULL; + + return CONTAINING_RECORD(view_vk, struct wined3d_swapchain_rendertarget_view_vk, view_vk); +} + static inline struct wined3d_rendertarget_view_vk *wined3d_rendertarget_view_vk( struct wined3d_rendertarget_view *view) { diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 355140043db..a2e60493a22 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2914,6 +2914,7 @@ void __cdecl wined3d_swapchain_get_desc(const struct wined3d_swapchain *swapchai HRESULT __cdecl wined3d_swapchain_get_raster_status(const struct wined3d_swapchain *swapchain, struct wined3d_raster_status *raster_status); struct wined3d_swapchain_state * __cdecl wined3d_swapchain_get_state(struct wined3d_swapchain *swapchain); +struct wined3d_swapchain * __cdecl wined3d_swapchain_from_resource(struct wined3d_resource *resource); ULONG __cdecl wined3d_swapchain_incref(struct wined3d_swapchain *swapchain); HRESULT __cdecl wined3d_swapchain_present(struct wined3d_swapchain *swapchain, const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, unsigned int swap_interval, uint32_t flags); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10567
Detection of swapchain backbuffer format casting support has been corrected based on @hverbeet suggestion to check D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST instead of feature_level. `wined3d_rendertarget_view` is no longer handles extra rtvs per swapchain backbuffers. Instead `struct wined3d_swapchain_rendertarget_view_gl` now handles extra views via `GLuint gl_swap_views[29]` and `struct wined3d_swapchain_rendertarget_view_vk` handles via `VkImageView vk_swap_views[29]`. Extra backbuffer views array size 29 (D3DPRESENT_BACK_BUFFERS_MAX_EX - 1) was chosen instead of a list. D3DPRESENT_BACK_BUFFERS_MAX_EX is from d3d9 and I did not find max equiv for d3d10+. Is d3d10+ bounded by something other than D3DPRESENT_BACK_BUFFERS_MAX_EX? Maybe the array is better handled by a list but array was chosen to keep memory packed despite costing extra space because the overhead seems likely negligible given there will probably never be too many RTVs for swapchain backbuffers. Latest patch also leaves d3d9 untouched because new swapchain backbuffer rtvs are now handled entirely within wined3d. d3d8/9 tests seem to pass but unclear if they still need to be adjusted to account for new `wined3d_swapchain struct list back_buffer_rendertarget_views;`. d3d8/9 are able to create rtvs for any swapchain backbuffer vs just the first for d3d10/11 and seem not to support different formats from the swapchain backbuffers, so the latest changes should not apply. wined3d logic seems to skip creating actual views when format and layer count matches so I think d3d8/9 should be unaffected by this patch but still needs to be tested more. Wine server tests pass but it seems to only run gl and not vulkan/damavand because vk fails for my local tests. Previous patch passed for both vk and gl so something like `vk_blitter_clear_rendertargets` may need to be fixed to handle the new impl. Frostpunk works for both gl and vk so vk bug seems related to blit_clear which works for gl. Besides pending vk blit_clear fixes, this latest patch seems ready enough for another review. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_144308
This is hard to read and could probably do with quite a lot of splitting. In particular: * D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST implementation can be its own commit It also should not use a fixed list of formats, and should live in wined3d like all the other format flags. * D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST validation similarly can be its own commit, and also should live in wined3d. Actually, you seem to unnecessarily have it in both places? * Tracking the list of swapchain views, while not doing anything with them yet, can be its own commit. * GL and Vulkan rotate implementations should ideally be separated. * Disabling GL_FRAMEBUFFER_SRGB on swapchain blit is still wrong, as Henri said. (Moving it back "to fix test failures" is not correct; you need to understand why it *should* be there.) And that should be its own commit; it's not related to the rest of this. * Diffs like this should just be avoided entirely: ``` - unsigned int swap_interval; - unsigned int max_frame_latency; + unsigned int swap_interval, max_frame_latency; ``` * I would not use the fixed array size of 29; just allocate it dynamically instead the same as we do for the actual list of backbuffers. With that done, wined3d_swapchain_rendertarget_view_gl is fairly unnecessary; it's just a single pointer that can be put directly in wined3d_rendertarget_view like the others. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_144322
On Fri Jun 26 16:05:47 2026 +0000, Elizabeth Figura wrote:
This is hard to read and could probably do with quite a lot of splitting. In particular: * D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST implementation can be its own commit It also should not use a fixed list of formats, and should live in wined3d like all the other format flags. * D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST validation similarly can be its own commit, and also should live in wined3d. Actually, you seem to unnecessarily have it in both places? * Tracking the list of swapchain views, while not doing anything with them yet, can be its own commit. * GL and Vulkan rotate implementations should ideally be separated. * Disabling GL_FRAMEBUFFER_SRGB on swapchain blit is still wrong, as Henri said. (Moving it back "to fix test failures" is not correct; you need to understand why it *should* be there.) And that should be its own commit; it's not related to the rest of this. * Diffs like this should just be avoided entirely: ``` - unsigned int swap_interval; - unsigned int max_frame_latency; + unsigned int swap_interval, max_frame_latency; ``` * I would not use the fixed array size of 29; just allocate it dynamically instead the same as we do for the actual list of backbuffers. With that done, wined3d_swapchain_rendertarget_view_gl is fairly unnecessary; it's just a single pointer that can be put directly in wined3d_rendertarget_view like the others. Thanks for review. I'll split as multiple commits so its easier to digest and include the other changes as you recommended.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10567#note_144323
participants (3)
-
Elizabeth Figura (@zfigura) -
Stian Low -
Stian Low (@stianlow)