From 55a02393d7f9ea531d8aedb4f09e48b47a735205 Mon Sep 17 00:00:00 2001 From: aignacio_sf <> Date: Wed, 28 Dec 2005 20:25:33 +0000 Subject: [PATCH] Add a retry when allocating/creating textures, vertex buffers, and index buffers. Added a fail-safe if DirectX can't allocate video memory. --- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 95 ++++++++++++-- panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 2 + panda/src/dxgsg9/dxIndexBufferContext9.cxx | 13 +- panda/src/dxgsg9/dxTextureContext9.cxx | 123 ++++++++++-------- panda/src/dxgsg9/dxVertexBufferContext9.cxx | 13 +- panda/src/dxgsg9/lru.cxx | 6 +- panda/src/dxgsg9/lru.h | 19 ++- panda/src/dxgsg9/wdxGraphicsWindow9.cxx | 6 + 8 files changed, 191 insertions(+), 86 deletions(-) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 555ffde6e1..2ce1bbb009 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -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; +} diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 843c488b26..e69e1b7346 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -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(); diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx index 3910ffbd68..792d48e359 100755 --- a/panda/src/dxgsg9/dxIndexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -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() diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index 8770f0d1d2..7744c94b5a 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -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) { diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.cxx b/panda/src/dxgsg9/dxVertexBufferContext9.cxx index 2eec27cf64..3317b72cae 100755 --- a/panda/src/dxgsg9/dxVertexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxVertexBufferContext9.cxx @@ -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); diff --git a/panda/src/dxgsg9/lru.cxx b/panda/src/dxgsg9/lru.cxx index c518e39d96..e8a09c210b 100644 --- a/panda/src/dxgsg9/lru.cxx +++ b/panda/src/dxgsg9/lru.cxx @@ -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); diff --git a/panda/src/dxgsg9/lru.h b/panda/src/dxgsg9/lru.h index 8f8423486b..07fd2ced56 100644 --- a/panda/src/dxgsg9/lru.h +++ b/panda/src/dxgsg9/lru.h @@ -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 diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx index a610283fd6..417ba3e993 100755 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx @@ -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