From: Stian Low <wineryyyyy@gmail.com> This is a somewhat risky change. As described in the patch, many applications are known to use this flag despite not actually requiring video support. Coincidentally, all known such applications are Media Foundation users which also happen to require shared resources, which are not yet implemented, and so already do not work. However, shared resources are not actually necessary to use Media Foundation, nor are they used internally by Media Foundation, and it is still quite possible that applications exist which require this flag and currently work. To make matters worse, while the existence of some degree of hardware video support can reasonably be assumed by anyone using a real GPU these days, the same cannot quite be said of Wine. Vulkan video support is relatively young, and not actually enabled by default on all major drivers; whereas VA support is an optional dependency which is far less ubiquitously installed. Additionally, problems related to patents mean that hardware decode support may not actually be available in Free Software distributions even if the hardware and drivers support them. Hence, even if we were to implement shared resources, this change could potentially prevent games from working. Still, this appears to be a correct change, and the way it's implemented here should cause no known regressions. All of the above concerns are only hypothetical at the moment. By a happy coincidence, allowing device creation to fail here also causes the Unity3D video player, which currently fails due to missing shared resource support, to use a fallback path. This fixes many Unity3D games, including Haven, Ashes of the Sun, and The Room 4. --- dlls/d3d11/d3d11_main.c | 5 +++++ dlls/d3d11/tests/d3d11.c | 7 ++++--- dlls/dxgi/device.c | 28 +++++++++++++++++++++++++++- dlls/dxgi/dxgi_main.c | 4 ++-- dlls/dxgi/dxgi_private.h | 3 ++- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/dlls/d3d11/d3d11_main.c b/dlls/d3d11/d3d11_main.c index 75986318693..e0e5c04546a 100644 --- a/dlls/d3d11/d3d11_main.c +++ b/dlls/d3d11/d3d11_main.c @@ -183,6 +183,11 @@ static HRESULT d3d11_create_device(IDXGIAdapter *adapter, D3D_DRIVER_TYPE driver } else { + /* Windows allows device creation to succeed in this case even if the + * chosen device lacks video support. See also dxgi_device_init(). */ + if (driver_type == D3D_DRIVER_TYPE_HARDWARE) + flags &= ~D3D11_CREATE_DEVICE_VIDEO_SUPPORT; + hr = CreateDXGIFactory1(&IID_IDXGIFactory, (void **)&factory); if (FAILED(hr)) { diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 782b50f8507..ce745d35ef2 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -37625,7 +37625,8 @@ static void test_video_support(void) else if (driver_types[i] == D3D_DRIVER_TYPE_UNKNOWN || driver_types[i] == D3D_DRIVER_TYPE_SOFTWARE) todo_wine ok(hr == E_INVALIDARG, "Got %#lx.\n", hr); else - todo_wine ok(hr == DXGI_ERROR_UNSUPPORTED, "Got %#lx.\n", hr); + todo_wine_if(driver_types[i] != D3D_DRIVER_TYPE_WARP || damavand) + ok(hr == DXGI_ERROR_UNSUPPORTED, "Got %#lx.\n", hr); if (hr == S_OK) ID3D11Device_Release(device); @@ -37644,7 +37645,7 @@ static void test_video_support(void) ok(hr == S_OK, "Got %#lx.\n", hr); count = ID3D11VideoDevice_GetVideoDecoderProfileCount(video_device); - todo_wine ok(count > 0, "Got no decoder profiles.\n"); + ok(count > 0, "Got no decoder profiles.\n"); ID3D11Device_Release(device); } @@ -37660,7 +37661,7 @@ static void test_video_support(void) hr = D3D11CreateDevice(adapter, driver_types[i], NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); if (driver_types[i] == D3D_DRIVER_TYPE_UNKNOWN) - todo_wine ok(hr == DXGI_ERROR_UNSUPPORTED, "Got %#lx.\n", hr); + todo_wine_if(damavand) ok(hr == DXGI_ERROR_UNSUPPORTED, "Got %#lx.\n", hr); else todo_wine ok(hr == E_INVALIDARG, "Got %#lx.\n", hr); if (hr == S_OK) diff --git a/dlls/dxgi/device.c b/dlls/dxgi/device.c index eedcc81d845..0d95fe4b645 100644 --- a/dlls/dxgi/device.c +++ b/dlls/dxgi/device.c @@ -485,7 +485,7 @@ static const struct IWineDXGISwapChainFactoryVtbl dxgi_swapchain_factory_vtbl = }; HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *layer, - IDXGIFactory *factory, IDXGIAdapter *adapter, + IDXGIFactory *factory, IDXGIAdapter *adapter, unsigned int flags, const D3D_FEATURE_LEVEL *feature_levels, unsigned int level_count) { struct wined3d_device_parent *wined3d_device_parent; @@ -511,6 +511,32 @@ HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *l return E_FAIL; } + /* Unlike other flags, this flag does not change device behaviour, but + * instead causes creation to fail if "video support" is not available. + * + * The name implies this means d3d11 video decode support. The documentation + * is less clear, and states that the display driver must support WDDM 1.2. + * WDDM 1.2 seems to include d3d11 video support, among other things. + * + * What muddies the issue is that it's not clear that WDDM 1.2 requires that + * the device is capable of actually decoding any specific codec. In + * practice, probably the only WDDM 1.2 driver which doesn't support any + * video codecs is WARP, which, confusingly, fails when D3D11CreateDevice() + * is called with the WARP adapter, but succeeds when called with a NULL + * adapter (assuming of course no hardware display driver is available.) + * Also, Media Foundation documents that this flag must be used on devices + * used with IMFDXGIDeviceManager, but Media Foundation as a whole does not + * depend on hardware decoding or video processing. + * + * Known applications using this flag seem to either directly use decode + * APIs, or IMFDXGIDeviceManager. */ + if ((flags & D3D11_CREATE_DEVICE_VIDEO_SUPPORT) + && !wined3d_adapter_get_decode_profile_count(dxgi_adapter->wined3d_adapter)) + { + WARN("Device does not support video decode; returning DXGI_ERROR_UNSUPPORTED.\n"); + return DXGI_ERROR_UNSUPPORTED; + } + device->IWineDXGIDevice_iface.lpVtbl = &dxgi_device_vtbl; device->IWineDXGISwapChainFactory_iface.lpVtbl = &dxgi_swapchain_factory_vtbl; device->refcount = 1; diff --git a/dlls/dxgi/dxgi_main.c b/dlls/dxgi/dxgi_main.c index ca1fb525535..0e2c23806ba 100644 --- a/dlls/dxgi/dxgi_main.c +++ b/dlls/dxgi/dxgi_main.c @@ -145,7 +145,7 @@ HRESULT WINAPI DXGID3D10CreateDevice(HMODULE d3d10core, IDXGIFactory *factory, I TRACE("d3d10core %p, factory %p, adapter %p, flags %#x, feature_levels %p, level_count %u, device %p.\n", d3d10core, factory, adapter, flags, feature_levels, level_count, device); - if (flags) + if (flags & ~D3D11_CREATE_DEVICE_VIDEO_SUPPORT) FIXME("Ignoring flags %#x.\n", flags); if (TRACE_ON(dxgi)) @@ -191,7 +191,7 @@ HRESULT WINAPI DXGID3D10CreateDevice(HMODULE d3d10core, IDXGIFactory *factory, I return E_OUTOFMEMORY; } - hr = dxgi_device_init(dxgi_device, &d3d10_layer, factory, adapter, feature_levels, level_count); + hr = dxgi_device_init(dxgi_device, &d3d10_layer, factory, adapter, flags, feature_levels, level_count); if (FAILED(hr)) { WARN("Failed to initialize device, hr %#lx.\n", hr); diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index ed82d366799..6ecd5751243 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -32,6 +32,7 @@ #include "dxgi1_6.h" #include "d3d10_1.h" +#include "d3d11.h" #include "d3d12.h" #ifdef DXGI_INIT_GUID #include "initguid.h" @@ -138,7 +139,7 @@ struct dxgi_device }; HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *layer, - IDXGIFactory *factory, IDXGIAdapter *adapter, + IDXGIFactory *factory, IDXGIAdapter *adapter, unsigned int flags, const D3D_FEATURE_LEVEL *feature_levels, unsigned int level_count); /* IDXGIOutput */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11720