diff --git a/panda/src/glstuff/glBufferContext_src.I b/panda/src/glstuff/glBufferContext_src.I index bec8283a18..56ecf2102a 100644 --- a/panda/src/glstuff/glBufferContext_src.I +++ b/panda/src/glstuff/glBufferContext_src.I @@ -16,8 +16,9 @@ */ INLINE CLP(BufferContext):: CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg, - PreparedGraphicsObjects *pgo) : - BufferContext(&pgo->_sbuffer_residency), + PreparedGraphicsObjects *pgo, + TypedWritableReferenceCount *object) : + BufferContext(&pgo->_sbuffer_residency, object), AdaptiveLruPage(0), _glgsg(glgsg) { diff --git a/panda/src/glstuff/glBufferContext_src.h b/panda/src/glstuff/glBufferContext_src.h index b6c46aab76..b67a9d214e 100644 --- a/panda/src/glstuff/glBufferContext_src.h +++ b/panda/src/glstuff/glBufferContext_src.h @@ -21,7 +21,8 @@ class EXPCL_GL CLP(BufferContext) : public BufferContext, public AdaptiveLruPage { public: INLINE CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg, - PreparedGraphicsObjects *pgo); + PreparedGraphicsObjects *pgo, + TypedWritableReferenceCount *object); ALLOC_DELETED_CHAIN(CLP(BufferContext)); virtual void evict_lru(); diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 8fbba8f79d..ebb038de7a 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1413,7 +1413,7 @@ open_buffer() { } if (_rb_context == nullptr) { - _rb_context = new BufferContext(&(glgsg->_renderbuffer_residency)); + _rb_context = new BufferContext(&(glgsg->_renderbuffer_residency), nullptr); } /* diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index df2095284c..1e6d1781cc 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -6519,7 +6519,7 @@ prepare_shader_buffer(ShaderBuffer *data) { if (_supports_shader_buffers) { PStatGPUTimer timer(this, _prepare_shader_buffer_pcollector); - CLP(BufferContext) *gbc = new CLP(BufferContext)(this, _prepared_objects); + CLP(BufferContext) *gbc = new CLP(BufferContext)(this, _prepared_objects, data); _glGenBuffers(1, &gbc->_index); if (GLCAT.is_debug() && gl_debug_buffers) { diff --git a/panda/src/gobj/bufferContext.I b/panda/src/gobj/bufferContext.I index 3c34d93a8a..6d564cef02 100644 --- a/panda/src/gobj/bufferContext.I +++ b/panda/src/gobj/bufferContext.I @@ -11,6 +11,14 @@ * @date 2006-03-16 */ +/** + * Returns the associated object. + */ +INLINE TypedWritableReferenceCount *BufferContext:: +get_object() const { + return _object; +} + /** * Returns the number of bytes previously reported for the data object. This * is used to track changes in the data object's allocated size; if it changes diff --git a/panda/src/gobj/bufferContext.cxx b/panda/src/gobj/bufferContext.cxx index 52cac06ce4..b268400d35 100644 --- a/panda/src/gobj/bufferContext.cxx +++ b/panda/src/gobj/bufferContext.cxx @@ -19,7 +19,8 @@ TypeHandle BufferContext::_type_handle; * */ BufferContext:: -BufferContext(BufferResidencyTracker *residency) : +BufferContext(BufferResidencyTracker *residency, TypedWritableReferenceCount *object) : + _object(object), _residency(residency), _residency_state(0), _data_size_bytes(0), diff --git a/panda/src/gobj/bufferContext.h b/panda/src/gobj/bufferContext.h index dedf5411e9..60c9ab3333 100644 --- a/panda/src/gobj/bufferContext.h +++ b/panda/src/gobj/bufferContext.h @@ -23,6 +23,7 @@ #include "bufferResidencyTracker.h" class PreparedGraphicsObjects; +class TypedWritableReferenceCount; /** * This is a base class for those kinds of SavedContexts that occupy an @@ -36,15 +37,19 @@ class PreparedGraphicsObjects; */ class EXPCL_PANDA_GOBJ BufferContext : public SavedContext, private LinkedListNode { public: - BufferContext(BufferResidencyTracker *residency); + BufferContext(BufferResidencyTracker *residency, TypedWritableReferenceCount *object); virtual ~BufferContext(); + INLINE TypedWritableReferenceCount *get_object() const; + PUBLISHED: INLINE size_t get_data_size_bytes() const; INLINE UpdateSeq get_modified() const; INLINE bool get_active() const; INLINE bool get_resident() const; + MAKE_PROPERTY(object, get_object); + MAKE_PROPERTY(data_size_bytes, get_data_size_bytes); MAKE_PROPERTY(modified, get_modified); MAKE_PROPERTY(active, get_active); @@ -62,6 +67,11 @@ public: private: void set_owning_chain(BufferContextChain *chain); +protected: + // This cannot be a PT(), because the object and the GSG both own their + // BufferContexts! That would create a circular reference count. + TypedWritableReferenceCount *_object; + private: BufferResidencyTracker *_residency; int _residency_state; diff --git a/panda/src/gobj/indexBufferContext.I b/panda/src/gobj/indexBufferContext.I index caf5e7f34a..e55304bfcb 100644 --- a/panda/src/gobj/indexBufferContext.I +++ b/panda/src/gobj/indexBufferContext.I @@ -16,9 +16,8 @@ */ INLINE IndexBufferContext:: IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) : - BufferContext(&pgo->_ibuffer_residency), - AdaptiveLruPage(0), - _data(data) + BufferContext(&pgo->_ibuffer_residency, data), + AdaptiveLruPage(0) { } @@ -27,7 +26,7 @@ IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) : */ INLINE GeomPrimitive *IndexBufferContext:: get_data() const { - return _data; + return (GeomPrimitive *)_object; } /** @@ -36,7 +35,7 @@ get_data() const { */ INLINE bool IndexBufferContext:: changed_size(const GeomPrimitivePipelineReader *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return get_data_size_bytes() != (size_t)reader->get_data_size_bytes(); } @@ -46,7 +45,7 @@ changed_size(const GeomPrimitivePipelineReader *reader) const { */ INLINE bool IndexBufferContext:: changed_usage_hint(const GeomPrimitivePipelineReader *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return _usage_hint != reader->get_usage_hint(); } @@ -56,7 +55,7 @@ changed_usage_hint(const GeomPrimitivePipelineReader *reader) const { */ INLINE bool IndexBufferContext:: was_modified(const GeomPrimitivePipelineReader *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return get_modified() != reader->get_modified(); } @@ -76,7 +75,7 @@ update_data_size_bytes(size_t new_data_size_bytes) { */ INLINE void IndexBufferContext:: mark_loaded(const GeomPrimitivePipelineReader *reader) { - nassertv(reader->get_object() == _data); + nassertv(reader->get_object() == get_data()); update_data_size_bytes(reader->get_data_size_bytes()); update_modified(reader->get_modified()); _usage_hint = reader->get_usage_hint(); diff --git a/panda/src/gobj/indexBufferContext.h b/panda/src/gobj/indexBufferContext.h index 6b2004fac2..139ab69362 100644 --- a/panda/src/gobj/indexBufferContext.h +++ b/panda/src/gobj/indexBufferContext.h @@ -50,9 +50,6 @@ public: virtual void write(std::ostream &out, int indent_level) const; private: - // This cannot be a PT(GeomPrimitive), because the data and the GSG both own - // their IndexBufferContexts! That would create a circular reference count. - GeomPrimitive *_data; GeomEnums::UsageHint _usage_hint; public: diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 96fcd80269..e3ab0e8d83 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -270,11 +270,11 @@ void PreparedGraphicsObjects:: release_texture(TextureContext *tc) { ReMutexHolder holder(_lock); - tc->_texture->clear_prepared(tc->get_view(), this); + tc->get_texture()->clear_prepared(tc->get_view(), this); // We have to set the Texture pointer to NULL at this point, since the // Texture itself might destruct at any time after it has been released. - tc->_texture = nullptr; + tc->_object = nullptr; bool removed = (_prepared_textures.erase(tc) != 0); nassertv(removed); @@ -307,8 +307,8 @@ release_all_textures() { tci != _prepared_textures.end(); ++tci) { TextureContext *tc = (*tci); - tc->_texture->clear_prepared(tc->get_view(), this); - tc->_texture = nullptr; + tc->get_texture()->clear_prepared(tc->get_view(), this); + tc->_object = nullptr; _released_textures.insert(tc); } @@ -946,14 +946,14 @@ void PreparedGraphicsObjects:: release_vertex_buffer(VertexBufferContext *vbc) { ReMutexHolder holder(_lock); - vbc->_data->clear_prepared(this); + vbc->get_data()->clear_prepared(this); - size_t data_size_bytes = vbc->_data->get_data_size_bytes(); - GeomEnums::UsageHint usage_hint = vbc->_data->get_usage_hint(); + size_t data_size_bytes = vbc->get_data()->get_data_size_bytes(); + GeomEnums::UsageHint usage_hint = vbc->get_data()->get_usage_hint(); // We have to set the Data pointer to NULL at this point, since the Data // itself might destruct at any time after it has been released. - vbc->_data = nullptr; + vbc->_object = nullptr; bool removed = (_prepared_vertex_buffers.erase(vbc) != 0); nassertv(removed); @@ -985,8 +985,8 @@ release_all_vertex_buffers() { vbci != _prepared_vertex_buffers.end(); ++vbci) { VertexBufferContext *vbc = (VertexBufferContext *)(*vbci); - vbc->_data->clear_prepared(this); - vbc->_data = nullptr; + vbc->get_data()->clear_prepared(this); + vbc->_object = nullptr; _released_vertex_buffers.insert(vbc); } @@ -1061,7 +1061,7 @@ prepare_vertex_buffer_now(GeomVertexArrayData *data, GraphicsStateGuardianBase * _vertex_buffer_cache, _vertex_buffer_cache_lru, _vertex_buffer_cache_size); if (vbc != nullptr) { - vbc->_data = data; + vbc->_object = data; } else { // Ask the GSG to create a brand new VertexBufferContext. There might be @@ -1144,14 +1144,14 @@ void PreparedGraphicsObjects:: release_index_buffer(IndexBufferContext *ibc) { ReMutexHolder holder(_lock); - ibc->_data->clear_prepared(this); + ibc->get_data()->clear_prepared(this); - size_t data_size_bytes = ibc->_data->get_data_size_bytes(); - GeomEnums::UsageHint usage_hint = ibc->_data->get_usage_hint(); + size_t data_size_bytes = ibc->get_data()->get_data_size_bytes(); + GeomEnums::UsageHint usage_hint = ibc->get_data()->get_usage_hint(); // We have to set the Data pointer to NULL at this point, since the Data // itself might destruct at any time after it has been released. - ibc->_data = nullptr; + ibc->_object = nullptr; bool removed = (_prepared_index_buffers.erase(ibc) != 0); nassertv(removed); @@ -1183,8 +1183,8 @@ release_all_index_buffers() { ibci != _prepared_index_buffers.end(); ++ibci) { IndexBufferContext *ibc = (IndexBufferContext *)(*ibci); - ibc->_data->clear_prepared(this); - ibc->_data = nullptr; + ibc->get_data()->clear_prepared(this); + ibc->_object = nullptr; _released_index_buffers.insert(ibc); } @@ -1258,7 +1258,7 @@ prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) { _index_buffer_cache, _index_buffer_cache_lru, _index_buffer_cache_size); if (ibc != nullptr) { - ibc->_data = data; + ibc->_object = data; } else { // Ask the GSG to create a brand new IndexBufferContext. There might be @@ -1341,6 +1341,13 @@ void PreparedGraphicsObjects:: release_shader_buffer(BufferContext *bc) { ReMutexHolder holder(_lock); + ShaderBuffer *buffer = (ShaderBuffer *)bc->_object; + buffer->clear_prepared(this); + + // We have to set the ShaderBuffer pointer to NULL at this point, since the + // buffer itself might destruct at any time after it has been released. + bc->_object = nullptr; + bool removed = (_prepared_shader_buffers.erase(bc) != 0); nassertv(removed); diff --git a/panda/src/gobj/shaderBuffer.cxx b/panda/src/gobj/shaderBuffer.cxx index 4e21319b49..fa16293d4d 100644 --- a/panda/src/gobj/shaderBuffer.cxx +++ b/panda/src/gobj/shaderBuffer.cxx @@ -143,6 +143,31 @@ release_all() { return num_freed; } +/** + * Removes the indicated PreparedGraphicsObjects table from the buffer's + * table, without actually releasing the texture. This is intended to be + * called only from PreparedGraphicsObjects::release_shader_buffer(); it + * should never be called by user code. + */ +void ShaderBuffer:: +clear_prepared(PreparedGraphicsObjects *prepared_objects) { + nassertv(_contexts != nullptr); + + Contexts::iterator ci; + ci = _contexts->find(prepared_objects); + if (ci != _contexts->end()) { + _contexts->erase(ci); + if (_contexts->empty()) { + delete _contexts; + _contexts = nullptr; + } + } else { + // If this assertion fails, clear_prepared() was given a prepared_objects + // which the data array didn't know about. + nassert_raise("unknown PreparedGraphicsObjects"); + } +} + /** * Tells the BamReader how to create objects of type ParamValue. */ diff --git a/panda/src/gobj/shaderBuffer.h b/panda/src/gobj/shaderBuffer.h index bdf0538857..0cc0660433 100644 --- a/panda/src/gobj/shaderBuffer.h +++ b/panda/src/gobj/shaderBuffer.h @@ -57,6 +57,9 @@ PUBLISHED: bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); +private: + void clear_prepared(PreparedGraphicsObjects *prepared_objects); + private: uint64_t _data_size_bytes; UsageHint _usage_hint; @@ -91,6 +94,8 @@ public: private: static TypeHandle _type_handle; + + friend class PreparedGraphicsObjects; }; INLINE std::ostream &operator << (std::ostream &out, const ShaderBuffer &m) { diff --git a/panda/src/gobj/textureContext.I b/panda/src/gobj/textureContext.I index fa947755d0..2c58bc7b07 100644 --- a/panda/src/gobj/textureContext.I +++ b/panda/src/gobj/textureContext.I @@ -16,9 +16,8 @@ */ INLINE TextureContext:: TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) : - BufferContext(&pgo->_texture_residency), + BufferContext(&pgo->_texture_residency, tex), AdaptiveLruPage(0), - _texture(tex), _view(view) { } @@ -28,7 +27,7 @@ TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) : */ INLINE Texture *TextureContext:: get_texture() const { - return _texture; + return (Texture *)_object; } /** @@ -56,7 +55,7 @@ was_modified() const { */ INLINE bool TextureContext:: was_properties_modified() const { - return _properties_modified != _texture->get_properties_modified(); + return _properties_modified != get_texture()->get_properties_modified(); } /** @@ -65,7 +64,7 @@ was_properties_modified() const { */ INLINE bool TextureContext:: was_image_modified() const { - return _image_modified != _texture->get_image_modified(); + return _image_modified != get_texture()->get_image_modified(); } /** @@ -74,7 +73,7 @@ was_image_modified() const { */ INLINE bool TextureContext:: was_simple_image_modified() const { - return _simple_image_modified != _texture->get_simple_image_modified(); + return _simple_image_modified != get_texture()->get_simple_image_modified(); } /** @@ -121,8 +120,8 @@ update_data_size_bytes(size_t new_data_size_bytes) { INLINE void TextureContext:: mark_loaded() { // _data_size_bytes = _data->get_texture_size_bytes(); - _properties_modified = _texture->get_properties_modified(); - _image_modified = _texture->get_image_modified(); + _properties_modified = get_texture()->get_properties_modified(); + _image_modified = get_texture()->get_image_modified(); update_modified(std::max(_properties_modified, _image_modified)); // Assume the texture is now resident. @@ -135,8 +134,8 @@ mark_loaded() { */ INLINE void TextureContext:: mark_simple_loaded() { - _properties_modified = _texture->get_properties_modified(); - _simple_image_modified = _texture->get_simple_image_modified(); + _properties_modified = get_texture()->get_properties_modified(); + _simple_image_modified = get_texture()->get_simple_image_modified(); update_modified(std::max(_properties_modified, _simple_image_modified)); // The texture's not exactly resident now, but some part of it is. diff --git a/panda/src/gobj/textureContext.h b/panda/src/gobj/textureContext.h index c7ae367ccc..2962fd38c0 100644 --- a/panda/src/gobj/textureContext.h +++ b/panda/src/gobj/textureContext.h @@ -60,9 +60,6 @@ public: virtual void write(std::ostream &out, int indent_level) const; private: - // This cannot be a PT(Texture), because the texture and the GSG both own - // their TextureContexts! That would create a circular reference count. - Texture *_texture; int _view; UpdateSeq _properties_modified; UpdateSeq _image_modified; diff --git a/panda/src/gobj/vertexBufferContext.I b/panda/src/gobj/vertexBufferContext.I index b57739cf09..bbfff0bb27 100644 --- a/panda/src/gobj/vertexBufferContext.I +++ b/panda/src/gobj/vertexBufferContext.I @@ -16,9 +16,8 @@ */ INLINE VertexBufferContext:: VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) : - BufferContext(&pgo->_vbuffer_residency), - AdaptiveLruPage(0), - _data(data) + BufferContext(&pgo->_vbuffer_residency, data), + AdaptiveLruPage(0) { } @@ -27,7 +26,7 @@ VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) : */ INLINE GeomVertexArrayData *VertexBufferContext:: get_data() const { - return _data; + return (GeomVertexArrayData *)_object; } /** @@ -36,7 +35,7 @@ get_data() const { */ INLINE bool VertexBufferContext:: changed_size(const GeomVertexArrayDataHandle *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return get_data_size_bytes() != (size_t)reader->get_data_size_bytes(); } @@ -46,7 +45,7 @@ changed_size(const GeomVertexArrayDataHandle *reader) const { */ INLINE bool VertexBufferContext:: changed_usage_hint(const GeomVertexArrayDataHandle *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return _usage_hint != reader->get_usage_hint(); } @@ -56,7 +55,7 @@ changed_usage_hint(const GeomVertexArrayDataHandle *reader) const { */ INLINE bool VertexBufferContext:: was_modified(const GeomVertexArrayDataHandle *reader) const { - nassertr(reader->get_object() == _data, false); + nassertr(reader->get_object() == get_data(), false); return get_modified() != reader->get_modified(); } @@ -77,7 +76,7 @@ update_data_size_bytes(size_t new_data_size_bytes) { */ INLINE void VertexBufferContext:: mark_loaded(const GeomVertexArrayDataHandle *reader) { - nassertv(reader->get_object() == _data); + nassertv(reader->get_object() == get_data()); update_data_size_bytes(reader->get_data_size_bytes()); update_modified(reader->get_modified()); _usage_hint = reader->get_usage_hint(); diff --git a/panda/src/gobj/vertexBufferContext.h b/panda/src/gobj/vertexBufferContext.h index 69f02e0ed7..c1696ba6cb 100644 --- a/panda/src/gobj/vertexBufferContext.h +++ b/panda/src/gobj/vertexBufferContext.h @@ -51,10 +51,6 @@ public: virtual void write(std::ostream &out, int indent_level) const; private: - // This cannot be a PT(GeomVertexArrayData), because the data and the GSG - // both own their VertexBufferContexts! That would create a circular - // reference count. - GeomVertexArrayData *_data; GeomEnums::UsageHint _usage_hint; public: