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 <siro@das-labor.org> Reviewed-by: Axel Davy <axel.davy@ens.fr>
This commit is contained in:
parent
a961ec335d
commit
1a893ac886
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue