Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51665 Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- v2: Supersede 235995. Simplify thread creation.
dlls/dxgi/adapter.c | 13 +++- dlls/dxgi/tests/dxgi.c | 4 -- dlls/wined3d/directx.c | 139 ++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d.spec | 2 + include/wine/wined3d.h | 3 + 5 files changed, 154 insertions(+), 7 deletions(-)
diff --git a/dlls/dxgi/adapter.c b/dlls/dxgi/adapter.c index 20c017eba08..b178376341b 100644 --- a/dlls/dxgi/adapter.c +++ b/dlls/dxgi/adapter.c @@ -333,15 +333,22 @@ static HRESULT STDMETHODCALLTYPE dxgi_adapter_SetVideoMemoryReservation(IWineDXG static HRESULT STDMETHODCALLTYPE dxgi_adapter_RegisterVideoMemoryBudgetChangeNotificationEvent( IWineDXGIAdapter *iface, HANDLE event, DWORD *cookie) { - FIXME("iface %p, event %p, cookie %p stub!\n", iface, event, cookie); + struct dxgi_adapter *adapter = impl_from_IWineDXGIAdapter(iface);
- return E_NOTIMPL; + TRACE("iface %p, event %p, cookie %p.\n", iface, event, cookie); + + if (!event || !cookie) + return DXGI_ERROR_INVALID_CALL; + + return wined3d_adapter_register_budget_change_notification(adapter->wined3d_adapter, event, cookie); }
static void STDMETHODCALLTYPE dxgi_adapter_UnregisterVideoMemoryBudgetChangeNotification( IWineDXGIAdapter *iface, DWORD cookie) { - FIXME("iface %p, cookie %#lx stub!\n", iface, cookie); + TRACE("iface %p, cookie %#lx.\n", iface, cookie); + + wined3d_adapter_unregister_budget_change_notification(cookie); }
static HRESULT STDMETHODCALLTYPE dxgi_adapter_GetDesc3(IWineDXGIAdapter *iface, DXGI_ADAPTER_DESC3 *desc) diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index 04bba29e8e5..33e9ead31ad 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -7539,16 +7539,13 @@ static void test_video_memory_budget_notification(void) goto done;
hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, NULL, &cookie); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
event = CreateEventW(NULL, FALSE, FALSE, NULL); hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, event, NULL); - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
hr = IDXGIAdapter3_RegisterVideoMemoryBudgetChangeNotificationEvent(adapter3, event, &cookie); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = IDXGIAdapter3_QueryVideoMemoryInfo(adapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memory_info); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); @@ -7560,7 +7557,6 @@ static void test_video_memory_budget_notification(void) if (memory_info.Budget) { ret = WaitForSingleObject(event, 1000); - todo_wine ok(ret == WAIT_OBJECT_0, "Expected event fired.\n"); }
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 8c58a346add..fb588b88098 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -23,6 +23,7 @@
#include "wined3d_private.h" #include "winternl.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -38,6 +39,19 @@ enum wined3d_driver_model DRIVER_MODEL_NT6X };
+struct wined3d_adapter_budget_change_notification +{ + const struct wined3d_adapter *adapter; + HANDLE event; + DWORD cookie; + UINT64 last_local_budget; + UINT64 last_non_local_budget; + struct list entry; +}; + +static struct list adapter_budget_change_notifications = LIST_INIT( adapter_budget_change_notifications ); +static HANDLE notification_thread, notification_thread_stop_event; + /* The d3d device ID */ static const GUID IID_D3DDEVICE_D3DUID = { 0xaeb2cdd4, 0x6e41, 0x43ea, { 0x94,0x1c,0x83,0x61,0xcc,0x76,0x07,0x81 } };
@@ -1046,6 +1060,131 @@ HRESULT CDECL wined3d_adapter_get_video_memory_info(const struct wined3d_adapter return WINED3D_OK; }
+static DWORD CALLBACK notification_thread_func(void *stop_event) +{ + struct wined3d_adapter_budget_change_notification *notification; + struct wined3d_video_memory_info info; + HRESULT hr; + + while (TRUE) + { + wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(notification, &adapter_budget_change_notifications, + struct wined3d_adapter_budget_change_notification, entry) + { + hr = wined3d_adapter_get_video_memory_info(notification->adapter, 0, + WINED3D_MEMORY_SEGMENT_GROUP_LOCAL, &info); + if (SUCCEEDED(hr) && info.budget != notification->last_local_budget) + { + notification->last_local_budget = info.budget; + SetEvent(notification->event); + continue; + } + + hr = wined3d_adapter_get_video_memory_info(notification->adapter, 0, + WINED3D_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); + if (SUCCEEDED(hr) && info.budget != notification->last_non_local_budget) + { + notification->last_non_local_budget = info.budget; + SetEvent(notification->event); + } + } + wined3d_mutex_unlock(); + + if (WaitForSingleObject(stop_event, 1000) == WAIT_OBJECT_0) + break; + } + + return TRUE; +} + +HRESULT CDECL wined3d_adapter_register_budget_change_notification(const struct wined3d_adapter *adapter, + HANDLE event, DWORD *cookie) +{ + static DWORD cookie_counter; + static BOOL wrapped; + struct wined3d_adapter_budget_change_notification *notification, *new_notification; + BOOL found = FALSE; + + new_notification = heap_alloc_zero(sizeof(*new_notification)); + if (!new_notification) + return E_OUTOFMEMORY; + + wined3d_mutex_lock(); + new_notification->adapter = adapter; + new_notification->event = event; + new_notification->cookie = cookie_counter++; + if (cookie_counter < new_notification->cookie) + wrapped = TRUE; + if (wrapped) + { + while (TRUE) + { + LIST_FOR_EACH_ENTRY(notification, &adapter_budget_change_notifications, + struct wined3d_adapter_budget_change_notification, entry) + { + if (notification->cookie == new_notification->cookie) + { + found = TRUE; + break; + } + } + + if (!found) + break; + + new_notification->cookie = cookie_counter++; + } + } + + *cookie = new_notification->cookie; + list_add_head(&adapter_budget_change_notifications, &new_notification->entry); + + if (!notification_thread) + { + notification_thread_stop_event = CreateEventW(0, FALSE, FALSE, NULL); + notification_thread = CreateThread(NULL, 0, notification_thread_func, + notification_thread_stop_event, 0, NULL); + } + wined3d_mutex_unlock(); + return WINED3D_OK; +} + +HRESULT CDECL wined3d_adapter_unregister_budget_change_notification(DWORD cookie) +{ + struct wined3d_adapter_budget_change_notification *notification; + HANDLE thread, thread_stop_event; + + wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(notification, &adapter_budget_change_notifications, + struct wined3d_adapter_budget_change_notification, entry) + { + if (notification->cookie == cookie) + { + list_remove(¬ification->entry); + heap_free(notification); + break; + } + } + + if (!list_empty(&adapter_budget_change_notifications)) + { + wined3d_mutex_unlock(); + return WINED3D_OK; + } + + thread = notification_thread; + thread_stop_event = notification_thread_stop_event; + notification_thread = NULL; + notification_thread_stop_event = NULL; + wined3d_mutex_unlock(); + SetEvent(thread_stop_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(thread_stop_event); + return WINED3D_OK; +} + HRESULT CDECL wined3d_register_software_device(struct wined3d *wined3d, void *init_function) { FIXME("wined3d %p, init_function %p stub!\n", wined3d, init_function); diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 845ca0fb170..63220e1222c 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -22,6 +22,8 @@ @ cdecl wined3d_adapter_get_output(ptr long) @ cdecl wined3d_adapter_get_output_count(ptr) @ cdecl wined3d_adapter_get_video_memory_info(ptr long long ptr) +@ cdecl wined3d_adapter_register_budget_change_notification(ptr ptr ptr) +@ cdecl wined3d_adapter_unregister_budget_change_notification(long)
@ cdecl wined3d_blend_state_create(ptr ptr ptr ptr ptr) @ cdecl wined3d_blend_state_decref(ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 2b7a626f751..116aea82348 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2364,6 +2364,9 @@ unsigned int __cdecl wined3d_adapter_get_output_count(const struct wined3d_adapt HRESULT __cdecl wined3d_adapter_get_video_memory_info(const struct wined3d_adapter *adapter, unsigned int node_idx, enum wined3d_memory_segment_group group, struct wined3d_video_memory_info *info); +HRESULT __cdecl wined3d_adapter_register_budget_change_notification(const struct wined3d_adapter *adapter, + HANDLE event, DWORD *cookie); +HRESULT __cdecl wined3d_adapter_unregister_budget_change_notification(DWORD cookie);
HRESULT __cdecl wined3d_buffer_create(struct wined3d_device *device, const struct wined3d_buffer_desc *desc, const struct wined3d_sub_resource_data *data, void *parent, const struct wined3d_parent_ops *parent_ops,
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=115226
Your paranoid android.
=== w10pro64 (32 bit report) ===
dxgi: dxgi.c:2831: Test failed: Got unexpected hr 0x887a0022. dxgi.c:2834: Test failed: Got unexpected fullscreen 0. dxgi.c:2837: Test failed: Got unexpected hr 0x887a0022. dxgi.c:2840: Test failed: Got unexpected fullscreen 0.
=== w864 (64 bit report) ===
dxgi: dxgi.c:4786: Test failed: Test 0: Got unexpected hr 0x87a0001. dxgi.c:4798: Test failed: Test 0: Got unexpected fullscreen status.