Nikolay Sivov : dxva2: Implement handle management for device manager.

Alexandre Julliard julliard at winehq.org
Mon Jun 22 15:55:58 CDT 2020


Module: wine
Branch: master
Commit: 24aaf0d535b6c5c0d56b1e50deb2e47d3cce9ab8
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=24aaf0d535b6c5c0d56b1e50deb2e47d3cce9ab8

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Mon Jun 22 13:45:30 2020 +0300

dxva2: Implement handle management for device manager.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dxva2/main.c        | 158 ++++++++++++++++++++++++++++++++++++++++++++---
 dlls/dxva2/tests/dxva2.c |  16 +----
 2 files changed, 151 insertions(+), 23 deletions(-)

diff --git a/dlls/dxva2/main.c b/dlls/dxva2/main.c
index e1eb212843..7e983a43dd 100644
--- a/dlls/dxva2/main.c
+++ b/dlls/dxva2/main.c
@@ -33,14 +33,59 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dxva2);
 
+enum device_handle_flags
+{
+    HANDLE_FLAG_OPEN = 0x1,
+    HANDLE_FLAG_INVALID = 0x2,
+};
+
+struct device_handle
+{
+    unsigned int flags;
+};
+
 struct device_manager
 {
     IDirect3DDeviceManager9 IDirect3DDeviceManager9_iface;
     LONG refcount;
 
+    IDirect3DDevice9 *device;
     UINT token;
+
+    struct device_handle *handles;
+    size_t count;
+    size_t capacity;
+
+    CRITICAL_SECTION cs;
 };
 
+static BOOL dxva_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
+{
+    size_t new_capacity, max_capacity;
+    void *new_elements;
+
+    if (count <= *capacity)
+        return TRUE;
+
+    max_capacity = ~(SIZE_T)0 / size;
+    if (count > max_capacity)
+        return FALSE;
+
+    new_capacity = max(4, *capacity);
+    while (new_capacity < count && new_capacity <= max_capacity / 2)
+        new_capacity *= 2;
+    if (new_capacity < count)
+        new_capacity = max_capacity;
+
+    if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
+        return FALSE;
+
+    *elements = new_elements;
+    *capacity = new_capacity;
+
+    return TRUE;
+}
+
 static struct device_manager *impl_from_IDirect3DDeviceManager9(IDirect3DDeviceManager9 *iface)
 {
     return CONTAINING_RECORD(iface, struct device_manager, IDirect3DDeviceManager9_iface);
@@ -82,6 +127,10 @@ static ULONG WINAPI device_manager_Release(IDirect3DDeviceManager9 *iface)
 
     if (!refcount)
     {
+        if (manager->device)
+            IDirect3DDevice9_Release(manager->device);
+        DeleteCriticalSection(&manager->cs);
+        heap_free(manager->handles);
         heap_free(manager);
     }
 
@@ -91,30 +140,122 @@ static ULONG WINAPI device_manager_Release(IDirect3DDeviceManager9 *iface)
 static HRESULT WINAPI device_manager_ResetDevice(IDirect3DDeviceManager9 *iface, IDirect3DDevice9 *device,
         UINT token)
 {
-    FIXME("%p, %p, %#x.\n", iface, device, token);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    size_t i;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %#x.\n", iface, device, token);
+
+    if (token != manager->token)
+        return E_INVALIDARG;
+
+    EnterCriticalSection(&manager->cs);
+    if (manager->device)
+    {
+        for (i = 0; i < manager->count; ++i)
+            manager->handles[i].flags |= HANDLE_FLAG_INVALID;
+        IDirect3DDevice9_Release(manager->device);
+    }
+    manager->device = device;
+    IDirect3DDevice9_AddRef(manager->device);
+    LeaveCriticalSection(&manager->cs);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI device_manager_OpenDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE *hdevice)
 {
-    FIXME("%p, %p.\n", iface, hdevice);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    HRESULT hr = S_OK;
+    size_t i;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, hdevice);
+
+    *hdevice = NULL;
+
+    EnterCriticalSection(&manager->cs);
+    if (!manager->device)
+        hr = DXVA2_E_NOT_INITIALIZED;
+    else
+    {
+        for (i = 0; i < manager->count; ++i)
+        {
+            if (!(manager->handles[i].flags & HANDLE_FLAG_OPEN))
+            {
+                manager->handles[i].flags |= HANDLE_FLAG_OPEN;
+                *hdevice = ULongToHandle(i + 1);
+                break;
+            }
+        }
+
+        if (dxva_array_reserve((void **)&manager->handles, &manager->capacity, manager->count + 1,
+                sizeof(*manager->handles)))
+        {
+            *hdevice = ULongToHandle(manager->count + 1);
+            manager->handles[manager->count].flags |= HANDLE_FLAG_OPEN;
+            manager->count++;
+        }
+        else
+            hr = E_OUTOFMEMORY;
+    }
+    LeaveCriticalSection(&manager->cs);
+
+    return hr;
+}
+
+static HRESULT device_manager_get_handle_index(struct device_manager *manager, HANDLE hdevice, size_t *idx)
+{
+    if (hdevice > ULongToHandle(manager->count))
+        return E_HANDLE;
+    *idx = (ULONG_PTR)hdevice - 1;
+    return S_OK;
 }
 
 static HRESULT WINAPI device_manager_CloseDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
 {
-    FIXME("%p, %p.\n", iface, hdevice);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    HRESULT hr;
+    size_t idx;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, hdevice);
+
+    EnterCriticalSection(&manager->cs);
+    if (SUCCEEDED(hr = device_manager_get_handle_index(manager, hdevice, &idx)))
+    {
+        if (manager->handles[idx].flags & HANDLE_FLAG_OPEN)
+        {
+            manager->handles[idx].flags = 0;
+            if (idx == manager->count - 1)
+                manager->count--;
+        }
+        else
+            hr = E_HANDLE;
+    }
+    LeaveCriticalSection(&manager->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI device_manager_TestDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
 {
-    FIXME("%p, %p.\n", iface, hdevice);
+    struct device_manager *manager = impl_from_IDirect3DDeviceManager9(iface);
+    HRESULT hr;
+    size_t idx;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, hdevice);
+
+    EnterCriticalSection(&manager->cs);
+    if (SUCCEEDED(hr = device_manager_get_handle_index(manager, hdevice, &idx)))
+    {
+        unsigned int flags = manager->handles[idx].flags;
+
+        if (flags & HANDLE_FLAG_INVALID)
+            hr = DXVA2_E_NEW_VIDEO_DEVICE;
+        else if (!(flags & HANDLE_FLAG_OPEN))
+            hr = E_HANDLE;
+    }
+    LeaveCriticalSection(&manager->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI device_manager_LockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
@@ -176,6 +317,7 @@ HRESULT WINAPI DXVA2CreateDirect3DDeviceManager9(UINT *token, IDirect3DDeviceMan
     object->IDirect3DDeviceManager9_iface.lpVtbl = &device_manager_vtbl;
     object->refcount = 1;
     object->token = GetTickCount();
+    InitializeCriticalSection(&object->cs);
 
     *token = object->token;
     *manager = &object->IDirect3DDeviceManager9_iface;
diff --git a/dlls/dxva2/tests/dxva2.c b/dlls/dxva2/tests/dxva2.c
index cbcad40ca5..605a69dd5a 100644
--- a/dlls/dxva2/tests/dxva2.c
+++ b/dlls/dxva2/tests/dxva2.c
@@ -84,23 +84,19 @@ static void test_device_manager(void)
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
-todo_wine
     ok(hr == DXVA2_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
 
     /* Invalid token. */
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token + 1);
-todo_wine
     ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     refcount = get_refcount((IUnknown *)device);
 
     handle1 = NULL;
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle1);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     refcount2 = get_refcount((IUnknown *)device);
@@ -108,40 +104,32 @@ todo_wine
 
     handle = NULL;
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
-todo_wine {
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
     ok(handle != handle1, "Unexpected handle.\n");
-}
+
     hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     /* Already closed. */
     hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
-todo_wine
     ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
 
     handle = NULL;
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle1);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_TestDevice(manager, handle1);
-todo_wine
     ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
 
     handle = NULL;
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     handle1 = NULL;
     hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle1);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_GetVideoService(manager, handle, &IID_IDirectXVideoProcessorService,
@@ -153,7 +141,6 @@ todo_wine
 
     device2 = create_device(d3d, window);
     hr = IDirect3DDeviceManager9_ResetDevice(manager, device2, token);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_GetVideoService(manager, handle, &IID_IDirectXVideoProcessorService,
@@ -162,7 +149,6 @@ todo_wine
     ok(hr == DXVA2_E_NEW_VIDEO_DEVICE, "Unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDeviceManager9_TestDevice(manager, handle);
-todo_wine
     ok(hr == DXVA2_E_NEW_VIDEO_DEVICE, "Unexpected hr %#x.\n", hr);
 
     IDirect3DDevice9_Release(device);




More information about the wine-cvs mailing list