File sc_gpumem.patch of Package wine

From 07b2f01b9b5721c502bee6fb4d6397756a51b376 Mon Sep 17 00:00:00 2001
From: Vingian <89702391+Vingian@users.noreply.github.com>
Date: Sat, 10 Jan 2026 06:08:52 -0300
Subject: [PATCH] D3DKMT: Minimal query implementation

A minimal implementation... just to satisfy the way SC monitors GPU memory.
---
 dlls/win32u/d3dkmt.c | 126 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c
index baf99f69291..573803c1de1 100644
--- a/dlls/win32u/d3dkmt.c
+++ b/dlls/win32u/d3dkmt.c
@@ -711,6 +711,22 @@ NTSTATUS WINAPI NtGdiDdDDIQueryAdapterInfo( D3DKMT_QUERYADAPTERINFO *desc )
         *value = KMT_DRIVERVERSION_WDDM_1_3;
         return STATUS_SUCCESS;
     }
+    case KMTQAITYPE_NODEMETADATA:
+    {
+        struct d3dkmt_adapter *adapter;
+        UINT *node = desc->pPrivateDriverData;
+
+        if (desc->PrivateDriverDataSize < sizeof(*node) * 2)
+            return STATUS_INVALID_PARAMETER;
+
+        if (!(adapter = get_d3dkmt_object( desc->hAdapter, D3DKMT_ADAPTER )) || !adapter->physical_device)
+            return STATUS_NOT_IMPLEMENTED;
+
+        memset( node, 0, desc->PrivateDriverDataSize );
+        //NodeData.EngineType = DXGK_ENGINE_TYPE_3D
+        node[1] = 1;
+        return STATUS_SUCCESS;
+    }
     default:
     {
         FIXME( "type %d not handled.\n", desc->Type );
@@ -719,12 +735,122 @@ NTSTATUS WINAPI NtGdiDdDDIQueryAdapterInfo( D3DKMT_QUERYADAPTERINFO *desc )
     }
 }
 
+static __thread struct {
+    LUID AdapterLuid;
+    DWORD time;
+    ULONGLONG total[2];
+    ULONGLONG budget[2];
+    ULONGLONG usage[2];
+} g_GPUMemCache = {0};
+
+static inline ULONGLONG GPUMem( LUID AdapterLuid, ULONGLONG *budget, ULONGLONG *usage, BOOL shared )
+{
+    DWORD now = NtGetTickCount();
+    BOOL use_cache = FALSE;
+    int idx_target = shared ? 1 : 0;
+
+    if (g_GPUMemCache.AdapterLuid.LowPart == AdapterLuid.LowPart && g_GPUMemCache.AdapterLuid.HighPart == AdapterLuid.HighPart)
+        if (now - g_GPUMemCache.time < 123)
+            use_cache = TRUE;
+
+    if (!use_cache)
+    {
+        D3DKMT_OPENADAPTERFROMLUID adp = { .AdapterLuid = AdapterLuid };
+        struct d3dkmt_adapter *adapter;
+        struct vulkan_physical_device *physical_device;
+
+        g_GPUMemCache.AdapterLuid = AdapterLuid;
+        g_GPUMemCache.time = now;
+        g_GPUMemCache.total[0] = g_GPUMemCache.total[1] = 0;
+        g_GPUMemCache.budget[0] = g_GPUMemCache.budget[1] = 0;
+        g_GPUMemCache.usage[0] = g_GPUMemCache.usage[1] = 0;
+
+        if (NtGdiDdDDIOpenAdapterFromLuid( &adp ) == STATUS_SUCCESS)
+        {
+            if ((adapter = get_d3dkmt_object( adp.hAdapter, D3DKMT_ADAPTER )) && (physical_device = adapter->physical_device))
+            {
+                struct vulkan_instance *instance = physical_device->instance;
+                VkPhysicalDeviceMemoryBudgetPropertiesEXT mem_budget = {0};
+                VkPhysicalDeviceMemoryProperties2 mem_prop2 = {0};
+
+                mem_budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
+                mem_prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
+                mem_prop2.pNext = &mem_budget;
+
+                instance->p_vkGetPhysicalDeviceMemoryProperties2KHR( physical_device->host.physical_device, &mem_prop2 );
+                for (UINT i = 0; i < mem_prop2.memoryProperties.memoryHeapCount; ++i)
+                {
+                    int idx = (mem_prop2.memoryProperties.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? 0 : 1;
+                    ULONGLONG s = mem_prop2.memoryProperties.memoryHeaps[i].size;
+                    ULONGLONG b = min( s, mem_budget.heapBudget[i] );
+                    ULONGLONG u = min( b, mem_budget.heapUsage[i] );
+                    g_GPUMemCache.total[idx] += s;
+                    g_GPUMemCache.budget[idx] += b;
+                    g_GPUMemCache.usage[idx] += u;
+                }
+            }
+            NtGdiDdDDICloseAdapter( &(D3DKMT_CLOSEADAPTER){ .hAdapter = adp.hAdapter } );
+        }
+    }
+
+    if (budget) *budget = g_GPUMemCache.budget[idx_target];
+    if (usage) *usage = g_GPUMemCache.usage[idx_target];
+    return g_GPUMemCache.total[idx_target];
+}
+
 /******************************************************************************
  *           NtGdiDdDDIQueryStatistics    (win32u.@)
  */
 NTSTATUS WINAPI NtGdiDdDDIQueryStatistics( D3DKMT_QUERYSTATISTICS *stats )
 {
     FIXME( "(%p): stub\n", stats );
+    switch ((int)stats->Type)
+    {
+    case D3DKMT_QUERYSTATISTICS_ADAPTER:
+    {
+        D3DKMT_OPENADAPTERFROMLUID adp = { .AdapterLuid = stats->AdapterLuid };
+        memset( &stats->QueryResult, 0, sizeof(stats->QueryResult) );
+        if (NtGdiDdDDIOpenAdapterFromLuid( &adp ) == STATUS_SUCCESS)
+        {
+            stats->QueryResult.AdapterInformation.NbSegments = 2;
+            stats->QueryResult.AdapterInformation.NodeCount = 1;
+            g_GPUMemCache.AdapterLuid.LowPart = g_GPUMemCache.AdapterLuid.HighPart = 0;
+            NtGdiDdDDICloseAdapter( &(D3DKMT_CLOSEADAPTER){ .hAdapter = adp.hAdapter } );
+        }
+        break;
+    }
+    case D3DKMT_QUERYSTATISTICS_SEGMENT:
+    case D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT:
+    case /*D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP*/0x09:
+    {
+        ULONGLONG total, budget, usage;
+        ULONG aperture = !!stats->QueryProcessSegment.SegmentId;
+
+        memset( &stats->QueryResult, 0, sizeof(stats->QueryResult) );
+        if (stats->QuerySegment.SegmentId > 1) break;
+        if (stats->Type >= D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT)
+            if (stats->hProcess && stats->hProcess != GetCurrentProcess())
+                break;
+
+        if ((total = GPUMem( stats->AdapterLuid, &budget, &usage, aperture )) > 0)
+        {
+            if (stats->Type == D3DKMT_QUERYSTATISTICS_SEGMENT) {
+                stats->QueryResult.SegmentInformation.CommitLimit = total;
+                stats->QueryResult.SegmentInformation.BytesCommitted = total - budget + usage;
+                stats->QueryResult.SegmentInformation.BytesResident = stats->QueryResult.SegmentInformation.BytesCommitted;
+                stats->QueryResult.SegmentInformation.Aperture = aperture;
+            } else if (stats->Type == D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT) {
+                stats->QueryResult.ProcessSegmentInformation.BytesCommitted = usage;
+            } else {
+                //ProcessSegmentGroupInformation.Budget
+                stats->QueryResult.ProcessSegmentInformation.BytesCommitted = budget;
+                //ProcessSegmentGroupInformation.Usage
+                stats->QueryResult.ProcessSegmentInformation.MinimumWorkingSet = usage;
+            }
+        }
+        break;
+    }
+    }
     return STATUS_SUCCESS;
 }
 
openSUSE Build Service is sponsored by