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:
parent
9a84565fd8
commit
55a02393d7
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue