Browse Source

Add a retry when allocating/creating textures, vertex buffers, and index buffers.
Added a fail-safe if DirectX can't allocate video memory.

aignacio_sf 20 years ago
parent
commit
55a02393d7

+ 81 - 14
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;
+}

+ 2 - 0
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();

+ 11 - 2
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()

+ 69 - 54
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)
     {

+ 11 - 2
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);

+ 3 - 3
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);
 

+ 8 - 11
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

+ 6 - 0
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