瀏覽代碼

graphics-memory-limit

David Rose 17 年之前
父節點
當前提交
a8ec068c05
共有 49 個文件被更改,包括 691 次插入265 次删除
  1. 3 0
      panda/src/display/graphicsStateGuardian.cxx
  2. 0 2
      panda/src/dxgsg8/config_dxgsg8.cxx
  3. 0 1
      panda/src/dxgsg8/config_dxgsg8.h
  4. 8 1
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  5. 33 0
      panda/src/dxgsg8/dxIndexBufferContext8.cxx
  6. 2 0
      panda/src/dxgsg8/dxIndexBufferContext8.h
  7. 114 101
      panda/src/dxgsg8/dxTextureContext8.cxx
  8. 2 0
      panda/src/dxgsg8/dxTextureContext8.h
  9. 33 0
      panda/src/dxgsg8/dxVertexBufferContext8.cxx
  10. 2 0
      panda/src/dxgsg8/dxVertexBufferContext8.h
  11. 0 2
      panda/src/dxgsg9/config_dxgsg9.cxx
  12. 0 1
      panda/src/dxgsg9/config_dxgsg9.h
  13. 8 2
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  14. 23 0
      panda/src/dxgsg9/dxIndexBufferContext9.cxx
  15. 2 0
      panda/src/dxgsg9/dxIndexBufferContext9.h
  16. 109 96
      panda/src/dxgsg9/dxTextureContext9.cxx
  17. 2 0
      panda/src/dxgsg9/dxTextureContext9.h
  18. 23 0
      panda/src/dxgsg9/dxVertexBufferContext9.cxx
  19. 2 0
      panda/src/dxgsg9/dxVertexBufferContext9.h
  20. 6 2
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  21. 2 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  22. 5 2
      panda/src/glstuff/glIndexBufferContext_src.I
  23. 40 0
      panda/src/glstuff/glIndexBufferContext_src.cxx
  24. 6 1
      panda/src/glstuff/glIndexBufferContext_src.h
  25. 32 0
      panda/src/glstuff/glTextureContext_src.cxx
  26. 2 0
      panda/src/glstuff/glTextureContext_src.h
  27. 5 2
      panda/src/glstuff/glVertexBufferContext_src.I
  28. 40 0
      panda/src/glstuff/glVertexBufferContext_src.cxx
  29. 8 1
      panda/src/glstuff/glVertexBufferContext_src.h
  30. 13 0
      panda/src/gobj/config_gobj.cxx
  31. 1 0
      panda/src/gobj/config_gobj.h
  32. 25 0
      panda/src/gobj/indexBufferContext.I
  33. 4 1
      panda/src/gobj/indexBufferContext.h
  34. 32 0
      panda/src/gobj/preparedGraphicsObjects.I
  35. 3 1
      panda/src/gobj/preparedGraphicsObjects.cxx
  36. 5 0
      panda/src/gobj/preparedGraphicsObjects.h
  37. 17 2
      panda/src/gobj/simpleLru.I
  38. 8 7
      panda/src/gobj/simpleLru.cxx
  39. 2 1
      panda/src/gobj/simpleLru.h
  40. 29 0
      panda/src/gobj/textureContext.I
  41. 4 1
      panda/src/gobj/textureContext.h
  42. 25 0
      panda/src/gobj/vertexBufferContext.I
  43. 4 1
      panda/src/gobj/vertexBufferContext.h
  44. 0 10
      panda/src/tinydisplay/config_tinydisplay.cxx
  45. 3 7
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx
  46. 0 2
      panda/src/tinydisplay/tinyGraphicsStateGuardian.h
  47. 1 14
      panda/src/tinydisplay/tinyTextureContext.I
  48. 2 1
      panda/src/tinydisplay/tinyTextureContext.cxx
  49. 1 3
      panda/src/tinydisplay/tinyTextureContext.h

+ 3 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -1240,6 +1240,9 @@ end_frame(Thread *current_thread) {
   _texture_state_pcollector.flush_level();
   _transform_state_pcollector.flush_level();
   _draw_primitive_pcollector.flush_level();
+
+  // Evict any textures and/or vbuffers that exceed our texture memory.
+  _prepared_objects->_graphics_memory_lru.begin_epoch();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 2
panda/src/dxgsg8/config_dxgsg8.cxx

@@ -84,8 +84,6 @@ ConfigVariableBool dx_ignore_mipmaps
 // if this is set, more accurate but more expensive fog computations are performed
 ConfigVariableBool dx_use_rangebased_fog
 ("dx-use-rangebased-fog", false);
-ConfigVariableBool dx_force_16bpptextures
-("dx-force-16bpptextures", false);
 ConfigVariableBool dx_no_dithering
 ("dx-no-dithering", false);
 ConfigVariableBool dx_force_16bpp_zbuffer

+ 0 - 1
panda/src/dxgsg8/config_dxgsg8.h

@@ -39,7 +39,6 @@ extern ConfigVariableBool dx_broken_max_index;
 extern ConfigVariableBool dx_ignore_mipmaps;
 extern ConfigVariableBool dx_mipmap_everything;
 extern ConfigVariableBool dx_show_transforms;
-extern ConfigVariableBool dx_force_16bpptextures;
 extern ConfigVariableBool dx_no_dithering;
 extern ConfigVariableBool dx_force_anisotropic_filtering;
 extern ConfigVariableBool dx_force_16bpp_zbuffer;

+ 8 - 1
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -277,6 +277,7 @@ update_texture(TextureContext *tc, bool force) {
       return false;
     }
   }
+  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   return true;
 }
@@ -427,6 +428,7 @@ apply_vertex_buffer(VertexBufferContext *vbc,
       dvbc->set_active(true);
     }
   }
+  dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   HRESULT hr = _d3d_device->SetVertexShader(dvbc->_fvf);
 #ifndef NDEBUG
@@ -524,6 +526,7 @@ apply_index_buffer(IndexBufferContext *ibc,
       dibc->set_active(true);
     }
   }
+  dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   return true;
 }
@@ -1572,7 +1575,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   SAFE_RELEASE(render_target);
   SAFE_RELEASE(tex_level_0);
 
-  if (!okflag) {
+  if (okflag) {
+    dtc->mark_loaded();
+    dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
+
+  } else {
     // The copy failed.  Fall back to copying it to RAM and back.
     // Terribly slow, but what are you going to do?
     return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);

+ 33 - 0
panda/src/dxgsg8/dxIndexBufferContext8.cxx

@@ -51,6 +51,39 @@ DXIndexBufferContext8::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXIndexBufferContext8::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXIndexBufferContext8::
+evict_lru() {
+  dequeue_lru();
+
+  if (_ibuffer != NULL) {
+    if (dxgsg8_cat.is_debug()) {
+      dxgsg8_cat.debug()
+        << "deleting index buffer " << _ibuffer << "\n";
+    }
+
+    RELEASE(_ibuffer, dxgsg8, "index buffer", RELEASE_ONCE);
+    _ibuffer = NULL;
+  }
+
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXIndexBufferContext8::create_ibuffer
 //       Access: Public

+ 2 - 0
panda/src/dxgsg8/dxIndexBufferContext8.h

@@ -29,6 +29,8 @@ public:
   DXIndexBufferContext8(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
   virtual ~DXIndexBufferContext8();
 
+  virtual void evict_lru();
+
   void create_ibuffer(DXScreenData &scrn,
                       const GeomPrimitivePipelineReader *reader);
   bool upload_data(const GeomPrimitivePipelineReader *reader, bool force);

+ 114 - 101
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -57,6 +57,35 @@ DXTextureContext8::
   delete_texture();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXTextureContext8::
+evict_lru() {
+  if (get_texture()->get_render_to_texture()) {
+    // Don't evict the result of render-to-texture.
+    mark_used_lru();
+    return;
+  }
+
+  dequeue_lru();
+  delete_texture();
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXTextureContext8::create_texture
 //       Access: Public
@@ -308,17 +337,49 @@ create_texture(DXScreenData &scrn) {
   // D3DXCheckTextureRequirements(), but it wouldn't handle all my
   // specialized low-memory cases perfectly
 
-#define CONVTYPE_STMT
-
-#define CHECK_FOR_FMT(FMT, CONV)  \
+#define CHECK_FOR_FMT(FMT)  \
                     if (scrn._supported_tex_formats_mask & FMT##_FLAG) {   \
-                        CONVTYPE_STMT;                             \
                         target_pixel_format = D3DFMT_##FMT;                 \
                         goto found_matching_format; }
 
+  if (texture_stored_compressed){
+    // if the texture is already compressed, we need to choose the
+    // corresponding format, otherwise we might end up
+    // cross-compressing from e.g. DXT5 to DXT3
+    switch (compression_mode){
+    case Texture::CM_dxt1:
+      CHECK_FOR_FMT(DXT1);
+      break;
+    case Texture::CM_dxt2:
+      CHECK_FOR_FMT(DXT2);
+      break;
+    case Texture::CM_dxt3:
+      CHECK_FOR_FMT(DXT3);
+      break;
+    case Texture::CM_dxt4:
+      CHECK_FOR_FMT(DXT4);
+      break;
+    case Texture::CM_dxt5:
+      CHECK_FOR_FMT(DXT5);
+      break;
+    }
+    // if we can't support the texture's compressed image, we can't
+    // load the texture.
+    goto error_exit;
+  }
+
+  if (compress_texture) {
+    if (num_alpha_bits <= 1) {
+      CHECK_FOR_FMT(DXT1);    
+    } else if (num_alpha_bits <= 4) {
+      CHECK_FOR_FMT(DXT3);    
+    } else {
+      CHECK_FOR_FMT(DXT5);
+    }
+  }
+
   // handle each target bitdepth separately.  might be less confusing
-  // to reorg by num_color_channels (input type, rather than desired
-  // 1st target)
+  // to reorg by num_color_channels (input type)
   switch (target_bpp) {
 
     // IMPORTANT NOTE:
@@ -329,37 +390,8 @@ create_texture(DXScreenData &scrn) {
     if (!((num_color_channels == 3) || (num_color_channels == 4)))
       break; //bail
 
-    if (!dx_force_16bpptextures) {
-      if (compress_texture) {
-        if (texture_stored_compressed){
-          // if the texture is already compressed, we need to choose the corresponding format, 
-          // otherwise we might end up cross-compressing from e.g. DXT5 to DXT3
-          switch (compression_mode){
-          case Texture::CM_dxt2:
-            CHECK_FOR_FMT(DXT2, Conv32toDXT2);
-            break;
-          case Texture::CM_dxt3:
-            CHECK_FOR_FMT(DXT3, Conv32toDXT3);
-            break;
-          case Texture::CM_dxt4:
-            CHECK_FOR_FMT(DXT4, Conv32toDXT4);
-            break;
-          case Texture::CM_dxt5:
-            CHECK_FOR_FMT(DXT5, Conv32toDXT5);
-            break;
-          }
-          // if no compressed format matches, just fall trhough to pick a different format          
-        }
-        else
-          CHECK_FOR_FMT(DXT3, Conv32toDXT3);    
-      }    
-      if (num_color_channels == 4) {
-        CHECK_FOR_FMT(A8R8G8B8, Conv32to32);
-      } else {
-        CHECK_FOR_FMT(A8R8G8B8, Conv24to32);
-      }
-    }
-
+    CHECK_FOR_FMT(A8R8G8B8);
+    
     if (num_alpha_bits>0) {
       nassertr(num_color_channels == 4, false);
 
@@ -377,16 +409,13 @@ create_texture(DXScreenData &scrn) {
       // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify
       // 32->16 conversion.  This should be true on most cards.
 
-#ifndef FORCE_16bpp_1555
-      if (num_alpha_bits == 1)
-#endif
-        {
-          CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555);
-        }
+      if (num_alpha_bits == 1) {
+        CHECK_FOR_FMT(A1R5G5B5);
+      }
 
       // normally prefer 4444 due to better alpha channel resolution
-      CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444);
-      CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555);
+      CHECK_FOR_FMT(A4R4G4B4);
+      CHECK_FOR_FMT(A1R5G5B5);
 
       // At this point, bail.  Don't worry about converting to
       // non-alpha formats yet, I think this will be a very rare case.
@@ -395,11 +424,11 @@ create_texture(DXScreenData &scrn) {
       // convert 3 or 4 channel to closest 16bpp color fmt
 
       if (num_color_channels == 3) {
-        CHECK_FOR_FMT(R5G6B5, Conv24to16_4444);
-        CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+        CHECK_FOR_FMT(R5G6B5);
+        CHECK_FOR_FMT(X1R5G5B5);
       } else {
-        CHECK_FOR_FMT(R5G6B5, Conv32to16_4444);
-        CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+        CHECK_FOR_FMT(R5G6B5);
+        CHECK_FOR_FMT(X1R5G5B5);
       }
     }
     break;
@@ -407,23 +436,19 @@ create_texture(DXScreenData &scrn) {
   case 24:
     nassertr(num_color_channels == 3, false);
 
-    if (compress_texture) {
-      CHECK_FOR_FMT(DXT1, Conv24toDXT1);    
-    }
-
-    if (!dx_force_16bpptextures) {
-      CHECK_FOR_FMT(R8G8B8, Conv24to24);
-
-      // no 24-bit fmt.  look for 32 bit fmt (note: this is
-      // memory-hogging choice instead I could look for
-      // memory-conserving 16-bit fmt).
-
-      CHECK_FOR_FMT(X8R8G8B8, Conv24to32);
-    }
+    CHECK_FOR_FMT(R8G8B8);
+    
+    // no 24-bit fmt.  look for 32 bit fmt (note: this is
+    // memory-hogging choice instead I could look for
+    // memory-conserving 16-bit fmt).
+    
+    CHECK_FOR_FMT(X8R8G8B8);
+    CHECK_FOR_FMT(A8R8G8B8);
 
     // no 24-bit or 32 fmt.  look for 16 bit fmt (higher res 565 1st)
-    CHECK_FOR_FMT(R5G6B5, Conv24to16_0565);
-    CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+    CHECK_FOR_FMT(R5G6B5);
+    CHECK_FOR_FMT(X1R5G5B5);
+    CHECK_FOR_FMT(A1R5G5B5);
     break;
 
   case 16:
@@ -431,22 +456,16 @@ create_texture(DXScreenData &scrn) {
       nassertr(num_alpha_bits > 0, false);
       nassertr(num_color_channels == 2, false);
 
-      CHECK_FOR_FMT(A8L8, ConvLum16to16);
+      CHECK_FOR_FMT(A8L8);
+      CHECK_FOR_FMT(A8R8G8B8);
 
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(A8R8G8B8, ConvLum16to32);
+      if (num_alpha_bits == 1) {
+        CHECK_FOR_FMT(A1R5G5B5);
       }
 
-#ifndef FORCE_16bpp_1555
-      if (num_alpha_bits == 1)
-#endif
-        {
-          CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555);
-        }
-
       // normally prefer 4444 due to better alpha channel resolution
-      CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444);
-      CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555);
+      CHECK_FOR_FMT(A4R4G4B4);
+      CHECK_FOR_FMT(A1R5G5B5);
     } else {
       nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
       // look for compatible 16bit fmts, if none then give up
@@ -454,13 +473,13 @@ create_texture(DXScreenData &scrn) {
       switch(num_alpha_bits) {
       case 0:
         if (num_color_channels == 3) {
-          CHECK_FOR_FMT(R5G6B5, Conv24to16_0565);
-          CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+          CHECK_FOR_FMT(R5G6B5);
+          CHECK_FOR_FMT(X1R5G5B5);
         } else {
           nassertr(num_color_channels == 4, false);
           // it could be 4 if user asks us to throw away the alpha channel
-          CHECK_FOR_FMT(R5G6B5, Conv32to16_0565);
-          CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+          CHECK_FOR_FMT(R5G6B5);
+          CHECK_FOR_FMT(X1R5G5B5);
         }
         break;
       case 1:
@@ -469,13 +488,13 @@ create_texture(DXScreenData &scrn) {
         // could use 32bpp ARGB.  fail if this particular fmt not
         // avail.
         nassertr(num_color_channels == 4, false);
-        CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+        CHECK_FOR_FMT(X1R5G5B5);
         break;
       case 4:
         // app specifically requests 4-4-4-4 F_rgba4 case, as opposed
         // to F_rgba, which could use 32bpp ARGB
         nassertr(num_color_channels == 4, false);
-        CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444);
+        CHECK_FOR_FMT(A4R4G4B4);
         break;
       default:
         nassertr(false, false);  // problem in get_bits_per_pixel()?
@@ -488,16 +507,14 @@ create_texture(DXScreenData &scrn) {
       nassertr(num_color_channels == 1, false);
 
       // look for native lum fmt first
-      CHECK_FOR_FMT(L8, ConvLum8to8);
-      CHECK_FOR_FMT(L8, ConvLum8to16_A8L8);
+      CHECK_FOR_FMT(L8);
+      CHECK_FOR_FMT(L8);
 
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(R8G8B8, ConvLum8to24);
-        CHECK_FOR_FMT(X8R8G8B8, ConvLum8to32);
-      }
+      CHECK_FOR_FMT(R8G8B8);
+      CHECK_FOR_FMT(X8R8G8B8);
 
-      CHECK_FOR_FMT(R5G6B5, ConvLum8to16_0565);
-      CHECK_FOR_FMT(X1R5G5B5, ConvLum8to16_X555);
+      CHECK_FOR_FMT(R5G6B5);
+      CHECK_FOR_FMT(X1R5G5B5);
 
     } else if (num_alpha_bits == 8) {
       // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444.
@@ -507,13 +524,9 @@ create_texture(DXScreenData &scrn) {
       // model we need somehow (is it that voodoo assumes color is
       // white?  isnt that what we do in ConvAlpha8to32 anyway?)
 
-      CHECK_FOR_FMT(A8L8, ConvAlpha8to16_A8L8);
-
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(A8R8G8B8, ConvAlpha8to32);
-      }
-
-      CHECK_FOR_FMT(A4R4G4B4, ConvAlpha8to16_4444);
+      CHECK_FOR_FMT(A8L8);
+      CHECK_FOR_FMT(A8R8G8B8);
+      CHECK_FOR_FMT(A4R4G4B4);
     }
     break;
 
@@ -1506,7 +1519,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn) {
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
       if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
         dxgsg8_cat.debug()
-        << "Using pre-calculated mipmap levels for texture  " << tex->get_name();
+          << "Using pre-calculated mipmap levels for texture  " << tex->get_name() << "\n";
 
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
@@ -1781,10 +1794,10 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) {
     return 24;
   case Texture::F_rgba8:
   case Texture::F_rgba:
+    *alphbits = 8;
+    return 32;
   case Texture::F_rgbm:
-    if (format == Texture::F_rgbm)   // does this make any sense?
-      *alphbits = 1;
-    else *alphbits = 8;
+    *alphbits = 1;
     return 32;
   case Texture::F_rgb12:
     return 36;

+ 2 - 0
panda/src/dxgsg8/dxTextureContext8.h

@@ -28,6 +28,8 @@ public:
   DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex);
   virtual ~DXTextureContext8();
 
+  virtual void evict_lru();
+
   bool create_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   void delete_texture();

+ 33 - 0
panda/src/dxgsg8/dxVertexBufferContext8.cxx

@@ -177,6 +177,39 @@ DXVertexBufferContext8::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXVertexBufferContext8::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXVertexBufferContext8::
+evict_lru() {
+  dequeue_lru();
+
+  if (_vbuffer != NULL) {
+    if (dxgsg8_cat.is_debug()) {
+      dxgsg8_cat.debug()
+        << "deleting vertex buffer " << _vbuffer << "\n";
+    }
+
+    RELEASE(_vbuffer, dxgsg8, "vertex buffer", RELEASE_ONCE);
+    _vbuffer = NULL;
+  }
+
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXVertexBufferContext8::create_vbuffer
 //       Access: Public

+ 2 - 0
panda/src/dxgsg8/dxVertexBufferContext8.h

@@ -29,6 +29,8 @@ public:
   DXVertexBufferContext8(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data);
   virtual ~DXVertexBufferContext8();
 
+  virtual void evict_lru();
+
   void create_vbuffer(DXScreenData &scrn,
                       const GeomVertexArrayDataHandle *reader);
   bool upload_data(const GeomVertexArrayDataHandle *reader, bool force);

+ 0 - 2
panda/src/dxgsg9/config_dxgsg9.cxx

@@ -87,8 +87,6 @@ ConfigVariableBool dx_ignore_mipmaps
 // if this is set, more accurate but more expensive fog computations are performed
 ConfigVariableBool dx_use_rangebased_fog
 ("dx-use-rangebased-fog", false);
-ConfigVariableBool dx_force_16bpptextures
-("dx-force-16bpptextures", false);
 ConfigVariableBool dx_no_dithering
 ("dx-no-dithering", false);
 ConfigVariableBool dx_force_16bpp_zbuffer

+ 0 - 1
panda/src/dxgsg9/config_dxgsg9.h

@@ -38,7 +38,6 @@ extern ConfigVariableBool dx_broken_max_index;
 extern ConfigVariableBool dx_ignore_mipmaps;
 extern ConfigVariableBool dx_mipmap_everything;
 extern ConfigVariableBool dx_show_transforms;
-extern ConfigVariableBool dx_force_16bpptextures;
 extern ConfigVariableBool dx_no_dithering;
 extern ConfigVariableBool dx_force_anisotropic_filtering;
 extern ConfigVariableBool dx_force_16bpp_zbuffer;

+ 8 - 2
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -335,10 +335,10 @@ update_texture(TextureContext *tc, bool force) {
       Texture *tex = tc->get_texture();
       dxgsg9_cat.error()
         << "Unable to re-create texture " << *tex << endl;
-      cerr << "b\n";
       return false;
     }
   }
+  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   return true;
 }
@@ -525,6 +525,7 @@ apply_vertex_buffer(VertexBufferContext *vbc,
       set_stream_source = true;
     }
   }
+  dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   if (shader_context == 0) {
     // FVF MODE
@@ -735,6 +736,7 @@ apply_index_buffer(IndexBufferContext *ibc,
       dibc->set_active(true);
     }
   }
+  dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   return true;
 }
@@ -2243,7 +2245,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   SAFE_RELEASE(render_target);
   SAFE_RELEASE(tex_level_0);
 
-  if (!okflag) {
+  if (okflag) {
+    dtc->mark_loaded();
+    dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
+
+  } else {
     // The copy failed.  Fall back to copying it to RAM and back.
     // Terribly slow, but what are you going to do?
     return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);

+ 23 - 0
panda/src/dxgsg9/dxIndexBufferContext9.cxx

@@ -54,6 +54,29 @@ DXIndexBufferContext9::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXIndexBufferContext9::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXIndexBufferContext9::
+evict_lru() {
+  dequeue_lru();
+  free_ibuffer();
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXIndexBufferContext9::free_ibuffer
 //       Access: Public

+ 2 - 0
panda/src/dxgsg9/dxIndexBufferContext9.h

@@ -29,6 +29,8 @@ public:
   DXIndexBufferContext9(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
   virtual ~DXIndexBufferContext9();
 
+  virtual void evict_lru();
+
   void free_ibuffer();
   void allocate_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader);
   void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader);

+ 109 - 96
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -68,6 +68,35 @@ DXTextureContext9::
   delete_texture();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext9::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXTextureContext9::
+evict_lru() {
+  if (get_texture()->get_render_to_texture()) {
+    // Don't evict the result of render-to-texture.
+    mark_used_lru();
+    return;
+  }
+
+  dequeue_lru();
+  delete_texture();
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXTextureContext9::create_texture
 //       Access: Public
@@ -318,14 +347,47 @@ create_texture(DXScreenData &scrn) {
   // D3DXCheckTextureRequirements(), but it wouldn't handle all my
   // specialized low-memory cases perfectly
 
-#define CONVTYPE_STMT
-
-#define CHECK_FOR_FMT(FMT, CONV)  \
+#define CHECK_FOR_FMT(FMT)  \
                     if (scrn._supported_tex_formats_mask & FMT##_FLAG) {   \
-                        CONVTYPE_STMT;                             \
                         target_pixel_format = D3DFMT_##FMT;                 \
                         goto found_matching_format; }
 
+  if (texture_stored_compressed){
+    // if the texture is already compressed, we need to choose the
+    // corresponding format, otherwise we might end up
+    // cross-compressing from e.g. DXT5 to DXT3
+    switch (compression_mode){
+    case Texture::CM_dxt1:
+      CHECK_FOR_FMT(DXT1);
+      break;
+    case Texture::CM_dxt2:
+      CHECK_FOR_FMT(DXT2);
+      break;
+    case Texture::CM_dxt3:
+      CHECK_FOR_FMT(DXT3);
+      break;
+    case Texture::CM_dxt4:
+      CHECK_FOR_FMT(DXT4);
+      break;
+    case Texture::CM_dxt5:
+      CHECK_FOR_FMT(DXT5);
+      break;
+    }
+    // if we can't support the texture's compressed image, we can't
+    // load the texture.
+    goto error_exit;
+  }
+
+  if (compress_texture) {
+    if (num_alpha_bits <= 1) {
+      CHECK_FOR_FMT(DXT1);    
+    } else if (num_alpha_bits <= 4) {
+      CHECK_FOR_FMT(DXT3);    
+    } else {
+      CHECK_FOR_FMT(DXT5);
+    }
+  }
+
   // handle each target bitdepth separately.  might be less confusing
   // to reorg by num_color_channels (input type, rather than desired
   // 1st target)
@@ -359,36 +421,7 @@ create_texture(DXScreenData &scrn) {
     if (!((num_color_channels == 3) || (num_color_channels == 4)))
       break; //bail
 
-    if (!dx_force_16bpptextures) {
-      if (compress_texture) {
-        if (texture_stored_compressed){
-          // if the texture is already compressed, we need to choose the corresponding format, 
-          // otherwise we might end up cross-compressing from e.g. DXT5 to DXT3
-          switch (compression_mode){
-          case Texture::CM_dxt2:
-            CHECK_FOR_FMT(DXT2, Conv32toDXT2);
-            break;
-          case Texture::CM_dxt3:
-            CHECK_FOR_FMT(DXT3, Conv32toDXT3);
-            break;
-          case Texture::CM_dxt4:
-            CHECK_FOR_FMT(DXT4, Conv32toDXT4);
-            break;
-          case Texture::CM_dxt5:
-            CHECK_FOR_FMT(DXT5, Conv32toDXT5);
-            break;
-          }
-          // if no compressed format matches, just fall trhough to pick a different format          
-        }
-        else
-          CHECK_FOR_FMT(DXT3, Conv32toDXT3);    
-      }
-      if (num_color_channels == 4) {
-        CHECK_FOR_FMT(A8R8G8B8, Conv32to32);
-      } else {
-        CHECK_FOR_FMT(A8R8G8B8, Conv24to32);
-      }
-    }
+    CHECK_FOR_FMT(A8R8G8B8);
 
     if (num_alpha_bits>0) {
       nassertr(num_color_channels == 4, false);
@@ -407,16 +440,13 @@ create_texture(DXScreenData &scrn) {
       // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify
       // 32->16 conversion.  This should be true on most cards.
 
-#ifndef FORCE_16bpp_1555
-      if (num_alpha_bits == 1)
-#endif
-      {
-        CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555);
+      if (num_alpha_bits == 1) {
+        CHECK_FOR_FMT(A1R5G5B5);
       }
 
       // normally prefer 4444 due to better alpha channel resolution
-      CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444);
-      CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555);
+      CHECK_FOR_FMT(A4R4G4B4);
+      CHECK_FOR_FMT(A1R5G5B5);
 
       // At this point, bail.  Don't worry about converting to
       // non-alpha formats yet, I think this will be a very rare case.
@@ -425,11 +455,11 @@ create_texture(DXScreenData &scrn) {
       // convert 3 or 4 channel to closest 16bpp color fmt
 
       if (num_color_channels == 3) {
-        CHECK_FOR_FMT(R5G6B5, Conv24to16_4444);
-        CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+        CHECK_FOR_FMT(R5G6B5);
+        CHECK_FOR_FMT(X1R5G5B5);
       } else {
-        CHECK_FOR_FMT(R5G6B5, Conv32to16_4444);
-        CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+        CHECK_FOR_FMT(R5G6B5);
+        CHECK_FOR_FMT(X1R5G5B5);
       }
     }
     break;
@@ -437,24 +467,19 @@ create_texture(DXScreenData &scrn) {
   case 24:
     nassertr(num_color_channels == 3, false);
 
-    if (compress_texture) {
-      CHECK_FOR_FMT(DXT1, Conv24toDXT1);    
-    }
-
-    if (!dx_force_16bpptextures) {
-//    if (!(want_16bit_rgb_textures || dx_force_16bpptextures)) {
-      CHECK_FOR_FMT(R8G8B8, Conv24to24);
+    CHECK_FOR_FMT(R8G8B8);
 
-      // no 24-bit fmt.  look for 32 bit fmt (note: this is
-      // memory-hogging choice instead I could look for
-      // memory-conserving 16-bit fmt).
+    // no 24-bit fmt.  look for 32 bit fmt (note: this is
+    // memory-hogging choice instead I could look for
+    // memory-conserving 16-bit fmt).
 
-      CHECK_FOR_FMT(X8R8G8B8, Conv24to32);
-    }
+    CHECK_FOR_FMT(X8R8G8B8);
+    CHECK_FOR_FMT(A8R8G8B8);
     
     // no 24-bit or 32 fmt.  look for 16 bit fmt (higher res 565 1st)
-    CHECK_FOR_FMT(R5G6B5, Conv24to16_0565);
-    CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+    CHECK_FOR_FMT(R5G6B5);
+    CHECK_FOR_FMT(X1R5G5B5);
+    CHECK_FOR_FMT(A1R5G5B5);
     break;
 
   case 16:
@@ -462,22 +487,16 @@ create_texture(DXScreenData &scrn) {
       nassertr(num_alpha_bits > 0, false);
       nassertr(num_color_channels == 2, false);
 
-      CHECK_FOR_FMT(A8L8, ConvLum16to16);
-
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(A8R8G8B8, ConvLum16to32);
-      }
+      CHECK_FOR_FMT(A8L8);
+      CHECK_FOR_FMT(A8R8G8B8);
 
-#ifndef FORCE_16bpp_1555
-      if (num_alpha_bits == 1)
-#endif
-      {
-        CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555);
+      if (num_alpha_bits == 1) {
+        CHECK_FOR_FMT(A1R5G5B5);
       }
 
       // normally prefer 4444 due to better alpha channel resolution
-      CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444);
-      CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555);
+      CHECK_FOR_FMT(A4R4G4B4);
+      CHECK_FOR_FMT(A1R5G5B5);
     } else {
       nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
       // look for compatible 16bit fmts, if none then give up
@@ -485,13 +504,13 @@ create_texture(DXScreenData &scrn) {
       switch(num_alpha_bits) {
       case 0:
         if (num_color_channels == 3) {
-          CHECK_FOR_FMT(R5G6B5, Conv24to16_0565);
-          CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
+          CHECK_FOR_FMT(R5G6B5);
+          CHECK_FOR_FMT(X1R5G5B5);
         } else {
           nassertr(num_color_channels == 4, false);
           // it could be 4 if user asks us to throw away the alpha channel
-          CHECK_FOR_FMT(R5G6B5, Conv32to16_0565);
-          CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+          CHECK_FOR_FMT(R5G6B5);
+          CHECK_FOR_FMT(X1R5G5B5);
         }
         break;
       case 1:
@@ -500,13 +519,13 @@ create_texture(DXScreenData &scrn) {
         // could use 32bpp ARGB.  fail if this particular fmt not
         // avail.
         nassertr(num_color_channels == 4, false);
-        CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
+        CHECK_FOR_FMT(X1R5G5B5);
         break;
       case 4:
         // app specifically requests 4-4-4-4 F_rgba4 case, as opposed
         // to F_rgba, which could use 32bpp ARGB
         nassertr(num_color_channels == 4, false);
-        CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444);
+        CHECK_FOR_FMT(A4R4G4B4);
         break;
       default:
         nassertr(false, false);  // problem in get_bits_per_pixel()?
@@ -519,16 +538,14 @@ create_texture(DXScreenData &scrn) {
       nassertr(num_color_channels == 1, false);
 
       // look for native lum fmt first
-      CHECK_FOR_FMT(L8, ConvLum8to8);
-      CHECK_FOR_FMT(L8, ConvLum8to16_A8L8);
+      CHECK_FOR_FMT(L8);
+      CHECK_FOR_FMT(L8);
 
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(R8G8B8, ConvLum8to24);
-        CHECK_FOR_FMT(X8R8G8B8, ConvLum8to32);
-      }
+      CHECK_FOR_FMT(R8G8B8);
+      CHECK_FOR_FMT(X8R8G8B8);
 
-      CHECK_FOR_FMT(R5G6B5, ConvLum8to16_0565);
-      CHECK_FOR_FMT(X1R5G5B5, ConvLum8to16_X555);
+      CHECK_FOR_FMT(R5G6B5);
+      CHECK_FOR_FMT(X1R5G5B5);
 
     } else if (num_alpha_bits == 8) {
       // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444.
@@ -538,13 +555,9 @@ create_texture(DXScreenData &scrn) {
       // model we need somehow (is it that voodoo assumes color is
       // white?  isnt that what we do in ConvAlpha8to32 anyway?)
 
-      CHECK_FOR_FMT(A8L8, ConvAlpha8to16_A8L8);
-
-      if (!dx_force_16bpptextures) {
-        CHECK_FOR_FMT(A8R8G8B8, ConvAlpha8to32);
-      }
-
-      CHECK_FOR_FMT(A4R4G4B4, ConvAlpha8to16_4444);
+      CHECK_FOR_FMT(A8L8);
+      CHECK_FOR_FMT(A8R8G8B8);
+      CHECK_FOR_FMT(A4R4G4B4);
     }
     break;
 
@@ -1739,7 +1752,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn) {
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
       if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
         dxgsg9_cat.debug()
-        << "Using pre-calculated mipmap levels for texture  " << tex->get_name();
+          << "Using pre-calculated mipmap levels for texture  " << tex->get_name() << "\n";
 
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
@@ -2031,10 +2044,10 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) {
     return 24;
   case Texture::F_rgba8:
   case Texture::F_rgba:
+    *alphbits = 8;
+    return 32;
   case Texture::F_rgbm:
-    if (format == Texture::F_rgbm)   // does this make any sense?
-      *alphbits = 1;
-    else *alphbits = 8;
+    *alphbits = 1;
     return 32;
   case Texture::F_rgb12:
     return 36;

+ 2 - 0
panda/src/dxgsg9/dxTextureContext9.h

@@ -30,6 +30,8 @@ public:
   DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex);
   virtual ~DXTextureContext9();
 
+  virtual void evict_lru();
+
   bool create_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   void delete_texture();

+ 23 - 0
panda/src/dxgsg9/dxVertexBufferContext9.cxx

@@ -305,6 +305,29 @@ DXVertexBufferContext9::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXVertexBufferContext9::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void DXVertexBufferContext9::
+evict_lru() {
+  dequeue_lru();
+  free_vbuffer();
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXVertexBufferContext9::free_vbuffer
 //       Access: Public

+ 2 - 0
panda/src/dxgsg9/dxVertexBufferContext9.h

@@ -29,6 +29,8 @@ public:
   DXVertexBufferContext9(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data, DXScreenData &scrn);
   virtual ~DXVertexBufferContext9();
 
+  virtual void evict_lru();
+
   void free_vbuffer();
   void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader);
   void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader, string name);

+ 6 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2676,6 +2676,7 @@ update_texture(TextureContext *tc, bool force) {
     specify_texture(gtc->get_texture());
     gtc->mark_loaded();
   }
+  gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   report_my_gl_errors();
   return true;
@@ -2814,7 +2815,7 @@ record_deleted_display_list(GLuint index) {
 VertexBufferContext *CLP(GraphicsStateGuardian)::
 prepare_vertex_buffer(GeomVertexArrayData *data) {
   if (_supports_buffers) {
-    CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(_prepared_objects, data);
+    CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(this, _prepared_objects, data);
     _glGenBuffers(1, &gvbc->_index);
 
     if (GLCAT.is_debug() && CLP(debug_buffers)) {
@@ -2881,6 +2882,7 @@ apply_vertex_buffer(VertexBufferContext *vbc,
 
     gvbc->mark_loaded(reader);
   }
+  gvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   maybe_gl_finish();
   report_my_gl_errors();
@@ -2998,7 +3000,7 @@ setup_array_data(const unsigned char *&client_pointer,
 IndexBufferContext *CLP(GraphicsStateGuardian)::
 prepare_index_buffer(GeomPrimitive *data) {
   if (_supports_buffers) {
-    CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(_prepared_objects, data);
+    CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(this, _prepared_objects, data);
     _glGenBuffers(1, &gibc->_index);
 
     if (GLCAT.is_debug() && CLP(debug_buffers)) {
@@ -3067,6 +3069,7 @@ apply_index_buffer(IndexBufferContext *ibc,
     }
     gibc->mark_loaded(reader);
   }
+  gibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   maybe_gl_finish();
   report_my_gl_errors();
@@ -3356,6 +3359,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   }
 
   gtc->mark_loaded();
+  gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   report_my_gl_errors();
 

+ 2 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -533,6 +533,8 @@ public:
 private:
   static TypeHandle _type_handle;
 
+  friend class CLP(VertexBufferContext);
+  friend class CLP(IndexBufferContext);
   friend class CLP(ShaderContext);
   friend class CLP(GraphicsBuffer);
   friend class CLP(OcclusionQueryContext);

+ 5 - 2
panda/src/glstuff/glIndexBufferContext_src.I

@@ -19,8 +19,11 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(IndexBufferContext)::
-CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
-  IndexBufferContext(pgo, data)
+CLP(IndexBufferContext)(CLP(GraphicsStateGuardian) *glgsg,
+                        PreparedGraphicsObjects *pgo,
+                        GeomPrimitive *data) :
+  IndexBufferContext(pgo, data),
+  _glgsg(glgsg)
 {
   _index = 0;
 }

+ 40 - 0
panda/src/glstuff/glIndexBufferContext_src.cxx

@@ -13,3 +13,43 @@
 ////////////////////////////////////////////////////////////////////
 
 TypeHandle CLP(IndexBufferContext)::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLIndexBufferContext::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void CLP(IndexBufferContext)::
+evict_lru() {
+  dequeue_lru();
+
+  // Make sure the buffer is unbound before we delete it.
+  if (_glgsg->_current_ibuffer_index == _index) {
+    if (GLCAT.is_debug() && CLP(debug_buffers)) {
+      GLCAT.debug()
+        << "unbinding index buffer\n";
+    }
+    _glgsg->_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    _glgsg->_current_ibuffer_index = 0;
+  }
+
+  // Free the buffer.
+  _glgsg->_glDeleteBuffers(1, &_index);
+
+  // We still need a valid index number, though, in case we want to
+  // re-load the buffer later.
+  _glgsg->_glGenBuffers(1, &_index);
+
+  update_data_size_bytes(0);
+  mark_unloaded();
+}

+ 6 - 1
panda/src/glstuff/glIndexBufferContext_src.h

@@ -23,10 +23,15 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(IndexBufferContext) : public IndexBufferContext {
 public:
-  INLINE CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, 
+  INLINE CLP(IndexBufferContext)(CLP(GraphicsStateGuardian) *glgsg,
+                                 PreparedGraphicsObjects *pgo, 
                                  GeomPrimitive *data);
   ALLOC_DELETED_CHAIN(CLP(IndexBufferContext));
 
+  virtual void evict_lru();
+
+  CLP(GraphicsStateGuardian) *_glgsg;
+
   // This is the GL "name" of the data object.
   GLuint _index;
 

+ 32 - 0
panda/src/glstuff/glTextureContext_src.cxx

@@ -15,3 +15,35 @@
 #include "pnotify.h"
 
 TypeHandle CLP(TextureContext)::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTextureContext::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void CLP(TextureContext)::
+evict_lru() {
+  dequeue_lru();
+
+  // Free the texture resources.
+  GLP(DeleteTextures)(1, &_index);
+
+  // We still need a valid index number, though, in case we want to
+  // re-load the texture later.
+  GLP(GenTextures)(1, &_index);
+
+  _already_applied = false;
+  update_data_size_bytes(0);
+  mark_unloaded();
+}

+ 2 - 0
panda/src/glstuff/glTextureContext_src.h

@@ -25,6 +25,8 @@ public:
   INLINE CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex);
   ALLOC_DELETED_CHAIN(CLP(TextureContext));
 
+  virtual void evict_lru();
+
   // This is the GL "name" of the texture object.
   GLuint _index;
 

+ 5 - 2
panda/src/glstuff/glVertexBufferContext_src.I

@@ -19,8 +19,11 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(VertexBufferContext)::
-CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
-  VertexBufferContext(pgo, data)
+CLP(VertexBufferContext)(CLP(GraphicsStateGuardian) *glgsg,
+                         PreparedGraphicsObjects *pgo, 
+                         GeomVertexArrayData *data) :
+  VertexBufferContext(pgo, data),
+  _glgsg(glgsg)
 {
   _index = 0;
 }

+ 40 - 0
panda/src/glstuff/glVertexBufferContext_src.cxx

@@ -13,3 +13,43 @@
 ////////////////////////////////////////////////////////////////////
 
 TypeHandle CLP(VertexBufferContext)::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLVertexBufferContext::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void CLP(VertexBufferContext)::
+evict_lru() {
+  dequeue_lru();
+
+  // Make sure the buffer is unbound before we delete it.
+  if (_glgsg->_current_vbuffer_index == _index) {
+    if (GLCAT.is_debug() && CLP(debug_buffers)) {
+      GLCAT.debug()
+        << "unbinding vertex buffer\n";
+    }
+    _glgsg->_glBindBuffer(GL_ARRAY_BUFFER, 0);
+    _glgsg->_current_vbuffer_index = 0;
+  }
+
+  // Free the buffer.
+  _glgsg->_glDeleteBuffers(1, &_index);
+
+  // We still need a valid index number, though, in case we want to
+  // re-load the buffer later.
+  _glgsg->_glGenBuffers(1, &_index);
+
+  update_data_size_bytes(0);
+  mark_unloaded();
+}

+ 8 - 1
panda/src/glstuff/glVertexBufferContext_src.h

@@ -16,6 +16,8 @@
 #include "vertexBufferContext.h"
 #include "deletedChain.h"
 
+class CLP(GraphicsStateGuardian);
+
 ////////////////////////////////////////////////////////////////////
 //       Class : GLVertexBufferContext
 // Description : Caches a GeomVertexArrayData on the GL as a buffer
@@ -23,10 +25,15 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(VertexBufferContext) : public VertexBufferContext {
 public:
-  INLINE CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, 
+  INLINE CLP(VertexBufferContext)(CLP(GraphicsStateGuardian) *glgsg,
+                                  PreparedGraphicsObjects *pgo, 
                                   GeomVertexArrayData *data);
   ALLOC_DELETED_CHAIN(CLP(VertexBufferContext));
 
+  virtual void evict_lru();
+
+  CLP(GraphicsStateGuardian) *_glgsg;
+
   // This is the GL "name" of the data object.
   GLuint _index;
 

+ 13 - 0
panda/src/gobj/config_gobj.cxx

@@ -374,6 +374,19 @@ ConfigVariableInt vertex_data_page_threads
           "is 0, this work will be done in the main thread, which may "
           "introduce occasional random chugs in rendering."));
 
+ConfigVariableInt graphics_memory_limit
+("graphics-memory-limit", -1,
+ PRC_DESC("This is a default limit that is imposed on each GSG at "
+          "GSG creation time.  It limits the total amount of graphics "
+          "memory, including texture memory and vertex buffer memory, "
+          "that will be consumed by the GSG, regardless of whether the "
+          "hardware claims to provide more graphics memory than this.  "
+          "It is useful to put a ceiling on graphics memory consumed, since "
+          "some drivers seem to allow the application to consume more "
+          "memory than the hardware can realistically support.  "
+          "Set this to -1 to have no limit other than the normal "
+          "hardware-imposed limit."));
+
 ConfigureFn(config_gobj) {
   BufferContext::init_type();
   Geom::init_type();

+ 1 - 0
panda/src/gobj/config_gobj.h

@@ -92,6 +92,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableFilename vertex_save_file_directory;
 extern EXPCL_PANDA_GOBJ ConfigVariableString vertex_save_file_prefix;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_small_size;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_page_threads;
+extern EXPCL_PANDA_GOBJ ConfigVariableInt graphics_memory_limit;
 
 #endif
 

+ 25 - 0
panda/src/gobj/indexBufferContext.I

@@ -21,6 +21,7 @@
 INLINE IndexBufferContext::
 IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
   BufferContext(&pgo->_ibuffer_residency),
+  SimpleLruPage(0),
   _data(data)
 {
 }
@@ -72,6 +73,18 @@ was_modified(const GeomPrimitivePipelineReader *reader) const {
   return get_modified() != reader->get_modified();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: IndexBufferContext::update_data_size_bytes
+//       Access: Public
+//  Description: Should be called (usually by a derived class) when
+//               the on-card size of this object has changed.
+////////////////////////////////////////////////////////////////////
+INLINE void IndexBufferContext::
+update_data_size_bytes(size_t new_data_size_bytes) {
+  BufferContext::update_data_size_bytes(new_data_size_bytes);
+  SimpleLruPage::set_lru_size(new_data_size_bytes);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: IndexBufferContext::mark_loaded
 //       Access: Public
@@ -89,3 +102,15 @@ mark_loaded(const GeomPrimitivePipelineReader *reader) {
   // Assume the buffer is now resident.
   set_resident(true);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexBufferContext::mark_unloaded
+//       Access: Public
+//  Description: Should be called after the buffer has been forced
+//               out of graphics memory.
+////////////////////////////////////////////////////////////////////
+INLINE void IndexBufferContext::
+mark_unloaded() {
+  update_modified(UpdateSeq::old());
+  set_resident(false);
+}

+ 4 - 1
panda/src/gobj/indexBufferContext.h

@@ -20,6 +20,7 @@
 #include "bufferContext.h"
 #include "geomPrimitive.h"
 #include "preparedGraphicsObjects.h"
+#include "simpleLru.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : IndexBufferContext
@@ -32,7 +33,7 @@
 //               allocate a vertex buffer for the array.  OpenGL can
 //               create a buffer object.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_GOBJ IndexBufferContext : public BufferContext {
+class EXPCL_PANDA_GOBJ IndexBufferContext : public BufferContext, public SimpleLruPage {
 public:
   INLINE IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
 
@@ -44,7 +45,9 @@ PUBLISHED:
   INLINE bool was_modified(const GeomPrimitivePipelineReader *reader) const;
 
 public:
+  INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void mark_loaded(const GeomPrimitivePipelineReader *reader);
+  INLINE void mark_unloaded();
 
 private:
   // This cannot be a PT(GeomPrimitive), because the data and

+ 32 - 0
panda/src/gobj/preparedGraphicsObjects.I

@@ -25,6 +25,38 @@ get_name() const {
   return _name;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::set_graphics_memory_limit
+//       Access: Public
+//  Description: Sets an artificial cap on graphics memory that
+//               will be imposed on this GSG.
+//
+//               This limits the total amount of graphics memory,
+//               including texture memory and vertex buffer memory,
+//               that will be consumed by the GSG, regardless of
+//               whether the hardware claims to provide more graphics
+//               memory than this. It is useful to put a ceiling on
+//               graphics memory consumed, since some drivers seem to
+//               allow the application to consume more memory than the
+//               hardware can realistically support.
+////////////////////////////////////////////////////////////////////
+INLINE void PreparedGraphicsObjects::
+set_graphics_memory_limit(size_t limit) {
+  _graphics_memory_lru.set_max_size(limit);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::get_graphics_memory_limit
+//       Access: Public
+//  Description: Returns the artificial cap on graphics memory that
+//               will be imposed on this GSG.  See
+//               set_graphics_memory_limit().
+////////////////////////////////////////////////////////////////////
+INLINE size_t PreparedGraphicsObjects::
+get_graphics_memory_limit() const {
+  return _graphics_memory_lru.get_max_size();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PreparedGraphicsObjects::release_all
 //       Access: Public

+ 3 - 1
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -24,6 +24,7 @@
 #include "reMutexHolder.h"
 #include "geomContext.h"
 #include "shaderContext.h"
+#include "config_gobj.h"
 
 int PreparedGraphicsObjects::_name_index = 0;
 
@@ -40,7 +41,8 @@ PreparedGraphicsObjects() :
   _index_buffer_cache_size(0),
   _texture_residency(_name, "texture"),
   _vbuffer_residency(_name, "vbuffer"),
-  _ibuffer_residency(_name, "ibuffer")
+  _ibuffer_residency(_name, "ibuffer"),
+  _graphics_memory_lru("graphics_memory_lru", graphics_memory_limit)
 {
   // GLGSG will turn this flag on.  This is a temporary hack to
   // disable this feature for DX8/DX9 for now, until we work out the

+ 5 - 0
panda/src/gobj/preparedGraphicsObjects.h

@@ -62,6 +62,9 @@ public:
 PUBLISHED:
   INLINE const string &get_name() const;
 
+  INLINE void set_graphics_memory_limit(size_t limit);
+  INLINE size_t get_graphics_memory_limit() const;
+
   INLINE void release_all();
   INLINE int get_num_queued() const;
   INLINE int get_num_prepared() const;
@@ -196,6 +199,8 @@ public:
   BufferResidencyTracker _vbuffer_residency;
   BufferResidencyTracker _ibuffer_residency;
 
+  SimpleLru _graphics_memory_lru;
+
 public:
   // This is only public as a temporary hack.  Don't mess with it
   // unless you know what you're doing.

+ 17 - 2
panda/src/gobj/simpleLru.I

@@ -50,7 +50,7 @@ set_max_size(size_t max_size) {
   MutexHolder holder(_global_lock);
   _max_size = max_size;
   if (_total_size > _max_size) {
-    do_evict();
+    do_evict_to(_max_size, false);
   }
 }
 
@@ -63,7 +63,22 @@ INLINE void SimpleLru::
 consider_evict() {
   MutexHolder holder(_global_lock);
   if (_total_size > _max_size) {
-    do_evict();
+    do_evict_to(_max_size, false);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::evict_to
+//       Access: Published
+//  Description: Evicts a sequence of objects until the queue fits
+//               within the indicated target size, regardless of its
+//               normal max size.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLru::
+evict_to(size_t target_size) {
+  MutexHolder holder(_global_lock);
+  if (_total_size > target_size) {
+    do_evict_to(target_size, true);
   }
 }
 

+ 8 - 7
panda/src/gobj/simpleLru.cxx

@@ -114,14 +114,15 @@ count_active_size() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SimpleLru::do_evict
+//     Function: SimpleLru::do_evict_to
 //       Access: Private
-//  Description: Evicts pages until the LRU is within tolerance.
-//               Assumes the lock is already held.  Does not evict
-//               "active" pages that were added within this epoch.
+//  Description: Evicts pages until the LRU is within the indicated
+//               size.  Assumes the lock is already held.  If
+//               hard_evict is false, does not evict "active" pages
+//               that were added within this epoch.
 ////////////////////////////////////////////////////////////////////
 void SimpleLru::
-do_evict() {
+do_evict_to(size_t target_size, bool hard_evict) {
   if (_next == this) {
     // Nothing in the queue.
     return;
@@ -134,7 +135,7 @@ do_evict() {
 
   // Now walk through the list.
   SimpleLruPage *node = (SimpleLruPage *)_next;
-  while (_total_size > _max_size) {
+  while (_total_size > target_size) {
     SimpleLruPage *next = (SimpleLruPage *)node->_next;
 
     // We must release the lock while we call evict_lru().
@@ -146,7 +147,7 @@ do_evict() {
       // If we reach the original tail of the list, stop.
       return;
     }
-    if (node == _active_marker) {
+    if (!hard_evict && node == _active_marker) {
       // Also stop if we reach the active marker.  Nodes beyond this
       // were added within this epoch.
       return;

+ 2 - 1
panda/src/gobj/simpleLru.h

@@ -38,13 +38,14 @@ PUBLISHED:
   size_t count_active_size() const;
 
   INLINE void consider_evict();
+  INLINE void evict_to(size_t target_size);
   INLINE void begin_epoch();
 
 public:
   static Mutex &_global_lock;
 
 private:
-  void do_evict();
+  void do_evict_to(size_t target_size, bool hard_evict);
   bool do_validate_size();
 
   size_t _total_size;

+ 29 - 0
panda/src/gobj/textureContext.I

@@ -21,6 +21,7 @@
 INLINE TextureContext::
 TextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
   BufferContext(&pgo->_texture_residency),
+  SimpleLruPage(0),
   _texture(tex)
 {
 }
@@ -84,6 +85,18 @@ was_simple_image_modified() const {
   return _simple_image_modified != _texture->get_simple_image_modified();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureContext::update_data_size_bytes
+//       Access: Public
+//  Description: Should be called (usually by a derived class) when
+//               the on-card size of this object has changed.
+////////////////////////////////////////////////////////////////////
+INLINE void TextureContext::
+update_data_size_bytes(size_t new_data_size_bytes) {
+  BufferContext::update_data_size_bytes(new_data_size_bytes);
+  SimpleLruPage::set_lru_size(new_data_size_bytes);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureContext::mark_loaded
 //       Access: Public
@@ -117,3 +130,19 @@ mark_simple_loaded() {
   // The texture's not exactly resident now, but some part of it is.
   set_resident(true);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureContext::mark_unloaded
+//       Access: Public
+//  Description: Should be called after the texture has been forced
+//               out of texture memory.
+////////////////////////////////////////////////////////////////////
+INLINE void TextureContext::
+mark_unloaded() {
+  _properties_modified = UpdateSeq::old();
+  _image_modified = UpdateSeq::old();
+  _simple_image_modified = UpdateSeq::old();
+  update_modified(UpdateSeq::old());
+
+  set_resident(false);
+}

+ 4 - 1
panda/src/gobj/textureContext.h

@@ -20,6 +20,7 @@
 #include "bufferContext.h"
 #include "texture.h"
 #include "preparedGraphicsObjects.h"
+#include "simpleLru.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TextureContext
@@ -34,7 +35,7 @@
 //               texture and store it here.  The texture stores all of
 //               these handles internally.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_GOBJ TextureContext : public BufferContext {
+class EXPCL_PANDA_GOBJ TextureContext : public BufferContext, public SimpleLruPage {
 public:
   INLINE TextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
 
@@ -47,8 +48,10 @@ PUBLISHED:
   INLINE bool was_simple_image_modified() const;
 
 public:
+  INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void mark_loaded();
   INLINE void mark_simple_loaded();
+  INLINE void mark_unloaded();
 
 private:
   // This cannot be a PT(Texture), because the texture and the GSG

+ 25 - 0
panda/src/gobj/vertexBufferContext.I

@@ -21,6 +21,7 @@
 INLINE VertexBufferContext::
 VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
   BufferContext(&pgo->_vbuffer_residency),
+  SimpleLruPage(0),
   _data(data)
 {
 }
@@ -72,6 +73,18 @@ was_modified(const GeomVertexArrayDataHandle *reader) const {
   return get_modified() != reader->get_modified();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::update_data_size_bytes
+//       Access: Public
+//  Description: Should be called (usually by a derived class) when
+//               the on-card size of this object has changed.
+////////////////////////////////////////////////////////////////////
+INLINE void VertexBufferContext::
+update_data_size_bytes(size_t new_data_size_bytes) {
+  BufferContext::update_data_size_bytes(new_data_size_bytes);
+  SimpleLruPage::set_lru_size(new_data_size_bytes);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VertexBufferContext::mark_loaded
 //       Access: Public
@@ -89,3 +102,15 @@ mark_loaded(const GeomVertexArrayDataHandle *reader) {
   // Assume the buffer is now resident.
   set_resident(true);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::mark_unloaded
+//       Access: Public
+//  Description: Should be called after the buffer has been forced
+//               out of graphics memory.
+////////////////////////////////////////////////////////////////////
+INLINE void VertexBufferContext::
+mark_unloaded() {
+  update_modified(UpdateSeq::old());
+  set_resident(false);
+}

+ 4 - 1
panda/src/gobj/vertexBufferContext.h

@@ -20,6 +20,7 @@
 #include "bufferContext.h"
 #include "geomVertexArrayData.h"
 #include "preparedGraphicsObjects.h"
+#include "simpleLru.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : VertexBufferContext
@@ -32,7 +33,7 @@
 //               allocate a vertex buffer for the array.  OpenGL can
 //               create a buffer object.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_GOBJ VertexBufferContext : public BufferContext {
+class EXPCL_PANDA_GOBJ VertexBufferContext : public BufferContext, public SimpleLruPage {
 public:
   INLINE VertexBufferContext(PreparedGraphicsObjects *pgo,
                              GeomVertexArrayData *data);
@@ -45,7 +46,9 @@ PUBLISHED:
   INLINE bool was_modified(const GeomVertexArrayDataHandle *reader) const;
 
 public:
+  INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void mark_loaded(const GeomVertexArrayDataHandle *reader);
+  INLINE void mark_unloaded();
 
 private:
   // This cannot be a PT(GeomVertexArrayData), because the data and

+ 0 - 10
panda/src/tinydisplay/config_tinydisplay.cxx

@@ -79,16 +79,6 @@ ConfigVariableInt osx_mouse_wheel_scale
  PRC_DESC("Specify the number of units to spin the Mac mouse wheel to "
           "represent a single wheel_up or wheel_down message."));
 
-ConfigVariableInt td_texture_ram
-("td-texture-ram", -1,
- PRC_DESC("This specifies the maximum amount of RAM to devote to keeping "
-          "textures resident with the tinydisplay software renderer.  When "
-          "this limit is exceeded, textures over the limit that have not "
-          "been rendered within the current frame will be evicted.  "
-          "(Textures will not be evicted while they are still in the "
-          "frame, even if this means this limit remains exceeded.)  "
-          "Set it to -1 for no limit."));
-
 ConfigVariableBool td_ignore_mipmaps
   ("td-ignore-mipmaps", false,
    PRC_DESC("Configure this true to disable use of mipmaps on the "

+ 3 - 7
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -50,8 +50,7 @@ PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_perspective_pcolle
 TinyGraphicsStateGuardian::
 TinyGraphicsStateGuardian(GraphicsPipe *pipe,
 			 TinyGraphicsStateGuardian *share_with) :
-  GraphicsStateGuardian(CS_yup_right, pipe),
-  _textures_lru("textures_lru", td_texture_ram)
+  GraphicsStateGuardian(CS_yup_right, pipe)
 {
   _current_frame_buffer = NULL;
   _aux_frame_buffer = NULL;
@@ -466,9 +465,6 @@ end_frame(Thread *current_thread) {
   _pixel_count_flat_perspective_pcollector.flush_level();
   _pixel_count_smooth_perspective_pcollector.flush_level();
 #endif  // DO_PSTATS
-
-  // Evict any textures that exceed our texture memory.
-  _textures_lru.begin_epoch();
 }
 
 
@@ -1274,7 +1270,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 
   gtc->update_data_size_bytes(gltex->xsize * gltex->ysize * 4);
   gtc->mark_loaded();
-  gtc->enqueue_lru(&_textures_lru);
+  gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   return true;
 }
@@ -1501,7 +1497,7 @@ update_texture(TextureContext *tc, bool force) {
       return false;
     }
   }
-  gtc->enqueue_lru(&_textures_lru);
+  gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
 
   _c->current_texture = gltex;
   _c->zb->current_texture = gltex->levels;

+ 0 - 2
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -145,8 +145,6 @@ private:
   bool _texture_replace;
   bool _filled_flat;
 
-  SimpleLru _textures_lru;
-
   CPT(TransformState) _scissor_mat;
 
   // Used during being_draw_primitives() .. end_draw_primitives().

+ 1 - 14
panda/src/tinydisplay/tinyTextureContext.I

@@ -20,7 +20,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE TinyTextureContext::
 TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
-  TextureContext(pgo, tex), SimpleLruPage(0)
+  TextureContext(pgo, tex)
 {
   _gltex.num_levels = 0;
   _gltex.allocated_buffer = NULL;
@@ -36,16 +36,3 @@ INLINE TinyTextureContext::
 ~TinyTextureContext() {
   nassertv(_gltex.num_levels == 0 && _gltex.allocated_buffer == NULL && _gltex.total_bytecount == 0);
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: TinyTextureContext::update_data_size_bytes
-//       Access: Public
-//  Description: This is overloaded (non-virtually) to update both the
-//               BufferContext and the LRU page with the same
-//               information.
-////////////////////////////////////////////////////////////////////
-INLINE void TinyTextureContext::
-update_data_size_bytes(size_t new_data_size_bytes) {
-  TextureContext::update_data_size_bytes(new_data_size_bytes);
-  SimpleLruPage::set_lru_size(new_data_size_bytes);
-}

+ 2 - 1
panda/src/tinydisplay/tinyTextureContext.cxx

@@ -48,5 +48,6 @@ evict_lru() {
     nassertv(gltex->num_levels == 0);
   }
 
-  set_resident(false);
+  update_data_size_bytes(0);
+  mark_unloaded();
 }

+ 1 - 3
panda/src/tinydisplay/tinyTextureContext.h

@@ -18,21 +18,19 @@
 #include "pandabase.h"
 #include "textureContext.h"
 #include "deletedChain.h"
-#include "simpleLru.h"
 #include "zgl.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TinyTextureContext
 // Description :
 ////////////////////////////////////////////////////////////////////
-class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext, public SimpleLruPage {
+class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext {
 public:
   INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
   ALLOC_DELETED_CHAIN(TinyTextureContext);
 
   INLINE ~TinyTextureContext();
 
-  INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   virtual void evict_lru();
 
   GLTexture _gltex;