[PATCH 6/6] d2d1: Support D3D11 interop using ID3DDeviceContextState.

Rémi Bernon rbernon at codeweavers.com
Mon Jan 18 06:57:46 CST 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49395
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/d2d1/d2d1_private.h |  6 ++++-
 dlls/d2d1/device.c       | 54 ++++++++++++++++++++++++++++++++++++++++
 dlls/d2d1/tests/d2d1.c   |  2 +-
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index cb3421478f0..e2794c8b1a2 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -27,7 +27,7 @@
 #include <math.h>
 #define COBJMACROS
 #include "d2d1_2.h"
-#include "d3d11.h"
+#include "d3d11_1.h"
 #ifdef D2D1_INIT_GUID
 #include "initguid.h"
 #endif
@@ -539,6 +539,10 @@ struct d2d_device
     ID2D1Factory1 *factory;
     IDXGIDevice *dxgi_device;
     ID3D10Device *d3d10_device;
+    ID3D11Device1 *d3d11_device;
+    ID3DDeviceContextState *d3d_dc_state;
+    ID3DDeviceContextState *prev_d3d_dc_state;
+    LONG d3d_dc_state_recursion;
     ID3D10Multithread *d3d10_mt;
 };
 
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c
index cfa28e984f9..11722a19eed 100644
--- a/dlls/d2d1/device.c
+++ b/dlls/d2d1/device.c
@@ -2864,6 +2864,7 @@ static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_targe
 HRESULT d2d_device_get_d3d10_device(ID2D1Device *iface, ID3D10Device **d3d10_device)
 {
     struct d2d_device *device = unsafe_impl_from_ID2D1Device(iface);
+    ID3D11DeviceContext1 *d3d11_context;
 
     if (!device->d3d10_device)
     {
@@ -2873,6 +2874,16 @@ HRESULT d2d_device_get_d3d10_device(ID2D1Device *iface, ID3D10Device **d3d10_dev
 
     if (device->d3d10_mt) ID3D10Multithread_Enter(device->d3d10_mt);
 
+    if (device->d3d11_device && !device->d3d_dc_state_recursion)
+    {
+        ID3D11Device1_GetImmediateContext1(device->d3d11_device, &d3d11_context);
+        ID3D11DeviceContext1_SwapDeviceContextState(d3d11_context, device->d3d_dc_state, &device->prev_d3d_dc_state);
+        ID3D11DeviceContext1_Release(d3d11_context);
+        device->d3d_dc_state_recursion = 1;
+    }
+    else if (device->d3d_dc_state_recursion)
+        device->d3d_dc_state_recursion++;
+
     ID3D10Device_AddRef(*d3d10_device = device->d3d10_device);
     return S_OK;
 }
@@ -2880,6 +2891,16 @@ HRESULT d2d_device_get_d3d10_device(ID2D1Device *iface, ID3D10Device **d3d10_dev
 void d2d_device_release_d3d10_device(ID2D1Device *iface, ID3D10Device *d3d10_device)
 {
     struct d2d_device *device = unsafe_impl_from_ID2D1Device(iface);
+    ID3D11DeviceContext1 *d3d11_context;
+
+    if (device->d3d11_device && !--device->d3d_dc_state_recursion)
+    {
+        ID3D11Device1_GetImmediateContext1(device->d3d11_device, &d3d11_context);
+        ID3D11DeviceContext1_SwapDeviceContextState(d3d11_context, device->prev_d3d_dc_state, NULL);
+        ID3DDeviceContextState_Release(device->prev_d3d_dc_state);
+        ID3D11DeviceContext1_Release(d3d11_context);
+        device->prev_d3d_dc_state = NULL;
+    }
 
     ID3D10Device_Release(d3d10_device);
 
@@ -4208,6 +4229,8 @@ static ULONG WINAPI d2d_device_Release(ID2D1Device *iface)
     if (!refcount)
     {
         if (device->d3d10_mt) ID3D10Multithread_Release(device->d3d10_mt);
+        if (device->d3d_dc_state) ID3DDeviceContextState_Release(device->d3d_dc_state);
+        if (device->d3d11_device) ID3D11Device1_Release(device->d3d11_device);
         if (device->d3d10_device) ID3D10Device_Release(device->d3d10_device);
         IDXGIDevice_Release(device->dxgi_device);
         ID2D1Factory1_Release(device->factory);
@@ -4324,8 +4347,39 @@ void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *iface, IDXGIDevic
 
     if (FAILED(hr = IDXGIDevice_QueryInterface(device->dxgi_device,
             &IID_ID3D10Device, (void **)&device->d3d10_device)))
+    {
+        ID3D11DeviceContext1 *d3d11_context;
+        DWORD levels = D3D_FEATURE_LEVEL_10_1;
+
+        if (FAILED(hr = IDXGIDevice_QueryInterface(device->dxgi_device,
+                &IID_ID3D11Device1, (void **)&device->d3d11_device)))
+            goto done;
+
+        if (FAILED(hr = ID3D11Device1_CreateDeviceContextState(device->d3d11_device, 0,
+                &levels, 1, D3D11_SDK_VERSION, &IID_ID3D10Device, NULL, &device->d3d_dc_state)))
+            goto done;
+
+        ID3D11Device1_GetImmediateContext1(device->d3d11_device, &d3d11_context);
+
+        if (device->d3d10_mt) ID3D10Multithread_Enter(device->d3d10_mt);
+        ID3D11DeviceContext1_SwapDeviceContextState(d3d11_context, device->d3d_dc_state, &device->prev_d3d_dc_state);
+        hr = ID3D11Device1_QueryInterface(device->d3d11_device, &IID_ID3D10Device, (void **)&device->d3d10_device);
+        ID3D11DeviceContext1_SwapDeviceContextState(d3d11_context, device->prev_d3d_dc_state, NULL);
+        if (device->d3d10_mt) ID3D10Multithread_Leave(device->d3d10_mt);
+
+        ID3DDeviceContextState_Release(device->prev_d3d_dc_state);
+        ID3D11DeviceContext1_Release(d3d11_context);
+        device->prev_d3d_dc_state = NULL;
+    }
+
+done:
+    if (FAILED(hr))
     {
         WARN("Failed to get device interface, hr %#x.\n", hr);
         device->d3d10_device = NULL;
+        if (device->d3d_dc_state) ID3DDeviceContextState_Release(device->d3d_dc_state);
+        device->d3d_dc_state = NULL;
+        if (device->d3d11_device) ID3D11Device1_Release(device->d3d11_device);
+        device->d3d11_device = NULL;
     }
 }
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 3e7df715dda..a1166b1ebb8 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -921,7 +921,7 @@ static ID2D1RenderTarget *create_render_target_desc(IDXGISurface *surface,
     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory);
     ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr);
     hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory, surface, desc, &render_target);
-    todo_wine_if(d3d11) ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
+    ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
     ID2D1Factory_Release(factory);
 
     if (FAILED(hr))
-- 
2.30.0




More information about the wine-devel mailing list