Browse Source

display: handle resource releases in batches, not individually

This is intended to eventually replace the old interface, since GSGs may be able to do a batch of prepare/release operations more efficiently.
rdb 6 years ago
parent
commit
207263c1a8

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

@@ -577,6 +577,17 @@ void GraphicsStateGuardian::
 release_texture(TextureContext *) {
 }
 
+/**
+ * Frees the resources previously allocated via a call to prepare_texture(),
+ * including deleting the TextureContext itself, if it is non-NULL.
+ */
+void GraphicsStateGuardian::
+release_textures(const pvector<TextureContext *> &contexts) {
+  for (TextureContext *tc : contexts) {
+    release_texture(tc);
+  }
+}
+
 /**
  * This method should only be called by the GraphicsEngine.  Do not call it
  * directly; call GraphicsEngine::extract_texture_data() instead.
@@ -666,6 +677,17 @@ void GraphicsStateGuardian::
 release_vertex_buffer(VertexBufferContext *) {
 }
 
+/**
+ * Frees the resources previously allocated via a call to prepare_data(),
+ * including deleting the VertexBufferContext itself, if necessary.
+ */
+void GraphicsStateGuardian::
+release_vertex_buffers(const pvector<BufferContext *> &contexts) {
+  for (BufferContext *bc : contexts) {
+    release_vertex_buffer((VertexBufferContext *)bc);
+  }
+}
+
 /**
  * Prepares the indicated buffer for retained-mode rendering.
  */
@@ -682,6 +704,17 @@ void GraphicsStateGuardian::
 release_index_buffer(IndexBufferContext *) {
 }
 
+/**
+ * Frees the resources previously allocated via a call to prepare_data(),
+ * including deleting the IndexBufferContext itself, if necessary.
+ */
+void GraphicsStateGuardian::
+release_index_buffers(const pvector<BufferContext *> &contexts) {
+  for (BufferContext *bc : contexts) {
+    release_index_buffer((IndexBufferContext *)bc);
+  }
+}
+
 /**
  * Prepares the indicated buffer for retained-mode rendering.
  */
@@ -698,6 +731,17 @@ void GraphicsStateGuardian::
 release_shader_buffer(BufferContext *) {
 }
 
+/**
+ * Frees the resources previously allocated via a call to prepare_data(),
+ * including deleting the BufferContext itself, if necessary.
+ */
+void GraphicsStateGuardian::
+release_shader_buffers(const pvector<BufferContext *> &contexts) {
+  for (BufferContext *bc : contexts) {
+    release_shader_buffer(bc);
+  }
+}
+
 /**
  * Begins a new occlusion query.  After this call, you may call
  * begin_draw_primitives() and draw_triangles()/draw_whatever() repeatedly.

+ 4 - 0
panda/src/display/graphicsStateGuardian.h

@@ -293,6 +293,7 @@ public:
   virtual TextureContext *prepare_texture(Texture *tex, int view);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
+  virtual void release_textures(const pvector<TextureContext *> &contexts);
   virtual bool extract_texture_data(Texture *tex);
 
   virtual SamplerContext *prepare_sampler(const SamplerState &sampler);
@@ -306,12 +307,15 @@ public:
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
+  virtual void release_vertex_buffers(const pvector<BufferContext *> &contexts);
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual void release_index_buffer(IndexBufferContext *ibc);
+  virtual void release_index_buffers(const pvector<BufferContext *> &contexts);
 
   virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data);
   virtual void release_shader_buffer(BufferContext *ibc);
+  virtual void release_shader_buffers(const pvector<BufferContext *> &contexts);
 
   virtual void begin_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();

+ 180 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -5991,6 +5991,48 @@ release_texture(TextureContext *tc) {
   delete gtc;
 }
 
+/**
+ * Frees the GL resources previously allocated for the textures.  This function
+ * should never be called directly; instead, call Texture::release() (or
+ * simply let the Texture destruct).
+ */
+void CLP(GraphicsStateGuardian)::
+release_textures(const pvector<TextureContext *> &contexts) {
+  if (contexts.empty()) {
+    return;
+  }
+
+  GLuint *indices = (GLuint *)alloca(sizeof(GLuint) * contexts.size() * 2);
+  GLuint *buffers = indices + contexts.size();
+  size_t num_indices = 0;
+  size_t num_buffers = 0;
+
+  for (TextureContext *tc : contexts) {
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+
+#ifndef OPENGLES_1
+    _textures_needing_fetch_barrier.erase(gtc);
+    _textures_needing_image_access_barrier.erase(gtc);
+    _textures_needing_update_barrier.erase(gtc);
+    _textures_needing_framebuffer_barrier.erase(gtc);
+#endif
+
+    indices[num_indices++] = gtc->_index;
+
+    if (gtc->_buffer != 0) {
+      buffers[num_buffers++] = gtc->_buffer;
+    }
+
+    delete gtc;
+  }
+
+  glDeleteTextures(num_indices, indices);
+
+  if (num_buffers > 0) {
+    _glDeleteBuffers(num_buffers, buffers);
+  }
+}
+
 /**
  * This method should only be called by the GraphicsEngine.  Do not call it
  * directly; call GraphicsEngine::extract_texture_data() instead.
@@ -6372,6 +6414,52 @@ release_vertex_buffer(VertexBufferContext *vbc) {
   delete gvbc;
 }
 
+/**
+ * Frees the GL resources previously allocated for the data.  This function
+ * should never be called directly; instead, call Data::release() (or simply
+ * let the Data destruct).
+ */
+void CLP(GraphicsStateGuardian)::
+release_vertex_buffers(const pvector<BufferContext *> &contexts) {
+  if (contexts.empty()) {
+    return;
+  }
+  nassertv(_supports_buffers);
+  bool debug = GLCAT.is_debug() && gl_debug_buffers;
+
+  GLuint *indices = (GLuint *)alloca(sizeof(GLuint) * contexts.size());
+  size_t num_indices = 0;
+
+  for (BufferContext *bc : contexts) {
+    CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), bc);
+
+    // Make sure the buffer is unbound before we delete it.  Not strictly
+    // necessary according to the OpenGL spec, but it might help out a flaky
+    // driver, and we need to keep our internal state consistent anyway.
+    if (_current_vbuffer_index == gvbc->_index) {
+      if (debug && GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "unbinding vertex buffer " << gvbc->_index << "\n";
+      }
+      _glBindBuffer(GL_ARRAY_BUFFER, 0);
+      _current_vbuffer_index = 0;
+    }
+
+    if (debug) {
+      GLCAT.debug()
+        << "deleting vertex buffer " << gvbc->_index << "\n";
+    }
+
+    indices[num_indices++] = gvbc->_index;
+    gvbc->_index = 0;
+
+    delete gvbc;
+  }
+
+  _glDeleteBuffers(num_indices, indices);
+  report_my_gl_errors();
+}
+
 /**
  * Internal function to bind a buffer object for the indicated data array, if
  * appropriate, or to unbind a buffer object if it should be rendered from
@@ -6561,6 +6649,52 @@ release_index_buffer(IndexBufferContext *ibc) {
   delete gibc;
 }
 
+/**
+ * Frees the GL resources previously allocated for the data.  This function
+ * should never be called directly; instead, call Data::release() (or simply
+ * let the Data destruct).
+ */
+void CLP(GraphicsStateGuardian)::
+release_index_buffers(const pvector<BufferContext *> &contexts) {
+  if (contexts.empty()) {
+    return;
+  }
+  nassertv(_supports_buffers);
+  bool debug = GLCAT.is_debug() && gl_debug_buffers;
+
+  GLuint *indices = (GLuint *)alloca(sizeof(GLuint) * contexts.size());
+  size_t num_indices = 0;
+
+  for (BufferContext *bc : contexts) {
+    CLP(IndexBufferContext) *gibc = DCAST(CLP(IndexBufferContext), bc);
+
+    // Make sure the buffer is unbound before we delete it.  Not strictly
+    // necessary according to the OpenGL spec, but it might help out a flaky
+    // driver, and we need to keep our internal state consistent anyway.
+    if (_current_ibuffer_index == gibc->_index) {
+      if (debug && GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "unbinding index buffer " << gibc->_index << "\n";
+      }
+      _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+      _current_ibuffer_index = 0;
+    }
+
+    if (debug) {
+      GLCAT.debug()
+        << "deleting index buffer " << gibc->_index << "\n";
+    }
+
+    indices[num_indices++] = gibc->_index;
+    gibc->_index = 0;
+
+    delete gibc;
+  }
+
+  _glDeleteBuffers(num_indices, indices);
+  report_my_gl_errors();
+}
+
 /**
  * Internal function to bind a buffer object for the indicated primitive's
  * index list, if appropriate, or to unbind a buffer object if it should be
@@ -6726,6 +6860,52 @@ release_shader_buffer(BufferContext *bc) {
 
   delete gbc;
 }
+
+/**
+ * Frees the GL resources previously allocated for the data.  This function
+ * should never be called directly; instead, call Data::release() (or simply
+ * let the Data destruct).
+ */
+void CLP(GraphicsStateGuardian)::
+release_shader_buffers(const pvector<BufferContext *> &contexts) {
+  if (contexts.empty()) {
+    return;
+  }
+  nassertv(_supports_buffers);
+  bool debug = GLCAT.is_debug() && gl_debug_buffers;
+
+  GLuint *indices = (GLuint *)alloca(sizeof(GLuint) * contexts.size());
+  size_t num_indices = 0;
+
+  for (BufferContext *bc : contexts) {
+    CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc);
+
+    // Make sure the buffer is unbound before we delete it.  Not strictly
+    // necessary according to the OpenGL spec, but it might help out a flaky
+    // driver, and we need to keep our internal state consistent anyway.
+    if (_current_sbuffer_index == gbc->_index) {
+      if (debug && GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "unbinding shader buffer " << gbc->_index << "\n";
+      }
+      _glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+      _current_sbuffer_index = 0;
+    }
+
+    if (debug) {
+      GLCAT.debug()
+        << "deleting shader buffer " << gbc->_index << "\n";
+    }
+
+    indices[num_indices++] = gbc->_index;
+    gbc->_index = 0;
+
+    delete gbc;
+  }
+
+  _glDeleteBuffers(num_indices, indices);
+  report_my_gl_errors();
+}
 #endif
 
 #ifndef OPENGLES

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

@@ -333,6 +333,7 @@ public:
   virtual TextureContext *prepare_texture(Texture *tex, int view);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
+  virtual void release_textures(const pvector<TextureContext *> &contexts);
   virtual bool extract_texture_data(Texture *tex);
 
 #ifndef OPENGLES_1
@@ -353,6 +354,7 @@ public:
                             const GeomVertexArrayDataHandle *reader,
                             bool force);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
+  virtual void release_vertex_buffers(const pvector<BufferContext *> &contexts);
 
   bool setup_array_data(const unsigned char *&client_pointer,
                         const GeomVertexArrayDataHandle *data,
@@ -363,6 +365,7 @@ public:
                           const GeomPrimitivePipelineReader *reader,
                           bool force);
   virtual void release_index_buffer(IndexBufferContext *ibc);
+  virtual void release_index_buffers(const pvector<BufferContext *> &contexts);
   bool setup_primitive(const unsigned char *&client_pointer,
                        const GeomPrimitivePipelineReader *reader,
                        bool force);
@@ -371,6 +374,7 @@ public:
   virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data);
   void apply_shader_buffer(GLuint base, ShaderBuffer *buffer);
   virtual void release_shader_buffer(BufferContext *bc);
+  virtual void release_shader_buffers(const pvector<BufferContext *> &contexts);
 #endif
 
 #ifndef OPENGLES

+ 46 - 94
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -66,71 +66,43 @@ PreparedGraphicsObjects::
   ReMutexHolder holder(_lock);
 
   release_all_textures();
-  Textures::iterator tci;
-  for (tci = _released_textures.begin();
-       tci != _released_textures.end();
-       ++tci) {
-    TextureContext *tc = (*tci);
+  for (TextureContext *tc : _released_textures) {
     delete tc;
   }
   _released_textures.clear();
 
   release_all_samplers();
-  ReleasedSamplers::iterator ssci;
-  for (ssci = _released_samplers.begin();
-       ssci != _released_samplers.end();
-       ++ssci) {
-    SamplerContext *sc = (*ssci);
+  for (SamplerContext *sc : _released_samplers) {
     delete sc;
   }
   _released_samplers.clear();
 
   release_all_geoms();
-  Geoms::iterator gci;
-  for (gci = _released_geoms.begin();
-       gci != _released_geoms.end();
-       ++gci) {
-    GeomContext *gc = (*gci);
+  for (GeomContext *gc : _released_geoms) {
     delete gc;
   }
   _released_geoms.clear();
 
   release_all_shaders();
-  Shaders::iterator sci;
-  for (sci = _released_shaders.begin();
-       sci != _released_shaders.end();
-       ++sci) {
-    ShaderContext *sc = (*sci);
+  for (ShaderContext *sc : _released_shaders) {
     delete sc;
   }
   _released_shaders.clear();
 
   release_all_vertex_buffers();
-  Buffers::iterator vbci;
-  for (vbci = _released_vertex_buffers.begin();
-       vbci != _released_vertex_buffers.end();
-       ++vbci) {
-    VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
-    delete vbc;
+  for (BufferContext *bc : _released_vertex_buffers) {
+    delete bc;
   }
   _released_vertex_buffers.clear();
 
   release_all_index_buffers();
-  Buffers::iterator ibci;
-  for (ibci = _released_index_buffers.begin();
-       ibci != _released_index_buffers.end();
-       ++ibci) {
-    IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
-    delete ibc;
+  for (BufferContext *bc : _released_index_buffers) {
+    delete bc;
   }
   _released_index_buffers.clear();
 
   release_all_shader_buffers();
-  Buffers::iterator bci;
-  for (bci = _released_shader_buffers.begin();
-       bci != _released_shader_buffers.end();
-       ++bci) {
-    BufferContext *bc = (BufferContext *)(*bci);
+  for (BufferContext *bc : _released_shader_buffers) {
     delete bc;
   }
   _released_shader_buffers.clear();
@@ -279,7 +251,7 @@ release_texture(TextureContext *tc) {
   bool removed = (_prepared_textures.erase(tc) != 0);
   nassertv(removed);
 
-  _released_textures.insert(tc);
+  _released_textures.push_back(tc);
 }
 
 /**
@@ -310,7 +282,7 @@ release_all_textures() {
     tc->get_texture()->clear_prepared(tc->get_view(), this);
     tc->_object = nullptr;
 
-    _released_textures.insert(tc);
+    _released_textures.push_back(tc);
   }
 
   _prepared_textures.clear();
@@ -965,7 +937,7 @@ release_vertex_buffer(VertexBufferContext *vbc) {
                             released_vbuffer_cache_size,
                             _released_vertex_buffers);
   } else {
-    _released_vertex_buffers.insert(vbc);
+    _released_vertex_buffers.push_back(vbc);
   }
 }
 
@@ -988,7 +960,7 @@ release_all_vertex_buffers() {
     vbc->get_data()->clear_prepared(this);
     vbc->_object = nullptr;
 
-    _released_vertex_buffers.insert(vbc);
+    _released_vertex_buffers.push_back(vbc);
   }
 
   _prepared_vertex_buffers.clear();
@@ -1004,7 +976,7 @@ release_all_vertex_buffers() {
     BufferList::iterator li;
     for (li = buffer_list.begin(); li != buffer_list.end(); ++li) {
       VertexBufferContext *vbc = (VertexBufferContext *)(*li);
-      _released_vertex_buffers.insert(vbc);
+      _released_vertex_buffers.push_back(vbc);
     }
   }
   _vertex_buffer_cache.clear();
@@ -1163,7 +1135,7 @@ release_index_buffer(IndexBufferContext *ibc) {
                             released_ibuffer_cache_size,
                             _released_index_buffers);
   } else {
-    _released_index_buffers.insert(ibc);
+    _released_index_buffers.push_back(ibc);
   }
 }
 
@@ -1186,7 +1158,7 @@ release_all_index_buffers() {
     ibc->get_data()->clear_prepared(this);
     ibc->_object = nullptr;
 
-    _released_index_buffers.insert(ibc);
+    _released_index_buffers.push_back(ibc);
   }
 
   _prepared_index_buffers.clear();
@@ -1202,7 +1174,7 @@ release_all_index_buffers() {
     BufferList::iterator li;
     for (li = buffer_list.begin(); li != buffer_list.end(); ++li) {
       IndexBufferContext *vbc = (IndexBufferContext *)(*li);
-      _released_index_buffers.insert(vbc);
+      _released_index_buffers.push_back(vbc);
     }
   }
   _index_buffer_cache.clear();
@@ -1351,7 +1323,7 @@ release_shader_buffer(BufferContext *bc) {
   bool removed = (_prepared_shader_buffers.erase(bc) != 0);
   nassertv(removed);
 
-  _released_shader_buffers.insert(bc);
+  _released_shader_buffers.push_back(bc);
 }
 
 /**
@@ -1371,7 +1343,7 @@ release_all_shader_buffers() {
        ++bci) {
 
     BufferContext *bc = (BufferContext *)(*bci);
-    _released_shader_buffers.insert(bc);
+    _released_shader_buffers.push_back(bc);
   }
 
   _prepared_shader_buffers.clear();
@@ -1512,68 +1484,45 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
 
   // First, release all the textures, geoms, and buffers awaiting release.
   if (!_released_textures.empty()) {
-    Textures::iterator tci;
-    for (tci = _released_textures.begin();
-         tci != _released_textures.end();
-         ++tci) {
-      TextureContext *tc = (*tci);
-      gsg->release_texture(tc);
-    }
-
+    gsg->release_textures(_released_textures);
     _released_textures.clear();
   }
 
   if (!_released_samplers.empty()) {
-    ReleasedSamplers::iterator sci;
-    for (sci = _released_samplers.begin();
-         sci != _released_samplers.end();
-         ++sci) {
-      SamplerContext *sc = (*sci);
+    for (SamplerContext *sc : _released_samplers) {
       gsg->release_sampler(sc);
     }
-
     _released_samplers.clear();
   }
 
-  Geoms::iterator gci;
-  for (gci = _released_geoms.begin();
-       gci != _released_geoms.end();
-       ++gci) {
-    GeomContext *gc = (*gci);
-    gsg->release_geom(gc);
+  if (!_released_geoms.empty()) {
+    for (GeomContext *gc : _released_geoms) {
+      gsg->release_geom(gc);
+    }
+    _released_geoms.clear();
   }
 
-  _released_geoms.clear();
-
-  Shaders::iterator sci;
-  for (sci = _released_shaders.begin();
-       sci != _released_shaders.end();
-       ++sci) {
-    ShaderContext *sc = (*sci);
-    gsg->release_shader(sc);
+  if (!_released_shaders.empty()) {
+    for (ShaderContext *sc : _released_shaders) {
+      gsg->release_shader(sc);
+    }
+    _released_shaders.clear();
   }
 
-  _released_shaders.clear();
-
-  Buffers::iterator vbci;
-  for (vbci = _released_vertex_buffers.begin();
-       vbci != _released_vertex_buffers.end();
-       ++vbci) {
-    VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
-    gsg->release_vertex_buffer(vbc);
+  if (!_released_vertex_buffers.empty()) {
+    gsg->release_vertex_buffers(_released_vertex_buffers);
+    _released_vertex_buffers.clear();
   }
 
-  _released_vertex_buffers.clear();
-
-  Buffers::iterator ibci;
-  for (ibci = _released_index_buffers.begin();
-       ibci != _released_index_buffers.end();
-       ++ibci) {
-    IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
-    gsg->release_index_buffer(ibc);
+  if (!_released_index_buffers.empty()) {
+    gsg->release_index_buffers(_released_index_buffers);
+    _released_index_buffers.clear();
   }
 
-  _released_index_buffers.clear();
+  if (!_released_shader_buffers.empty()) {
+    gsg->release_shader_buffers(_released_shader_buffers);
+    _released_shader_buffers.clear();
+  }
 
   // Reset the residency trackers.
   _texture_residency.begin_frame(current_thread);
@@ -1697,7 +1646,7 @@ cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes,
                         PreparedGraphicsObjects::BufferCacheLRU &buffer_cache_lru,
                         size_t &buffer_cache_size,
                         int released_buffer_cache_size,
-                        PreparedGraphicsObjects::Buffers &released_buffers) {
+                        pvector<BufferContext *> &released_buffers) {
   BufferCacheKey key;
   key._data_size_bytes = data_size_bytes;
   key._usage_hint = usage_hint;
@@ -1723,7 +1672,10 @@ cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes,
            (int)buffer_cache_size > released_buffer_cache_size) {
       BufferContext *released_buffer = buffer_list.back();
       buffer_list.pop_back();
-      released_buffers.insert(released_buffer);
+      if (released_buffer->_object != nullptr) {
+        released_buffer->_object = nullptr;
+        released_buffers.push_back(released_buffer);
+      }
       buffer_cache_size -= release_key._data_size_bytes;
     }
 

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

@@ -253,7 +253,7 @@ private:
                                BufferCacheLRU &buffer_cache_lru,
                                size_t &buffer_cache_size,
                                int released_buffer_cache_size,
-                               Buffers &released_buffers);
+                               pvector<BufferContext *> &released_buffers);
   BufferContext *get_cached_buffer(size_t data_size_bytes,
                                    GeomEnums::UsageHint usage_hint,
                                    BufferCache &buffer_cache,
@@ -262,7 +262,8 @@ private:
 
   ReMutex _lock;
   std::string _name;
-  Textures _prepared_textures, _released_textures;
+  Textures _prepared_textures;
+  pvector<TextureContext *> _released_textures;
   EnqueuedTextures _enqueued_textures;
   PreparedSamplers _prepared_samplers;
   ReleasedSamplers _released_samplers;
@@ -271,11 +272,14 @@ private:
   EnqueuedGeoms _enqueued_geoms;
   Shaders _prepared_shaders, _released_shaders;
   EnqueuedShaders _enqueued_shaders;
-  Buffers _prepared_vertex_buffers, _released_vertex_buffers;
+  Buffers _prepared_vertex_buffers;
+  pvector<BufferContext *> _released_vertex_buffers;
   EnqueuedVertexBuffers _enqueued_vertex_buffers;
-  Buffers _prepared_index_buffers, _released_index_buffers;
+  Buffers _prepared_index_buffers;
+  pvector<BufferContext *> _released_index_buffers;
   EnqueuedIndexBuffers _enqueued_index_buffers;
-  Buffers _prepared_shader_buffers, _released_shader_buffers;
+  Buffers _prepared_shader_buffers;
+  pvector<BufferContext *> _released_shader_buffers;
   EnqueuedShaderBuffers _enqueued_shader_buffers;
 
   BufferCache _vertex_buffer_cache;

+ 4 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -147,6 +147,7 @@ public:
   virtual TextureContext *prepare_texture(Texture *tex, int view)=0;
   virtual bool update_texture(TextureContext *tc, bool force)=0;
   virtual void release_texture(TextureContext *tc)=0;
+  virtual void release_textures(const pvector<TextureContext *> &contexts)=0;
   virtual bool extract_texture_data(Texture *tex)=0;
 
   virtual SamplerContext *prepare_sampler(const SamplerState &sampler)=0;
@@ -160,12 +161,15 @@ public:
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data)=0;
   virtual void release_vertex_buffer(VertexBufferContext *vbc)=0;
+  virtual void release_vertex_buffers(const pvector<BufferContext *> &contexts)=0;
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data)=0;
   virtual void release_index_buffer(IndexBufferContext *ibc)=0;
+  virtual void release_index_buffers(const pvector<BufferContext *> &contexts)=0;
 
   virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data)=0;
   virtual void release_shader_buffer(BufferContext *ibc)=0;
+  virtual void release_shader_buffers(const pvector<BufferContext *> &contexts)=0;
 
   virtual void dispatch_compute(int size_x, int size_y, int size_z)=0;