From 24aaf0d535b6c5c0d56b1e50deb2e47d3cce9ab8 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 22 Jun 2020 13:45:30 +0300 Subject: [PATCH] dxva2: Implement handle management for device manager. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- 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 e1eb2128439..7e983a43dd6 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 cbcad40ca59..605a69dd5a5 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);