[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