Add a retry when allocating/creating textures, vertex buffers, and index buffers.

Added a fail-safe if DirectX can't allocate video memory.
This commit is contained in:
aignacio_sf 2005-12-28 20:25:33 +00:00
parent 9a84565fd8
commit 55a02393d7
8 changed files with 191 additions and 86 deletions

View File

@ -1976,14 +1976,6 @@ reset() {
_lru = 0;
}
if (_enable_lru)
{
if (available_texture_memory >= 256000000)
{
// _enable_lru = false;
}
}
if (_enable_lru)
{
int maximum_memory;
@ -1991,18 +1983,48 @@ reset() {
int maximum_page_types;
Lru *lru;
maximum_memory = available_texture_memory;
int minimum_memory_requirement;
int optimum_memory_requirement;
int free_memory_requirement;
// TEST LRU *****
maximum_memory = 55000000;
// THESE NEED TO SPECIFIED SOMEHOW
minimum_memory_requirement = 64000000;
optimum_memory_requirement = 128000000;
free_memory_requirement = 5000000; // allow DirectX some space in case of fragmentation, ...
maximum_pages = 20000;
maximum_page_types = GPT_TotalPageTypes;
maximum_memory = available_texture_memory - free_memory_requirement;
if (!false)
{
if (maximum_memory < minimum_memory_requirement)
{
// video memory is way too low, so take all of it
maximum_memory = available_texture_memory;
// should warn user about low video memory
}
else
{
if (maximum_memory >= optimum_memory_requirement)
{
// cap video memory used
maximum_memory = optimum_memory_requirement;
}
}
}
else
{
// TEST LRU *****
maximum_memory = 55000000;
maximum_pages = 20000;
}
maximum_page_types = GPT_TotalPageTypes;
lru = new Lru (maximum_memory, maximum_pages, maximum_page_types);
if (lru)
{
lru -> _m.minimum_memory = 1000000;
lru -> register_lru_page_type (GPT_VertexBuffer, vertex_buffer_page_in_function, vertex_buffer_page_out_function);
lru -> register_lru_page_type (GPT_IndexBuffer, index_buffer_page_in_function, index_buffer_page_out_function);
lru -> register_lru_page_type (GPT_Texture, texture_page_in_function, texture_page_out_function);
@ -4220,3 +4242,48 @@ draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
index_data, index_type, safe_buffer_start - stride * min_index, stride);
}
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian9::check_dx_allocation
// Access:
// Description: This function is called after the creation of
// textures, vertex buffers, and index buffers to
// check if DirectX is out of memory. If DirectX is
// out of memory and the LRU is being used, then
// page out some memory. This function is a fail-safe
// just in case another process takes allocates video
// memory, DirectX is fragmented, or there are some
// borderline memory allocation cases, ...
////////////////////////////////////////////////////////////////////
bool DXGraphicsStateGuardian9::
check_dx_allocation (HRESULT result, int allocation_size, int attempts)
{
bool retry;
retry = false;
if (attempts <= 4)
{
switch (result) {
case D3D_OK:
break;
case D3DERR_OUTOFVIDEOMEMORY:
if (_lru) {
// increase the page out size as the number of attempts increases
if (_lru -> page_out_lru (allocation_size * attempts)) {
retry = true;
}
}
break;
case E_OUTOFMEMORY:
// ??? is this case system memory
break;
default:
break;
}
}
return retry;
}

View File

@ -118,6 +118,8 @@ public:
virtual void set_state_and_transform(const RenderState *state,
const TransformState *transform);
bool check_dx_allocation (HRESULT result, int allocation_size, int attempts);
protected:
void do_issue_transform();
void do_issue_alpha_test();

View File

@ -114,8 +114,17 @@ allocate_ibuffer(DXScreenData &scrn) {
pool = D3DPOOL_DEFAULT;
}
HRESULT hr = scrn._d3d_device->CreateIndexBuffer
(data_size, usage, index_type, pool, &_ibuffer, NULL);
int attempts;
HRESULT hr;
attempts = 0;
do
{
hr = scrn._d3d_device->CreateIndexBuffer
(data_size, usage, index_type, pool, &_ibuffer, NULL);
attempts++;
}
while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
if (FAILED(hr)) {
dxgsg9_cat.warning()

View File

@ -678,52 +678,6 @@ create_texture(DXScreenData &scrn) {
}
}
switch (_texture->get_texture_type()) {
case Texture::TT_1d_texture:
case Texture::TT_2d_texture:
hr = scrn._d3d_device->CreateTexture
(target_width, target_height, mip_level_count, usage,
target_pixel_format, pool, &_d3d_2d_texture, NULL);
_d3d_texture = _d3d_2d_texture;
break;
case Texture::TT_3d_texture:
hr = scrn._d3d_device->CreateVolumeTexture
(target_width, target_height, target_depth, mip_level_count, usage,
target_pixel_format, pool, &_d3d_volume_texture, NULL);
_d3d_texture = _d3d_volume_texture;
break;
case Texture::TT_cube_map:
hr = scrn._d3d_device->CreateCubeTexture
(target_width, mip_level_count, usage,
target_pixel_format, pool, &_d3d_cube_texture, NULL);
_d3d_texture = _d3d_cube_texture;
target_height = target_width;
break;
}
if (FAILED(hr)) {
dxgsg9_cat.error()
<< "D3D create_texture failed!" << D3DERRORSTRING(hr);
goto error_exit;
}
if (dxgsg9_cat.is_debug()) {
dxgsg9_cat.debug()
<< "create_texture: " << _texture->get_name()
<< " converting panda equivalent of " << D3DFormatStr(_d3d_format)
<< " => " << D3DFormatStr(target_pixel_format) << endl;
}
hr = fill_d3d_texture_pixels();
if (FAILED(hr)) {
goto error_exit;
}
// PRINT_REFCNT(dxgsg9, scrn._d3d9);
float bytes_per_texel;
bytes_per_texel = 1.0f;
@ -787,19 +741,80 @@ create_texture(DXScreenData &scrn) {
break;
}
int data_size;
data_size = target_width * target_height * target_depth;
data_size = (int) ((float) data_size * bytes_per_texel);
if (_has_mipmaps)
{
data_size = (int) ((float) data_size * 1.3f);
}
if (_texture->get_texture_type() == Texture::TT_cube_map)
{
data_size *= 6;
}
int attempts;
attempts = 0;
do
{
switch (_texture->get_texture_type()) {
case Texture::TT_1d_texture:
case Texture::TT_2d_texture:
hr = scrn._d3d_device->CreateTexture
(target_width, target_height, mip_level_count, usage,
target_pixel_format, pool, &_d3d_2d_texture, NULL);
_d3d_texture = _d3d_2d_texture;
break;
case Texture::TT_3d_texture:
hr = scrn._d3d_device->CreateVolumeTexture
(target_width, target_height, target_depth, mip_level_count, usage,
target_pixel_format, pool, &_d3d_volume_texture, NULL);
_d3d_texture = _d3d_volume_texture;
break;
case Texture::TT_cube_map:
hr = scrn._d3d_device->CreateCubeTexture
(target_width, mip_level_count, usage,
target_pixel_format, pool, &_d3d_cube_texture, NULL);
_d3d_texture = _d3d_cube_texture;
target_height = target_width;
break;
}
attempts++;
}
while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
if (FAILED(hr)) {
dxgsg9_cat.error()
<< "D3D create_texture failed!" << D3DERRORSTRING(hr);
goto error_exit;
}
if (dxgsg9_cat.is_debug()) {
dxgsg9_cat.debug()
<< "create_texture: " << _texture->get_name()
<< " converting panda equivalent of " << D3DFormatStr(_d3d_format)
<< " => " << D3DFormatStr(target_pixel_format) << endl;
}
hr = fill_d3d_texture_pixels();
if (FAILED(hr)) {
goto error_exit;
}
// PRINT_REFCNT(dxgsg9, scrn._d3d9);
// must not put render to texture into LRU
if (_lru_page == 0 && _managed == false && _texture->get_render_to_texture ( ) == false)
{
int data_size;
Lru *lru;
data_size = target_width * target_height * target_depth;
data_size = (int) ((float) data_size * bytes_per_texel);
if (_has_mipmaps)
{
data_size = (int) ((float) data_size * 1.3f);
}
lru = scrn._dxgsg9 -> _lru;
if (lru)
{

View File

@ -239,8 +239,17 @@ allocate_vbuffer(DXScreenData &scrn) {
usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
}
hr = scrn._d3d_device->CreateVertexBuffer
(data_size, usage, _fvf, pool, &_vbuffer, NULL);
int attempts;
attempts = 0;
do
{
hr = scrn._d3d_device->CreateVertexBuffer
(data_size, usage, _fvf, pool, &_vbuffer, NULL);
attempts++;
}
while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
if (FAILED(hr)) {
dxgsg9_cat.warning()
<< "CreateVertexBuffer failed" << D3DERRORSTRING(hr);

View File

@ -1034,7 +1034,7 @@ bool Lru::page_out_lru (int memory_required)
do {
int index;
// page out lower priority pages first
// page out lower priority pages first
for(index = LPP_PageOut - 1; index >= 0; index--) {
LruPage *lru_page;
LruPage *next_lru_page;
@ -1048,11 +1048,11 @@ bool Lru::page_out_lru (int memory_required)
this->_m.available_memory += lru_page->_m.size;
lru_page->_m.in_cache = false;
// PAGE OUT CALLBACK
// PAGE OUT CALLBACK
this->_m.page_out_function_array[lru_page->_m.type](lru_page);
this->_m.total_lifetime_page_outs++;
// MOVE THE PAGE TO THE LPP_PageOut PRIORITY
// MOVE THE PAGE TO THE LPP_PageOut PRIORITY
this->remove_page(lru_page);
this->add_page(LPP_PageOut, lru_page);

View File

@ -169,8 +169,9 @@ public:
void calculate_lru_statistics (void);
private:
bool page_out_lru (int memory_required);
private:
void update_page_priorities (void);
void update_lru_page (LruPage *lru_page);
void update_lru_page_old (LruPage *lru_page);
@ -186,7 +187,7 @@ public:
int current_frame_identifier;
int maximum_memory;
int minimum_memory; // target amount of memory to keep free if possible
int minimum_memory; // target amount of memory to keep free if possible
int maximum_page_types;
int total_lifetime_page_ins;
@ -200,15 +201,12 @@ public:
int total_page_access;
int minimum_page_out_frames; // number of frames required before page out
int maximum_page_updates_per_frame; // unused pages
int start_priority_index;
LruPage *start_update_lru_page;
int identifier; // this is also the number of pages created during the lifetime of the LRU
int identifier; // the number of pages created during the lifetime of the LRU
float weight; // used for exponential moving average
float weight; // used for exponential moving average
float maximum_frame_bandwidth_utilization;
float frame_bandwidth_factor;
@ -219,18 +217,17 @@ public:
int total_lru_page_priority_changes;
LruPage *lru_page_priority_change_array [FRAME_MAXIMUM_PRIORITY_CHANGES];
void *context;
int lru_page_count_array [LPP_TotalPriorities];
int maximum_pages;
int total_lru_pages_in_pool;
int total_lru_pages_in_free_pool;
LruPage **lru_page_pool;
LruPage **lru_page_free_pool;
int lru_page_count_array [LPP_TotalPriorities];
PageTypeStatistics *page_type_statistics_array;
void *context; // user specified data
#if ENABLE_MUTEX
Mutex *mutex;
#endif

View File

@ -591,6 +591,12 @@ create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer
wdxdisplay9_cat.warning() << "SetForegroundWindow() failed!\n";
}
// TURN THIS ON IF MULTITHREADED DX IS NEEDED
if (false)
{
dwBehaviorFlags |= D3DCREATE_MULTITHREADED;
}
if (is_fullscreen()) {
// CREATE FULLSCREEN BUFFERS