From 1a893ac8869a0be08582f3b224d1a92ff37fc400 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Wed, 30 Sep 2015 16:42:10 +0200 Subject: [PATCH] st/nine: Implement NineDevice9_GetAvailableTextureMem 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 Reviewed-by: Axel Davy --- 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 cb6c813b650..5fbb4357c2f 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 f462bcb1c36..34edf0cfa48 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 56e85156a29..b929c50a83c 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 906f90806ce..8122257b7a7 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.30.2