[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