Fix ShaderBuffer cleanup assertion with state cache disabled

This commit is contained in:
rdb 2018-12-26 22:44:26 +01:00
parent a9d6d3be46
commit 669a655366
16 changed files with 106 additions and 61 deletions

View File

@ -16,8 +16,9 @@
*/ */
INLINE CLP(BufferContext):: INLINE CLP(BufferContext)::
CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg, CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo) : PreparedGraphicsObjects *pgo,
BufferContext(&pgo->_sbuffer_residency), TypedWritableReferenceCount *object) :
BufferContext(&pgo->_sbuffer_residency, object),
AdaptiveLruPage(0), AdaptiveLruPage(0),
_glgsg(glgsg) _glgsg(glgsg)
{ {

View File

@ -21,7 +21,8 @@
class EXPCL_GL CLP(BufferContext) : public BufferContext, public AdaptiveLruPage { class EXPCL_GL CLP(BufferContext) : public BufferContext, public AdaptiveLruPage {
public: public:
INLINE CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg, INLINE CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo); PreparedGraphicsObjects *pgo,
TypedWritableReferenceCount *object);
ALLOC_DELETED_CHAIN(CLP(BufferContext)); ALLOC_DELETED_CHAIN(CLP(BufferContext));
virtual void evict_lru(); virtual void evict_lru();

View File

@ -1413,7 +1413,7 @@ open_buffer() {
} }
if (_rb_context == nullptr) { if (_rb_context == nullptr) {
_rb_context = new BufferContext(&(glgsg->_renderbuffer_residency)); _rb_context = new BufferContext(&(glgsg->_renderbuffer_residency), nullptr);
} }
/* /*

View File

@ -6519,7 +6519,7 @@ prepare_shader_buffer(ShaderBuffer *data) {
if (_supports_shader_buffers) { if (_supports_shader_buffers) {
PStatGPUTimer timer(this, _prepare_shader_buffer_pcollector); 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); _glGenBuffers(1, &gbc->_index);
if (GLCAT.is_debug() && gl_debug_buffers) { if (GLCAT.is_debug() && gl_debug_buffers) {

View File

@ -11,6 +11,14 @@
* @date 2006-03-16 * @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 * 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 * is used to track changes in the data object's allocated size; if it changes

View File

@ -19,7 +19,8 @@ TypeHandle BufferContext::_type_handle;
* *
*/ */
BufferContext:: BufferContext::
BufferContext(BufferResidencyTracker *residency) : BufferContext(BufferResidencyTracker *residency, TypedWritableReferenceCount *object) :
_object(object),
_residency(residency), _residency(residency),
_residency_state(0), _residency_state(0),
_data_size_bytes(0), _data_size_bytes(0),

View File

@ -23,6 +23,7 @@
#include "bufferResidencyTracker.h" #include "bufferResidencyTracker.h"
class PreparedGraphicsObjects; class PreparedGraphicsObjects;
class TypedWritableReferenceCount;
/** /**
* This is a base class for those kinds of SavedContexts that occupy an * 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 { class EXPCL_PANDA_GOBJ BufferContext : public SavedContext, private LinkedListNode {
public: public:
BufferContext(BufferResidencyTracker *residency); BufferContext(BufferResidencyTracker *residency, TypedWritableReferenceCount *object);
virtual ~BufferContext(); virtual ~BufferContext();
INLINE TypedWritableReferenceCount *get_object() const;
PUBLISHED: PUBLISHED:
INLINE size_t get_data_size_bytes() const; INLINE size_t get_data_size_bytes() const;
INLINE UpdateSeq get_modified() const; INLINE UpdateSeq get_modified() const;
INLINE bool get_active() const; INLINE bool get_active() const;
INLINE bool get_resident() const; INLINE bool get_resident() const;
MAKE_PROPERTY(object, get_object);
MAKE_PROPERTY(data_size_bytes, get_data_size_bytes); MAKE_PROPERTY(data_size_bytes, get_data_size_bytes);
MAKE_PROPERTY(modified, get_modified); MAKE_PROPERTY(modified, get_modified);
MAKE_PROPERTY(active, get_active); MAKE_PROPERTY(active, get_active);
@ -62,6 +67,11 @@ public:
private: private:
void set_owning_chain(BufferContextChain *chain); 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: private:
BufferResidencyTracker *_residency; BufferResidencyTracker *_residency;
int _residency_state; int _residency_state;

View File

@ -16,9 +16,8 @@
*/ */
INLINE IndexBufferContext:: INLINE IndexBufferContext::
IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) : IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
BufferContext(&pgo->_ibuffer_residency), BufferContext(&pgo->_ibuffer_residency, data),
AdaptiveLruPage(0), AdaptiveLruPage(0)
_data(data)
{ {
} }
@ -27,7 +26,7 @@ IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
*/ */
INLINE GeomPrimitive *IndexBufferContext:: INLINE GeomPrimitive *IndexBufferContext::
get_data() const { get_data() const {
return _data; return (GeomPrimitive *)_object;
} }
/** /**
@ -36,7 +35,7 @@ get_data() const {
*/ */
INLINE bool IndexBufferContext:: INLINE bool IndexBufferContext::
changed_size(const GeomPrimitivePipelineReader *reader) const { 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(); 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:: INLINE bool IndexBufferContext::
changed_usage_hint(const GeomPrimitivePipelineReader *reader) const { 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(); return _usage_hint != reader->get_usage_hint();
} }
@ -56,7 +55,7 @@ changed_usage_hint(const GeomPrimitivePipelineReader *reader) const {
*/ */
INLINE bool IndexBufferContext:: INLINE bool IndexBufferContext::
was_modified(const GeomPrimitivePipelineReader *reader) const { 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(); return get_modified() != reader->get_modified();
} }
@ -76,7 +75,7 @@ update_data_size_bytes(size_t new_data_size_bytes) {
*/ */
INLINE void IndexBufferContext:: INLINE void IndexBufferContext::
mark_loaded(const GeomPrimitivePipelineReader *reader) { 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_data_size_bytes(reader->get_data_size_bytes());
update_modified(reader->get_modified()); update_modified(reader->get_modified());
_usage_hint = reader->get_usage_hint(); _usage_hint = reader->get_usage_hint();

View File

@ -50,9 +50,6 @@ public:
virtual void write(std::ostream &out, int indent_level) const; virtual void write(std::ostream &out, int indent_level) const;
private: 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; GeomEnums::UsageHint _usage_hint;
public: public:

View File

@ -270,11 +270,11 @@ void PreparedGraphicsObjects::
release_texture(TextureContext *tc) { release_texture(TextureContext *tc) {
ReMutexHolder holder(_lock); 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 // 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. // 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); bool removed = (_prepared_textures.erase(tc) != 0);
nassertv(removed); nassertv(removed);
@ -307,8 +307,8 @@ release_all_textures() {
tci != _prepared_textures.end(); tci != _prepared_textures.end();
++tci) { ++tci) {
TextureContext *tc = (*tci); TextureContext *tc = (*tci);
tc->_texture->clear_prepared(tc->get_view(), this); tc->get_texture()->clear_prepared(tc->get_view(), this);
tc->_texture = nullptr; tc->_object = nullptr;
_released_textures.insert(tc); _released_textures.insert(tc);
} }
@ -946,14 +946,14 @@ void PreparedGraphicsObjects::
release_vertex_buffer(VertexBufferContext *vbc) { release_vertex_buffer(VertexBufferContext *vbc) {
ReMutexHolder holder(_lock); 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(); size_t data_size_bytes = vbc->get_data()->get_data_size_bytes();
GeomEnums::UsageHint usage_hint = vbc->_data->get_usage_hint(); 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 // 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. // 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); bool removed = (_prepared_vertex_buffers.erase(vbc) != 0);
nassertv(removed); nassertv(removed);
@ -985,8 +985,8 @@ release_all_vertex_buffers() {
vbci != _prepared_vertex_buffers.end(); vbci != _prepared_vertex_buffers.end();
++vbci) { ++vbci) {
VertexBufferContext *vbc = (VertexBufferContext *)(*vbci); VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
vbc->_data->clear_prepared(this); vbc->get_data()->clear_prepared(this);
vbc->_data = nullptr; vbc->_object = nullptr;
_released_vertex_buffers.insert(vbc); _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, _vertex_buffer_cache_lru,
_vertex_buffer_cache_size); _vertex_buffer_cache_size);
if (vbc != nullptr) { if (vbc != nullptr) {
vbc->_data = data; vbc->_object = data;
} else { } else {
// Ask the GSG to create a brand new VertexBufferContext. There might be // Ask the GSG to create a brand new VertexBufferContext. There might be
@ -1144,14 +1144,14 @@ void PreparedGraphicsObjects::
release_index_buffer(IndexBufferContext *ibc) { release_index_buffer(IndexBufferContext *ibc) {
ReMutexHolder holder(_lock); 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(); size_t data_size_bytes = ibc->get_data()->get_data_size_bytes();
GeomEnums::UsageHint usage_hint = ibc->_data->get_usage_hint(); 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 // 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. // 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); bool removed = (_prepared_index_buffers.erase(ibc) != 0);
nassertv(removed); nassertv(removed);
@ -1183,8 +1183,8 @@ release_all_index_buffers() {
ibci != _prepared_index_buffers.end(); ibci != _prepared_index_buffers.end();
++ibci) { ++ibci) {
IndexBufferContext *ibc = (IndexBufferContext *)(*ibci); IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
ibc->_data->clear_prepared(this); ibc->get_data()->clear_prepared(this);
ibc->_data = nullptr; ibc->_object = nullptr;
_released_index_buffers.insert(ibc); _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, _index_buffer_cache_lru,
_index_buffer_cache_size); _index_buffer_cache_size);
if (ibc != nullptr) { if (ibc != nullptr) {
ibc->_data = data; ibc->_object = data;
} else { } else {
// Ask the GSG to create a brand new IndexBufferContext. There might be // Ask the GSG to create a brand new IndexBufferContext. There might be
@ -1341,6 +1341,13 @@ void PreparedGraphicsObjects::
release_shader_buffer(BufferContext *bc) { release_shader_buffer(BufferContext *bc) {
ReMutexHolder holder(_lock); 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); bool removed = (_prepared_shader_buffers.erase(bc) != 0);
nassertv(removed); nassertv(removed);

View File

@ -143,6 +143,31 @@ release_all() {
return num_freed; 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. * Tells the BamReader how to create objects of type ParamValue.
*/ */

View File

@ -57,6 +57,9 @@ PUBLISHED:
bool release(PreparedGraphicsObjects *prepared_objects); bool release(PreparedGraphicsObjects *prepared_objects);
int release_all(); int release_all();
private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
private: private:
uint64_t _data_size_bytes; uint64_t _data_size_bytes;
UsageHint _usage_hint; UsageHint _usage_hint;
@ -91,6 +94,8 @@ public:
private: private:
static TypeHandle _type_handle; static TypeHandle _type_handle;
friend class PreparedGraphicsObjects;
}; };
INLINE std::ostream &operator << (std::ostream &out, const ShaderBuffer &m) { INLINE std::ostream &operator << (std::ostream &out, const ShaderBuffer &m) {

View File

@ -16,9 +16,8 @@
*/ */
INLINE TextureContext:: INLINE TextureContext::
TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) : TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
BufferContext(&pgo->_texture_residency), BufferContext(&pgo->_texture_residency, tex),
AdaptiveLruPage(0), AdaptiveLruPage(0),
_texture(tex),
_view(view) _view(view)
{ {
} }
@ -28,7 +27,7 @@ TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
*/ */
INLINE Texture *TextureContext:: INLINE Texture *TextureContext::
get_texture() const { get_texture() const {
return _texture; return (Texture *)_object;
} }
/** /**
@ -56,7 +55,7 @@ was_modified() const {
*/ */
INLINE bool TextureContext:: INLINE bool TextureContext::
was_properties_modified() const { 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:: INLINE bool TextureContext::
was_image_modified() const { 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:: INLINE bool TextureContext::
was_simple_image_modified() const { 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:: INLINE void TextureContext::
mark_loaded() { mark_loaded() {
// _data_size_bytes = _data->get_texture_size_bytes(); // _data_size_bytes = _data->get_texture_size_bytes();
_properties_modified = _texture->get_properties_modified(); _properties_modified = get_texture()->get_properties_modified();
_image_modified = _texture->get_image_modified(); _image_modified = get_texture()->get_image_modified();
update_modified(std::max(_properties_modified, _image_modified)); update_modified(std::max(_properties_modified, _image_modified));
// Assume the texture is now resident. // Assume the texture is now resident.
@ -135,8 +134,8 @@ mark_loaded() {
*/ */
INLINE void TextureContext:: INLINE void TextureContext::
mark_simple_loaded() { mark_simple_loaded() {
_properties_modified = _texture->get_properties_modified(); _properties_modified = get_texture()->get_properties_modified();
_simple_image_modified = _texture->get_simple_image_modified(); _simple_image_modified = get_texture()->get_simple_image_modified();
update_modified(std::max(_properties_modified, _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. // The texture's not exactly resident now, but some part of it is.

View File

@ -60,9 +60,6 @@ public:
virtual void write(std::ostream &out, int indent_level) const; virtual void write(std::ostream &out, int indent_level) const;
private: 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; int _view;
UpdateSeq _properties_modified; UpdateSeq _properties_modified;
UpdateSeq _image_modified; UpdateSeq _image_modified;

View File

@ -16,9 +16,8 @@
*/ */
INLINE VertexBufferContext:: INLINE VertexBufferContext::
VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) : VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
BufferContext(&pgo->_vbuffer_residency), BufferContext(&pgo->_vbuffer_residency, data),
AdaptiveLruPage(0), AdaptiveLruPage(0)
_data(data)
{ {
} }
@ -27,7 +26,7 @@ VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
*/ */
INLINE GeomVertexArrayData *VertexBufferContext:: INLINE GeomVertexArrayData *VertexBufferContext::
get_data() const { get_data() const {
return _data; return (GeomVertexArrayData *)_object;
} }
/** /**
@ -36,7 +35,7 @@ get_data() const {
*/ */
INLINE bool VertexBufferContext:: INLINE bool VertexBufferContext::
changed_size(const GeomVertexArrayDataHandle *reader) const { 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(); 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:: INLINE bool VertexBufferContext::
changed_usage_hint(const GeomVertexArrayDataHandle *reader) const { 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(); return _usage_hint != reader->get_usage_hint();
} }
@ -56,7 +55,7 @@ changed_usage_hint(const GeomVertexArrayDataHandle *reader) const {
*/ */
INLINE bool VertexBufferContext:: INLINE bool VertexBufferContext::
was_modified(const GeomVertexArrayDataHandle *reader) const { 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(); return get_modified() != reader->get_modified();
} }
@ -77,7 +76,7 @@ update_data_size_bytes(size_t new_data_size_bytes) {
*/ */
INLINE void VertexBufferContext:: INLINE void VertexBufferContext::
mark_loaded(const GeomVertexArrayDataHandle *reader) { 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_data_size_bytes(reader->get_data_size_bytes());
update_modified(reader->get_modified()); update_modified(reader->get_modified());
_usage_hint = reader->get_usage_hint(); _usage_hint = reader->get_usage_hint();

View File

@ -51,10 +51,6 @@ public:
virtual void write(std::ostream &out, int indent_level) const; virtual void write(std::ostream &out, int indent_level) const;
private: 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; GeomEnums::UsageHint _usage_hint;
public: public: