[PATCH] dxva2: Implement locking functionality in device manager.

Nikolay Sivov nsivov at codeweavers.com
Tue Jun 30 04:35:59 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dxva2/main.c        |  94 +++++++++++++++++++++++++++++++--
 dlls/dxva2/tests/dxva2.c | 110 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 199 insertions(+), 5 deletions(-)

diff --git a/dlls/dxva2/main.c b/dlls/dxva2/main.c
index 4a51410d4b6..dd949b3d316 100644
--- a/dlls/dxva2/main.c
+++ b/dlls/dxva2/main.c
@@ -42,6 +42,7 @@ enum device_handle_flags
 struct device_handle
 {
     unsigned int flags;
+    IDirect3DStateBlock9 *state_block;
 };
 
 struct device_manager
@@ -57,7 +58,10 @@ struct device_manager
     size_t count;
     size_t capacity;
 
+    HANDLE locking_handle;
+
     CRITICAL_SECTION cs;
+    CONDITION_VARIABLE lock;
 };
 
 static BOOL dxva_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
@@ -254,6 +258,7 @@ static ULONG WINAPI device_manager_Release(IDirect3DDeviceManager9 *iface)
 {
     struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
     ULONG refcount = InterlockedDecrement(&manager->refcount);
+    size_t i;
 
     TRACE("%p, refcount %u.\n", iface, refcount);
 
@@ -262,6 +267,11 @@ static ULONG WINAPI device_manager_Release(IDirect3DDeviceManager9 *iface)
         if (manager->device)
             IDirect3DDevice9_Release(manager->device);
         DeleteCriticalSection(&manager->cs);
+        for (i = 0; i < manager->count; ++i)
+        {
+            if (manager->handles[i].state_block)
+                IDirect3DStateBlock9_Release(manager->handles[i].state_block);
+        }
         heap_free(manager->handles);
         heap_free(manager);
     }
@@ -284,13 +294,21 @@ static HRESULT WINAPI device_manager_ResetDevice(IDirect3DDeviceManager9 *iface,
     if (manager->device)
     {
         for (i = 0; i < manager->count; ++i)
+        {
+            if (manager->handles[i].state_block)
+                IDirect3DStateBlock9_Release(manager->handles[i].state_block);
+            manager->handles[i].state_block = NULL;
             manager->handles[i].flags |= HANDLE_FLAG_INVALID;
+        }
+        manager->locking_handle = NULL;
         IDirect3DDevice9_Release(manager->device);
     }
     manager->device = device;
     IDirect3DDevice9_AddRef(manager->device);
     LeaveCriticalSection(&manager->cs);
 
+    WakeAllConditionVariable(&manager->lock);
+
     return S_OK;
 }
 
@@ -324,6 +342,7 @@ static HRESULT WINAPI device_manager_OpenDeviceHandle(IDirect3DDeviceManager9 *i
         {
             *hdevice = ULongToHandle(manager->count + 1);
             manager->handles[manager->count].flags |= HANDLE_FLAG_OPEN;
+            manager->handles[manager->count].state_block = NULL;
             manager->count++;
         }
         else
@@ -355,15 +374,22 @@ static HRESULT WINAPI device_manager_CloseDeviceHandle(IDirect3DDeviceManager9 *
     {
         if (manager->handles[idx].flags & HANDLE_FLAG_OPEN)
         {
+            if (manager->locking_handle == hdevice)
+                manager->locking_handle = NULL;
             manager->handles[idx].flags = 0;
             if (idx == manager->count - 1)
                 manager->count--;
+            if (manager->handles[idx].state_block)
+                IDirect3DStateBlock9_Release(manager->handles[idx].state_block);
+            manager->handles[idx].state_block = NULL;
         }
         else
             hr = E_HANDLE;
     }
     LeaveCriticalSection(&manager->cs);
 
+    WakeAllConditionVariable(&manager->lock);
+
     return hr;
 }
 
@@ -393,16 +419,75 @@ static HRESULT WINAPI device_manager_TestDevice(IDirect3DDeviceManager9 *iface,
 static HRESULT WINAPI device_manager_LockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
         IDirect3DDevice9 **device, BOOL block)
 {
-    FIXME("%p, %p, %p, %d.\n", iface, hdevice, device, block);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    HRESULT hr;
+    size_t idx;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p, %d.\n", iface, hdevice, device, block);
+
+    EnterCriticalSection(&manager->cs);
+    if (!manager->device)
+        hr = DXVA2_E_NOT_INITIALIZED;
+    else if (SUCCEEDED(hr = device_manager_get_handle_index(manager, hdevice, &idx)))
+    {
+        if (manager->locking_handle && !block)
+            hr = DXVA2_E_VIDEO_DEVICE_LOCKED;
+        else
+        {
+            while (manager->locking_handle && block)
+            {
+                SleepConditionVariableCS(&manager->lock, &manager->cs, INFINITE);
+            }
+
+            if (SUCCEEDED(hr = device_manager_get_handle_index(manager, hdevice, &idx)))
+            {
+                if (manager->handles[idx].flags & HANDLE_FLAG_INVALID)
+                    hr = DXVA2_E_NEW_VIDEO_DEVICE;
+                else
+                {
+                    if (manager->handles[idx].state_block)
+                    {
+                        if (FAILED(IDirect3DStateBlock9_Apply(manager->handles[idx].state_block)))
+                            WARN("Failed to apply state.\n");
+                        IDirect3DStateBlock9_Release(manager->handles[idx].state_block);
+                        manager->handles[idx].state_block = NULL;
+                    }
+                    *device = manager->device;
+                    IDirect3DDevice9_AddRef(*device);
+                    manager->locking_handle = hdevice;
+                }
+            }
+        }
+    }
+    LeaveCriticalSection(&manager->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI device_manager_UnlockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice, BOOL savestate)
 {
-    FIXME("%p, %p, %d.\n", iface, hdevice, savestate);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    HRESULT hr;
+    size_t idx;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %d.\n", iface, hdevice, savestate);
+
+    EnterCriticalSection(&manager->cs);
+
+    if (hdevice != manager->locking_handle)
+        hr = E_INVALIDARG;
+    else if (SUCCEEDED(hr = device_manager_get_handle_index(manager, hdevice, &idx)))
+    {
+        manager->locking_handle = NULL;
+        if (savestate)
+            IDirect3DDevice9_CreateStateBlock(manager->device, D3DSBT_ALL, &manager->handles[idx].state_block);
+    }
+
+    LeaveCriticalSection(&manager->cs);
+
+    WakeAllConditionVariable(&manager->lock);
+
+    return hr;
 }
 
 static HRESULT WINAPI device_manager_GetVideoService(IDirect3DDeviceManager9 *iface, HANDLE hdevice, REFIID riid,
@@ -470,6 +555,7 @@ HRESULT WINAPI DXVA2CreateDirect3DDeviceManager9(UINT *token, IDirect3DDeviceMan
     object->refcount = 1;
     object->token = GetTickCount();
     InitializeCriticalSection(&object->cs);
+    InitializeConditionVariable(&object->lock);
 
     *token = object->token;
     *manager = &object->IDirect3DDeviceManager9_iface;
diff --git a/dlls/dxva2/tests/dxva2.c b/dlls/dxva2/tests/dxva2.c
index e3e8dd2e66c..49b192a1fad 100644
--- a/dlls/dxva2/tests/dxva2.c
+++ b/dlls/dxva2/tests/dxva2.c
@@ -72,6 +72,7 @@ static void test_device_manager(void)
     HWND window;
     UINT token;
     HRESULT hr;
+    RECT rect;
 
     window = create_window();
     d3d = Direct3DCreate9(D3D_SDK_VERSION);
@@ -88,13 +89,15 @@ static void test_device_manager(void)
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
     ok(hr == DXVA2_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
 
+    hr = IDirect3DDeviceManager9_LockDevice(manager, 0, &device2, FALSE);
+    ok(hr == DXVA2_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
     /* Invalid token. */
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token + 1);
     ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-
     refcount = get_refcount((IUnknown *)device);
 
     handle1 = NULL;
@@ -140,6 +143,7 @@ static void test_device_manager(void)
     IDirectXVideoProcessorService_Release(processor_service);
 
     device2 = create_device(d3d, window);
+
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device2, token);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
@@ -150,6 +154,110 @@ static void test_device_manager(void)
     hr = IDirect3DDeviceManager9_TestDevice(manager, handle);
     ok(hr == DXVA2_E_NEW_VIDEO_DEVICE, "Unexpected hr %#x.\n", hr);
 
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    /* Lock/Unlock. */
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, handle, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, handle, FALSE);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, (HANDLE)((ULONG_PTR)handle + 100), FALSE);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    /* Locked with one handle, unlock with another. */
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle1);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, handle1, FALSE);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    /* Closing unlocks the device. */
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle1, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle1);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    /* Open two handles. */
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle1);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle1, &device3, FALSE);
+    ok(hr == DXVA2_E_VIDEO_DEVICE_LOCKED, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle1);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    /* State saving function. */
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+
+    SetRect(&rect, 50, 60, 70, 80);
+    hr = IDirect3DDevice9_SetScissorRect(device3, &rect);
+    ok(SUCCEEDED(hr), "Failed to set scissor rect, hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, handle, TRUE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    SetRect(&rect, 30, 60, 70, 80);
+    hr = IDirect3DDevice9_SetScissorRect(device3, &rect);
+    ok(SUCCEEDED(hr), "Failed to set scissor rect, hr %#x.\n", hr);
+
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_LockDevice(manager, handle, &device3, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(device2 == device3, "Unexpected device pointer.\n");
+
+    hr = IDirect3DDevice9_GetScissorRect(device3, &rect);
+    ok(SUCCEEDED(hr), "Failed to get scissor rect, hr %#x.\n", hr);
+    ok(rect.left == 50 && rect.top == 60 && rect.right == 70 && rect.bottom == 80,
+            "Got unexpected scissor rect %s.\n", wine_dbgstr_rect(&rect));
+
+    IDirect3DDevice9_Release(device3);
+
+    hr = IDirect3DDeviceManager9_UnlockDevice(manager, handle, TRUE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
     /* Acceleration service. */
     hr = DXVA2CreateVideoService(device, &IID_IDirectXVideoAccelerationService, (void **)&accel_service);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-- 
2.27.0




More information about the wine-devel mailing list