[PATCH v4 2/5] dxgi: Return device local and non-local usage from QueryVideoMemoryInfo().

Conor McCarthy cmccarthy at codeweavers.com
Wed Dec 4 08:11:15 CST 2019


Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 dlls/ddraw/ddraw.c             |  7 ++--
 dlls/dxgi/adapter.c            | 53 ++++++++++++++++-------------
 dlls/wined3d/adapter_gl.c      |  2 +-
 dlls/wined3d/adapter_vk.c      |  2 +-
 dlls/wined3d/device.c          |  6 ++--
 dlls/wined3d/directx.c         | 61 +++++++++++++++++++++++++++++-----
 dlls/wined3d/resource.c        |  5 +--
 dlls/wined3d/texture.c         |  2 +-
 dlls/wined3d/wined3d.spec      |  1 +
 dlls/wined3d/wined3d_private.h | 11 ++++--
 include/wine/wined3d.h         | 18 ++++++++--
 11 files changed, 121 insertions(+), 47 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index d744df8c..bbb71cce 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -1926,10 +1926,11 @@ static HRESULT WINAPI ddraw7_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *c
 
     if (total)
     {
-        struct wined3d_adapter_identifier desc = {0};
+        struct wined3d_adapter_memory_info memory_info = {0};
 
-        hr = wined3d_get_adapter_identifier(ddraw->wined3d, WINED3DADAPTER_DEFAULT, 0, &desc);
-        total_vidmem = min(UINT_MAX, desc.video_memory);
+        hr = wined3d_get_adapter_memory_info(ddraw->wined3d, WINED3DADAPTER_DEFAULT,
+                WINED3D_ADAPTER_MEMORY_LOCAL, &memory_info);
+        total_vidmem = min(UINT_MAX, memory_info.total);
         *total = framebuffer_size > total_vidmem ? 0 : total_vidmem - framebuffer_size;
         TRACE("Total video memory %#x.\n", *total);
     }
diff --git a/dlls/dxgi/adapter.c b/dlls/dxgi/adapter.c
index d2fc629c..b0825cc5 100644
--- a/dlls/dxgi/adapter.c
+++ b/dlls/dxgi/adapter.c
@@ -149,7 +149,9 @@ static HRESULT STDMETHODCALLTYPE dxgi_adapter_EnumOutputs(IWineDXGIAdapter *ifac
 
 static HRESULT dxgi_adapter_get_desc(struct dxgi_adapter *adapter, DXGI_ADAPTER_DESC3 *desc)
 {
+    struct wined3d_adapter_memory_info mem_non_local;
     char description[ARRAY_SIZE(desc->Description)];
+    struct wined3d_adapter_memory_info mem_local;
     struct wined3d_adapter_identifier adapter_id;
     HRESULT hr;
 
@@ -160,6 +162,11 @@ static HRESULT dxgi_adapter_get_desc(struct dxgi_adapter *adapter, DXGI_ADAPTER_
 
     if (FAILED(hr = wined3d_get_adapter_identifier(adapter->factory->wined3d, adapter->ordinal, 0, &adapter_id)))
         return hr;
+    if (FAILED(hr = wined3d_get_adapter_memory_info(adapter->factory->wined3d,
+            adapter->ordinal, WINED3D_ADAPTER_MEMORY_LOCAL, &mem_local))
+            || FAILED(hr = wined3d_get_adapter_memory_info(adapter->factory->wined3d,
+                    adapter->ordinal, WINED3D_ADAPTER_MEMORY_NON_LOCAL, &mem_non_local)))
+        return hr;
 
     if (!MultiByteToWideChar(CP_ACP, 0, description, -1, desc->Description, ARRAY_SIZE(description)))
     {
@@ -172,9 +179,10 @@ static HRESULT dxgi_adapter_get_desc(struct dxgi_adapter *adapter, DXGI_ADAPTER_
     desc->DeviceId = adapter_id.device_id;
     desc->SubSysId = adapter_id.subsystem_id;
     desc->Revision = adapter_id.revision;
-    desc->DedicatedVideoMemory = adapter_id.video_memory;
+    /* On UMA adapters DXGI defines all memory as local, and the non-local total is 0. */
+    desc->DedicatedVideoMemory = !mem_non_local.total ? 0 : mem_local.total;
     desc->DedicatedSystemMemory = 0; /* FIXME */
-    desc->SharedSystemMemory = adapter_id.shared_system_memory;
+    desc->SharedSystemMemory = !mem_non_local.total ? mem_local.total : mem_non_local.total;
     desc->AdapterLuid = adapter_id.adapter_luid;
     desc->Flags = 0;
     desc->GraphicsPreemptionGranularity = 0; /* FIXME */
@@ -290,45 +298,42 @@ static void STDMETHODCALLTYPE dxgi_adapter_UnregisterHardwareContentProtectionTe
     FIXME("iface %p, cookie %#x stub!\n", iface, cookie);
 }
 
+/* Required for query and reservation functions. */
+C_ASSERT(DXGI_MEMORY_SEGMENT_GROUP_LOCAL == (int)WINED3D_ADAPTER_MEMORY_LOCAL
+        && DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL == (int)WINED3D_ADAPTER_MEMORY_NON_LOCAL);
+
 static HRESULT STDMETHODCALLTYPE dxgi_adapter_QueryVideoMemoryInfo(IWineDXGIAdapter *iface,
         UINT node_index, DXGI_MEMORY_SEGMENT_GROUP segment_group, DXGI_QUERY_VIDEO_MEMORY_INFO *info)
 {
     struct dxgi_adapter *adapter = impl_from_IWineDXGIAdapter(iface);
-    struct wined3d_adapter_identifier adapter_id;
+    struct wined3d_adapter_memory_info memory_info;
     static unsigned int once;
     HRESULT hr;
 
     TRACE("iface %p, node_index %u, segment_group %#x, info %p.\n",
             iface, node_index, segment_group, info);
 
+    if (segment_group > DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)
+    {
+        WARN("Invalid memory segment group 0x%x.\n", segment_group);
+        return E_INVALIDARG;
+    }
+
     if (!once++)
-        FIXME("Returning fake video memory info.\n");
+        FIXME("Returning fake or estimated video memory info.\n");
 
     if (node_index)
         FIXME("Ignoring node index %u.\n", node_index);
 
-    adapter_id.driver_size = 0;
-    adapter_id.description_size = 0;
-    adapter_id.device_name_size = 0;
-
-    if (FAILED(hr = wined3d_get_adapter_identifier(adapter->factory->wined3d, adapter->ordinal, 0, &adapter_id)))
+    if (FAILED(hr = wined3d_get_adapter_memory_info(adapter->factory->wined3d,
+            adapter->ordinal, segment_group, &memory_info)))
         return hr;
 
-    switch (segment_group)
-    {
-        case DXGI_MEMORY_SEGMENT_GROUP_LOCAL:
-            info->Budget = adapter_id.video_memory;
-            info->CurrentUsage = 0;
-            info->AvailableForReservation = adapter_id.video_memory / 2;
-            info->CurrentReservation = 0;
-            break;
-        case DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL:
-            memset(info, 0, sizeof(*info));
-            break;
-        default:
-            WARN("Invalid memory segment group %#x.\n", segment_group);
-            return E_INVALIDARG;
-    }
+    /* Budget must leave a little extra space. In Windows this seems to always be about total/6.5 if total <= 8 Gb. */
+    info->Budget = memory_info.total - memory_info.total / 7u;
+    info->CurrentUsage = memory_info.used;
+    info->AvailableForReservation = memory_info.total / 2u;
+    info->CurrentReservation = memory_info.reserved;
 
     TRACE("Budget 0x%s, usage 0x%s, available for reservation 0x%s, reservation 0x%s.\n",
             wine_dbgstr_longlong(info->Budget), wine_dbgstr_longlong(info->CurrentUsage),
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index 7018c6da..0adcc165 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -3881,7 +3881,7 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
     TRACE("Reporting (fake) driver version 0x%08x-0x%08x.\n",
             driver_info->version_high, driver_info->version_low);
 
-    adapter->vram_bytes_used = 0;
+    memset(&adapter->memory_usage, 0, sizeof(adapter->memory_usage));
     TRACE("Emulating 0x%s bytes of video ram.\n", wine_dbgstr_longlong(driver_info->vram_bytes));
 
     if (gl_info->supported[EXT_MEMORY_OBJECT])
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 21163a20..f00de70c 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1180,7 +1180,7 @@ static BOOL wined3d_adapter_vk_init(struct wined3d_adapter_vk *adapter_vk,
     VK_CALL(vkGetPhysicalDeviceMemoryProperties(adapter_vk->physical_device, &memory_properties));
 
     adapter_vk_init_driver_info(adapter, &properties2.properties, &memory_properties);
-    adapter->vram_bytes_used = 0;
+    memset(&adapter->memory_usage, 0, sizeof(adapter->memory_usage));
     TRACE("Emulating 0x%s bytes of video ram.\n", wine_dbgstr_longlong(adapter->driver_info.vram_bytes));
 
     memcpy(&adapter->driver_uuid, id_properties.driverUUID, sizeof(adapter->driver_uuid));
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 98559e4f..0f6ee51b 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1198,10 +1198,10 @@ UINT CDECL wined3d_device_get_available_texture_mem(const struct wined3d_device
 
     TRACE("Emulating 0x%s bytes. 0x%s used, returning 0x%s left.\n",
             wine_dbgstr_longlong(driver_info->vram_bytes),
-            wine_dbgstr_longlong(device->adapter->vram_bytes_used),
-            wine_dbgstr_longlong(driver_info->vram_bytes - device->adapter->vram_bytes_used));
+            wine_dbgstr_longlong(device->adapter->memory_usage[WINED3D_ADAPTER_MEMORY_LOCAL].bytes_used),
+            wine_dbgstr_longlong(driver_info->vram_bytes - device->adapter->memory_usage[WINED3D_ADAPTER_MEMORY_LOCAL].bytes_used));
 
-    return min(UINT_MAX, driver_info->vram_bytes - device->adapter->vram_bytes_used);
+    return min(UINT_MAX, driver_info->vram_bytes - device->adapter->memory_usage[WINED3D_ADAPTER_MEMORY_LOCAL].bytes_used);
 }
 
 void CDECL wined3d_device_set_stream_output(struct wined3d_device *device, UINT idx,
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 902cc444..4a8baed3 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -143,14 +143,33 @@ static HRESULT wined3d_output_init(struct wined3d_output *output, const WCHAR *d
     return WINED3D_OK;
 }
 
+static uint64_t adapter_get_total_memory(const struct wined3d_adapter *adapter, enum wined3d_adapter_memory_type type)
+{
+    /* vram_bytes may be zero for a UMA adapter. DXGI defines all memory as local for UMA adapters. */
+    if (!adapter->driver_info.vram_bytes)
+        return type == WINED3D_ADAPTER_MEMORY_NON_LOCAL ? 0 : adapter->driver_info.sysmem_bytes;
+    else
+        return type == WINED3D_ADAPTER_MEMORY_NON_LOCAL ? adapter->driver_info.sysmem_bytes : adapter->driver_info.vram_bytes;
+}
+
 /* Adjust the amount of used texture memory */
-UINT64 adapter_adjust_memory(struct wined3d_adapter *adapter, INT64 amount)
+UINT64 adapter_adjust_memory(struct wined3d_adapter *adapter, enum wined3d_adapter_memory_type type,
+        INT64 amount)
 {
-    adapter->vram_bytes_used += amount;
-    TRACE("Adjusted used adapter memory by 0x%s to 0x%s.\n",
+    uint64_t bytes_total;
+
+    adapter->memory_usage[type].bytes_used += amount;
+    TRACE("Adjusted used adapter memory type %u by 0x%s to 0x%s.\n", type,
             wine_dbgstr_longlong(amount),
-            wine_dbgstr_longlong(adapter->vram_bytes_used));
-    return adapter->vram_bytes_used;
+            wine_dbgstr_longlong(adapter->memory_usage[type].bytes_used));
+
+    bytes_total = adapter_get_total_memory(adapter, type);
+    if (bytes_total && adapter->memory_usage[type].bytes_used > bytes_total)
+        WARN("Current type %u usage estimate 0x%s exceeds 0x%s available.\n", type,
+                wine_dbgstr_longlong(adapter->memory_usage[type].bytes_used),
+                wine_dbgstr_longlong(bytes_total));
+
+    return adapter->memory_usage[type].bytes_used;
 }
 
 void wined3d_adapter_cleanup(struct wined3d_adapter *adapter)
@@ -1365,8 +1384,6 @@ HRESULT CDECL wined3d_get_adapter_identifier(const struct wined3d *wined3d,
     identifier->device_uuid = adapter->device_uuid;
     identifier->whql_level = (flags & WINED3DENUM_NO_WHQL_LEVEL) ? 0 : 1;
     identifier->adapter_luid = adapter->luid;
-    identifier->video_memory = min(~(SIZE_T)0, adapter->driver_info.vram_bytes);
-    identifier->shared_system_memory = min(~(SIZE_T)0, adapter->driver_info.sysmem_bytes);
 
     wined3d_mutex_unlock();
 
@@ -1377,6 +1394,34 @@ fail:
     return WINED3DERR_INVALIDCALL;
 }
 
+HRESULT CDECL wined3d_get_adapter_memory_info(const struct wined3d *wined3d, unsigned int adapter_idx,
+        enum wined3d_adapter_memory_type type, struct wined3d_adapter_memory_info *info)
+{
+    const struct wined3d_adapter *adapter;
+
+    TRACE("wined3d %p, adapter_idx %u, type %u, info %p.\n",
+            wined3d, adapter_idx, type, info);
+
+    wined3d_mutex_lock();
+
+    if (adapter_idx >= wined3d->adapter_count || type >= ARRAY_SIZE(adapter->memory_usage))
+        goto fail;
+
+    adapter = wined3d->adapters[adapter_idx];
+
+    info->total = adapter_get_total_memory(adapter, type);
+    info->used = adapter->memory_usage[type].bytes_used;
+    info->reserved = adapter->memory_usage[type].bytes_reserved;
+
+    wined3d_mutex_unlock();
+
+    return WINED3D_OK;
+
+fail:
+    wined3d_mutex_unlock();
+    return E_INVALIDARG;
+}
+
 HRESULT CDECL wined3d_get_adapter_raster_status(const struct wined3d *wined3d, UINT adapter_idx,
         struct wined3d_raster_status *raster_status)
 {
@@ -2778,7 +2823,7 @@ static struct wined3d_adapter *wined3d_adapter_no3d_create(unsigned int ordinal,
         return NULL;
 
     wined3d_driver_info_init(&adapter->driver_info, &gpu_description, 0, 0);
-    adapter->vram_bytes_used = 0;
+    memset(&adapter->memory_usage, 0, sizeof(adapter->memory_usage));
     TRACE("Emulating 0x%s bytes of video ram.\n", wine_dbgstr_longlong(adapter->driver_info.vram_bytes));
 
     if (!wined3d_adapter_init(adapter, ordinal, &wined3d_adapter_no3d_ops))
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
index bba940f4..4feecedc 100644
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -227,7 +227,8 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
                 ERR("Out of adapter memory.\n");
                 return WINED3DERR_OUTOFVIDEOMEMORY;
             }
-            adapter_adjust_memory(device->adapter, size);
+            /* FIXME: non-local memory can be accounted for too if it proves necessary. */
+            adapter_adjust_memory(device->adapter, WINED3D_ADAPTER_MEMORY_LOCAL, size);
         }
 
         device_resource_add(device, resource);
@@ -256,7 +257,7 @@ void resource_cleanup(struct wined3d_resource *resource)
         if (!(resource->access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
         {
             TRACE("Decrementing device memory pool by %u.\n", resource->size);
-            adapter_adjust_memory(resource->device->adapter, (INT64)0 - resource->size);
+            adapter_adjust_memory(resource->device->adapter, WINED3D_ADAPTER_MEMORY_LOCAL, (INT64)0 - resource->size);
         }
 
         device_resource_released(resource->device, resource);
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index d4d90c28..2f6ebf17 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1596,7 +1596,7 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT
     texture->resource.width = width;
     texture->resource.height = height;
     if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
-        adapter_adjust_memory(device->adapter,  (INT64)texture->slice_pitch - texture->resource.size);
+        adapter_adjust_memory(device->adapter, WINED3D_ADAPTER_MEMORY_LOCAL, (INT64)texture->slice_pitch - texture->resource.size);
     texture->resource.size = texture->slice_pitch;
     sub_resource->size = texture->slice_pitch;
     sub_resource->locations = WINED3D_LOCATION_DISCARDED;
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index fed5ce1b..e618b6fd 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -14,6 +14,7 @@
 @ cdecl wined3d_get_adapter_count(ptr)
 @ cdecl wined3d_get_adapter_display_mode(ptr long ptr ptr)
 @ cdecl wined3d_get_adapter_identifier(ptr long long ptr)
+@ cdecl wined3d_get_adapter_memory_info(ptr long long ptr)
 @ cdecl wined3d_get_adapter_mode_count(ptr long long long)
 @ cdecl wined3d_get_adapter_output(ptr long ptr)
 @ cdecl wined3d_get_adapter_raster_status(ptr long ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 3ae7dab8..3b4145fd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2868,6 +2868,12 @@ struct wined3d_output
     D3DDDI_VIDEO_PRESENT_SOURCE_ID vidpn_source_id;
 };
 
+struct wined3d_adapter_memory_usage
+{
+    UINT64 bytes_used;
+    UINT64 bytes_reserved;
+};
+
 /* The adapter structure */
 struct wined3d_adapter
 {
@@ -2879,7 +2885,7 @@ struct wined3d_adapter
     struct wined3d_d3d_info d3d_info;
     struct wined3d_driver_info driver_info;
     struct wined3d_output output;
-    UINT64 vram_bytes_used;
+    struct wined3d_adapter_memory_usage memory_usage[WINED3D_ADAPTER_MEMORY_COUNT];
     GUID driver_uuid;
     GUID device_uuid;
     LUID luid;
@@ -2956,7 +2962,8 @@ BOOL wined3d_adapter_gl_init_format_info(struct wined3d_adapter *adapter,
 BOOL wined3d_adapter_no3d_init_format_info(struct wined3d_adapter *adapter) DECLSPEC_HIDDEN;
 BOOL wined3d_adapter_vk_init_format_info(struct wined3d_adapter_vk *adapter_vk,
         const struct wined3d_vk_info *vk_info) DECLSPEC_HIDDEN;
-UINT64 adapter_adjust_memory(struct wined3d_adapter *adapter, INT64 amount) DECLSPEC_HIDDEN;
+UINT64 adapter_adjust_memory(struct wined3d_adapter *adapter, enum wined3d_adapter_memory_type type,
+        INT64 amount) DECLSPEC_HIDDEN;
 
 BOOL wined3d_caps_gl_ctx_test_viewport_subpixel_bits(struct wined3d_caps_gl_ctx *ctx) DECLSPEC_HIDDEN;
 
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index eba14e9a..7e5ca169 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -1738,8 +1738,20 @@ struct wined3d_adapter_identifier
     GUID device_uuid;
     DWORD whql_level;
     LUID adapter_luid;
-    SIZE_T video_memory;
-    SIZE_T shared_system_memory;
+};
+
+enum wined3d_adapter_memory_type
+{
+    WINED3D_ADAPTER_MEMORY_LOCAL = 0,
+    WINED3D_ADAPTER_MEMORY_NON_LOCAL = 1,
+    WINED3D_ADAPTER_MEMORY_COUNT = 2,
+};
+
+struct wined3d_adapter_memory_info
+{
+    UINT64 total;
+    UINT64 used;
+    UINT64 reserved;
 };
 
 struct wined3d_swapchain_desc
@@ -2206,6 +2218,8 @@ HRESULT __cdecl wined3d_get_adapter_display_mode(const struct wined3d *wined3d,
         struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation);
 HRESULT __cdecl wined3d_get_adapter_identifier(const struct wined3d *wined3d, UINT adapter_idx,
         DWORD flags, struct wined3d_adapter_identifier *identifier);
+HRESULT __cdecl wined3d_get_adapter_memory_info(const struct wined3d *wined3d, unsigned int adapter_idx,
+        enum wined3d_adapter_memory_type type, struct wined3d_adapter_memory_info *info);
 UINT __cdecl wined3d_get_adapter_mode_count(const struct wined3d *wined3d, UINT adapter_idx,
         enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering);
 struct wined3d_output * __cdecl wined3d_get_adapter_output(const struct wined3d *wined3d, unsigned int adapter_idx);
-- 
2.24.0




More information about the wine-devel mailing list