[Mesa-dev] [PATCH 36/45] st/nine: Implement NineDevice9_GetAvailableTextureMem

Axel Davy axel.davy at ens.fr
Fri Jan 29 08:09:00 PST 2016


From: Patrick Rudolph <siro at das-labor.org>

Implement a device private memory counter similar to Win 7.

Only textures and surfaces increment vidmem and may return
ERR_OUTOFVIDEOMEMORY. Vertexbuffers and indexbuffers creation always
succeedes, even when out of video memory.

Fixes "Vampire: The Masquerade - Bloodlines" allocating resources until crash.
Fixes "Age of Conan" allocating resources until crash.
Fixes failing WINE test device.c test_vidmem_accounting().

Signed-off-by: Patrick Rudolph <siro at das-labor.org>
Reviewed-by: Axel Davy <axel.davy at ens.fr>
---
 src/gallium/state_trackers/nine/device9.c   | 19 ++++++++++++-----
 src/gallium/state_trackers/nine/device9.h   |  2 ++
 src/gallium/state_trackers/nine/resource9.c | 32 +++++++++++++++++++++++++++++
 src/gallium/state_trackers/nine/resource9.h |  2 ++
 4 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
index 33775ac..c42c8c0 100644
--- a/src/gallium/state_trackers/nine/device9.c
+++ b/src/gallium/state_trackers/nine/device9.c
@@ -175,6 +175,19 @@ NineDevice9_ctor( struct NineDevice9 *This,
     /* Create first, it messes up our state. */
     This->hud = hud_create(This->pipe, This->cso); /* NULL result is fine */
 
+    /* Available memory counter. Updated only for allocations with this device
+     * instance. This is the Win 7 behavior.
+     * Win XP shares this counter across multiple devices. */
+    This->available_texture_mem = This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY);
+    if (This->available_texture_mem < 4096)
+        This->available_texture_mem <<= 20;
+    else
+        This->available_texture_mem = UINT_MAX;
+    /* We cap texture memory usage to 80% of what is reported free initially
+     * This helps get closer Win behaviour. For example VertexBuffer allocation
+     * still succeeds when texture allocation fails. */
+    This->available_texture_limit = This->available_texture_mem * 20LL / 100LL;
+
     /* create implicit swapchains */
     This->nswapchains = ID3DPresentGroup_GetMultiheadCount(This->present);
     This->swapchains = CALLOC(This->nswapchains,
@@ -540,11 +553,7 @@ NineDevice9_TestCooperativeLevel( struct NineDevice9 *This )
 UINT WINAPI
 NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This )
 {
-   const unsigned mem = This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY);
-   if (mem < 4096)
-      return mem << 20;
-   else
-      return UINT_MAX;
+    return This->available_texture_mem;
 }
 
 HRESULT WINAPI
diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h
index f462bcb..34edf0c 100644
--- a/src/gallium/state_trackers/nine/device9.h
+++ b/src/gallium/state_trackers/nine/device9.h
@@ -139,6 +139,8 @@ struct NineDevice9
     struct pipe_resource *dummy_vbo;
     BOOL device_needs_reset;
     int minor_version_num;
+    long long available_texture_mem;
+    long long available_texture_limit;
 };
 static inline struct NineDevice9 *
 NineDevice9( void *data )
diff --git a/src/gallium/state_trackers/nine/resource9.c b/src/gallium/state_trackers/nine/resource9.c
index 56e8515..b929c50 100644
--- a/src/gallium/state_trackers/nine/resource9.c
+++ b/src/gallium/state_trackers/nine/resource9.c
@@ -29,6 +29,7 @@
 
 #include "util/u_hash_table.h"
 #include "util/u_inlines.h"
+#include "util/u_resource.h"
 
 #include "nine_pdata.h"
 
@@ -61,6 +62,33 @@ NineResource9_ctor( struct NineResource9 *This,
 
     if (Allocate) {
         assert(!initResource);
+
+        /* On Windows it is possible allocation fails when
+         * IDirect3DDevice9::GetAvailableTextureMem() still reports
+         * enough free space.
+         *
+         * Some games allocate surfaces
+         * in a loop until they receive D3DERR_OUTOFVIDEOMEMORY to measure
+         * the available texture memory size.
+         *
+         * We are not using the drivers VRAM statistics because:
+         *  * This would add overhead to each resource allocation.
+         *  * Freeing memory is lazy and takes some time, but applications
+         *    expects the memory counter to change immediately after allocating
+         *    or freeing memory.
+         *
+         * Vertexbuffers and indexbuffers are not accounted !
+         */
+        if (This->info.target != PIPE_BUFFER) {
+            This->size = util_resource_size(&This->info);
+
+            This->base.device->available_texture_mem -= This->size;
+            if (This->base.device->available_texture_mem <=
+                    This->base.device->available_texture_limit) {
+                return D3DERR_OUTOFVIDEOMEMORY;
+            }
+        }
+
         DBG("(%p) Creating pipe_resource.\n", This);
         This->resource = screen->resource_create(screen, &This->info);
         if (!This->resource)
@@ -91,6 +119,10 @@ NineResource9_dtor( struct NineResource9 *This )
      * still hold a reference. */
     pipe_resource_reference(&This->resource, NULL);
 
+    /* NOTE: size is 0, unless something has actually been allocated */
+    if (This->base.device)
+        This->base.device->available_texture_mem += This->size;
+
     NineUnknown_dtor(&This->base);
 }
 
diff --git a/src/gallium/state_trackers/nine/resource9.h b/src/gallium/state_trackers/nine/resource9.h
index 906f908..8122257 100644
--- a/src/gallium/state_trackers/nine/resource9.h
+++ b/src/gallium/state_trackers/nine/resource9.h
@@ -45,6 +45,8 @@ struct NineResource9
 
     /* for [GS]etPrivateData/FreePrivateData */
     struct util_hash_table *pdata;
+
+    long long size;
 };
 static inline struct NineResource9 *
 NineResource9( void *data )
-- 
2.7.0



More information about the mesa-dev mailing list