Signed-off-by: Nikolay Sivov nsivov@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);