dxva2: Implement locking functionality in device manager.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-06-30 12:35:59 +03:00 committed by Alexandre Julliard
parent b61455cb81
commit 431324ba63
2 changed files with 199 additions and 5 deletions

View File

@ -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;

View File

@ -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);