[PATCH 0/3] MR10874: d3d8: Do not support multisampling for 16-bit formats.
Star Wars Starfighter depends upon `Reset()` failing when it tries to enable multisampling, because it calls `LockRect()` on the back buffer, leaving it in WINED3D_LOCATION_SYSMEM which later hits "Not supported for multisample textures" in `wined3d_texture_gl_upload_data()`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10874
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/d3d8/tests/device.c | 95 +++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index 02383233cff..ff14cac9dec 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -9507,26 +9507,36 @@ static void test_clip_planes_limits(void) static void test_swapchain_multisample_reset(void) { D3DPRESENT_PARAMETERS present_parameters; + IDirect3DSurface8 *surface; + unsigned int i, windowed; IDirect3DDevice8 *device; + D3DLOCKED_RECT lr; IDirect3D8 *d3d; ULONG refcount; HWND window; HRESULT hr; + static const struct + { + const char *name; + D3DFORMAT format; + HRESULT expected_hr; + BOOL todo; + } + formats[] = + { + {"D3DFMT_R5G6B5", D3DFMT_R5G6B5, D3DERR_INVALIDCALL, TRUE}, + {"D3DFMT_X1R5G5B5", D3DFMT_X1R5G5B5, D3DERR_INVALIDCALL, TRUE}, + {"D3DFMT_A1R5G5B5", D3DFMT_A1R5G5B5, D3DERR_INVALIDCALL, TRUE}, + {"D3DFMT_X8R8G8B8", D3DFMT_X8R8G8B8}, + {"D3DFMT_A8R8G8B8", D3DFMT_A8R8G8B8}, + }; + window = create_window(); ok(!!window, "Failed to create a window.\n"); d3d = Direct3DCreate8(D3D_SDK_VERSION); ok(!!d3d, "Failed to create D3D object.\n"); - if (IDirect3D8_CheckDeviceMultiSampleType(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, - D3DFMT_A8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES) == D3DERR_NOTAVAILABLE) - { - skip("Multisampling not supported for D3DFMT_A8R8G8B8.\n"); - IDirect3D8_Release(d3d); - DestroyWindow(window); - return; - } - if (!(device = create_device(d3d, window, NULL))) { skip("Failed to create 3D device.\n"); @@ -9538,19 +9548,62 @@ static void test_swapchain_multisample_reset(void) hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); ok(hr == D3D_OK, "Failed to clear, hr %#lx.\n", hr); - memset(&present_parameters, 0, sizeof(present_parameters)); - present_parameters.BackBufferWidth = 640; - present_parameters.BackBufferHeight = 480; - present_parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; - present_parameters.hDeviceWindow = NULL; - present_parameters.Windowed = TRUE; - present_parameters.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; - hr = IDirect3DDevice8_Reset(device, &present_parameters); - ok(hr == D3D_OK, "Failed to reset device, hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(formats); ++i) + { + for (windowed = 0; windowed < 2; ++windowed) + { + winetest_push_context("Test %u, format %s, windowed %u", i, formats[i].name, windowed); - hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0f, 0); - ok(hr == D3D_OK, "Failed to clear, hr %#lx.\n", hr); + if (FAILED(hr = IDirect3D8_CheckDeviceMultiSampleType(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + formats[i].format, windowed, D3DMULTISAMPLE_2_SAMPLES))) + { + ok(hr == D3DERR_NOTAVAILABLE, "Unexpected hr %#lx.\n", hr); + skip("Multisampling not supported.\n"); + winetest_pop_context(); + continue; + } + + memset(&present_parameters, 0, sizeof(present_parameters)); + present_parameters.BackBufferWidth = 640; + present_parameters.BackBufferHeight = 480; + present_parameters.BackBufferFormat = formats[i].format; + present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + present_parameters.hDeviceWindow = window; + present_parameters.Windowed = windowed; + present_parameters.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; + hr = IDirect3DDevice8_Reset(device, &present_parameters); + todo_wine_if(formats[i].todo) + ok(hr == formats[i].expected_hr, "Unexpected hr %#lx.\n", hr); + + if (FAILED(hr)) + { + winetest_pop_context(); + continue; + } + + hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0f, 0); + ok(hr == D3D_OK, "Failed to clear, hr %#lx.\n", hr); + + /* Lockable back buffer flag is allowed. */ + present_parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + hr = IDirect3DDevice8_Reset(device, &present_parameters); + ok(hr == D3D_OK, "Failed to reset device, hr %#lx.\n", hr); + + hr = IDirect3DDevice8_GetBackBuffer(device, 0, D3DBACKBUFFER_TYPE_MONO, &surface); + ok(SUCCEEDED(hr), "GetBackBuffer failed, hr %#lx.\n", hr); + + /* But locking is not allowed. */ + hr = IDirect3DSurface8_LockRect(surface, &lr, NULL, 0); + todo_wine + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + IDirect3DSurface8_UnlockRect(surface); + + IDirect3DSurface8_Release(surface); + + winetest_pop_context(); + } + } refcount = IDirect3DDevice8_Release(device); ok(!refcount, "Device has %lu references left.\n", refcount); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10874
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/d3d8/surface.c | 11 +++++++++++ dlls/d3d8/tests/device.c | 3 --- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/d3d8/surface.c b/dlls/d3d8/surface.c index 5b02035d539..23a1a4b14eb 100644 --- a/dlls/d3d8/surface.c +++ b/dlls/d3d8/surface.c @@ -210,10 +210,21 @@ static HRESULT WINAPI d3d8_surface_LockRect(IDirect3DSurface8 *iface, struct wined3d_map_desc map_desc; HRESULT hr; D3DRESOURCETYPE type; + D3DSURFACE_DESC desc; TRACE("iface %p, locked_rect %p, rect %s, flags %#lx.\n", iface, locked_rect, wine_dbgstr_rect(rect), flags); + IDirect3DSurface8_GetDesc(iface, &desc); + + if (desc.MultiSampleType) + { + WARN("Trying to lock a multisampled surface, returning D3DERR_INVALIDCALL.\n"); + locked_rect->Pitch = 0; + locked_rect->pBits = NULL; + return D3DERR_INVALIDCALL; + } + wined3d_mutex_lock(); if (surface->texture) diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index ff14cac9dec..019340b191e 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -9594,10 +9594,7 @@ static void test_swapchain_multisample_reset(void) /* But locking is not allowed. */ hr = IDirect3DSurface8_LockRect(surface, &lr, NULL, 0); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - IDirect3DSurface8_UnlockRect(surface); IDirect3DSurface8_Release(surface); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10874
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/d3d8/device.c | 19 +++++++++++++++++++ dlls/d3d8/tests/device.c | 8 +++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 036c60edc37..3ff36fc65fb 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -937,6 +937,20 @@ static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource) return D3DERR_DEVICELOST; } +static BOOL d3d_format_check_multisampled_support(D3DFORMAT format) +{ + switch (format) + { + /* 16-bit format support was patchy as far back as Windows XP, but is nonexistent now. */ + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + return FALSE; + default: + return TRUE; + } +} + static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface, D3DPRESENT_PARAMETERS *present_parameters) { @@ -953,6 +967,11 @@ static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface, WARN("App not active, returning D3DERR_DEVICELOST.\n"); return D3DERR_DEVICELOST; } + + if (present_parameters->MultiSampleType + && !d3d_format_check_multisampled_support(present_parameters->BackBufferFormat)) + return D3DERR_INVALIDCALL; + output_idx = device->adapter_ordinal; if (!wined3d_swapchain_desc_from_d3d8(&swapchain_desc, device->d3d_parent->wined3d_outputs[output_idx], present_parameters)) diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index 019340b191e..250c04c7f51 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -9521,13 +9521,12 @@ static void test_swapchain_multisample_reset(void) const char *name; D3DFORMAT format; HRESULT expected_hr; - BOOL todo; } formats[] = { - {"D3DFMT_R5G6B5", D3DFMT_R5G6B5, D3DERR_INVALIDCALL, TRUE}, - {"D3DFMT_X1R5G5B5", D3DFMT_X1R5G5B5, D3DERR_INVALIDCALL, TRUE}, - {"D3DFMT_A1R5G5B5", D3DFMT_A1R5G5B5, D3DERR_INVALIDCALL, TRUE}, + {"D3DFMT_R5G6B5", D3DFMT_R5G6B5, D3DERR_INVALIDCALL}, + {"D3DFMT_X1R5G5B5", D3DFMT_X1R5G5B5, D3DERR_INVALIDCALL}, + {"D3DFMT_A1R5G5B5", D3DFMT_A1R5G5B5, D3DERR_INVALIDCALL}, {"D3DFMT_X8R8G8B8", D3DFMT_X8R8G8B8}, {"D3DFMT_A8R8G8B8", D3DFMT_A8R8G8B8}, }; @@ -9572,7 +9571,6 @@ static void test_swapchain_multisample_reset(void) present_parameters.Windowed = windowed; present_parameters.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; hr = IDirect3DDevice8_Reset(device, &present_parameters); - todo_wine_if(formats[i].todo) ok(hr == formats[i].expected_hr, "Unexpected hr %#lx.\n", hr); if (FAILED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10874
This should almost certainly happen in wined3d. Does d3d9 or d3d10 allow multisampling of 16-bit formats? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10874#note_139591
On Wed May 13 14:49:08 2026 +0000, Elizabeth Figura wrote:
This should almost certainly happen in wined3d. Does d3d9 or d3d10 allow multisampling of 16-bit formats? d3d9 is a bit different. It allows 16-bit for windowed devices, and doesn't allow the lockable flag. I haven't found any code in wined3d which checks for d3d8 vs d3d9. Is there an established way to do that and should it be done at all?
The d3d10 module has very few tests, so I haven't tested it in d3d10. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10874#note_139707
participants (3)
-
Conor McCarthy -
Conor McCarthy (@cmccarthy) -
Elizabeth Figura (@zfigura)