Zhiyi Zhang : dxgi: Implement adapter video memory budget change notification.

Alexandre Julliard julliard at winehq.org
Mon May 23 15:51:52 CDT 2022


Module: wine
Branch: master
Commit: fd6e137dfe16700e0a0a7ebb23b413019bc18193
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=fd6e137dfe16700e0a0a7ebb23b413019bc18193

Author: Zhiyi Zhang <zzhang at codeweavers.com>
Date:   Mon May 23 11:21:16 2022 +0800

dxgi: Implement adapter video memory budget change notification.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51665
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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(&notification->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,




More information about the wine-cvs mailing list