mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
released-vbuffer-cache
This commit is contained in:
parent
707ff8f504
commit
be8b867498
@ -250,6 +250,24 @@ ConfigVariableInt geom_cache_min_frames
|
|||||||
"object will remain in the geom cache, even if geom-cache-size "
|
"object will remain in the geom cache, even if geom-cache-size "
|
||||||
"is exceeded."));
|
"is exceeded."));
|
||||||
|
|
||||||
|
ConfigVariableInt released_vbuffer_cache_size
|
||||||
|
("released-vbuffer-cache-size", 1048576,
|
||||||
|
PRC_DESC("Specifies the size in bytes of the cache of vertex "
|
||||||
|
"buffers that have recently been released. If a new vertex "
|
||||||
|
"buffer is prepared while a recently-released one of the same "
|
||||||
|
"size is still in the cache, that same buffer is recycled. This "
|
||||||
|
"cuts down on the overhead of creating and destroying vertex "
|
||||||
|
"buffers on the graphics card."));
|
||||||
|
|
||||||
|
ConfigVariableInt released_ibuffer_cache_size
|
||||||
|
("released-ibuffer-cache-size", 102400,
|
||||||
|
PRC_DESC("Specifies the size in bytes of the cache of index "
|
||||||
|
"buffers that have recently been released. If a new index "
|
||||||
|
"buffer is prepared while a recently-released one of the same "
|
||||||
|
"size is still in the cache, that same buffer is recycled. This "
|
||||||
|
"cuts down on the overhead of creating and destroying index "
|
||||||
|
"buffers on the graphics card."));
|
||||||
|
|
||||||
ConfigVariableDouble default_near
|
ConfigVariableDouble default_near
|
||||||
("default-near", 1.0,
|
("default-near", 1.0,
|
||||||
PRC_DESC("The default near clipping distance for all cameras."));
|
PRC_DESC("The default near clipping distance for all cameras."));
|
||||||
|
@ -63,6 +63,8 @@ extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_header_only;
|
|||||||
|
|
||||||
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_size;
|
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_size;
|
||||||
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
|
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
|
||||||
|
extern EXPCL_PANDA_GOBJ ConfigVariableInt released_vbuffer_cache_size;
|
||||||
|
extern EXPCL_PANDA_GOBJ ConfigVariableInt released_ibuffer_cache_size;
|
||||||
|
|
||||||
extern EXPCL_PANDA_GOBJ ConfigVariableDouble default_near;
|
extern EXPCL_PANDA_GOBJ ConfigVariableDouble default_near;
|
||||||
extern EXPCL_PANDA_GOBJ ConfigVariableDouble default_far;
|
extern EXPCL_PANDA_GOBJ ConfigVariableDouble default_far;
|
||||||
|
@ -17,8 +17,68 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "geomEnums.h"
|
#include "geomEnums.h"
|
||||||
|
#include "string_utils.h"
|
||||||
|
#include "config_gobj.h"
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: GeomEnums::UsageHint output operator
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
ostream &
|
||||||
|
operator << (ostream &out, GeomEnums::UsageHint usage_hint) {
|
||||||
|
switch (usage_hint) {
|
||||||
|
case GeomEnums::UH_client:
|
||||||
|
return out << "client";
|
||||||
|
|
||||||
|
case GeomEnums::UH_stream:
|
||||||
|
return out << "stream";
|
||||||
|
|
||||||
|
case GeomEnums::UH_dynamic:
|
||||||
|
return out << "dynamic";
|
||||||
|
|
||||||
|
case GeomEnums::UH_static:
|
||||||
|
return out << "static";
|
||||||
|
|
||||||
|
case GeomEnums::UH_unspecified:
|
||||||
|
return out << "unspecified";
|
||||||
|
}
|
||||||
|
|
||||||
|
return out << "**invalid usage hint (" << (int)usage_hint << ")**";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: GeomEnums::UsageHint input operator
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
istream &
|
||||||
|
operator >> (istream &in, GeomEnums::UsageHint &usage_hint) {
|
||||||
|
string word;
|
||||||
|
in >> word;
|
||||||
|
|
||||||
|
if (cmp_nocase(word, "client") == 0) {
|
||||||
|
usage_hint = GeomEnums::UH_client;
|
||||||
|
} else if (cmp_nocase(word, "stream") == 0) {
|
||||||
|
usage_hint = GeomEnums::UH_stream;
|
||||||
|
} else if (cmp_nocase(word, "dynamic") == 0) {
|
||||||
|
usage_hint = GeomEnums::UH_dynamic;
|
||||||
|
} else if (cmp_nocase(word, "static") == 0) {
|
||||||
|
usage_hint = GeomEnums::UH_static;
|
||||||
|
} else if (cmp_nocase(word, "unspecified") == 0) {
|
||||||
|
usage_hint = GeomEnums::UH_unspecified;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
gobj_cat->error() << "Invalid usage hint value: " << word << "\n";
|
||||||
|
usage_hint = GeomEnums::UH_unspecified;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: GeomEnums::NumericType output operator
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
ostream &
|
ostream &
|
||||||
operator << (ostream &out, GeomEnums::NumericType numeric_type) {
|
operator << (ostream &out, GeomEnums::NumericType numeric_type) {
|
||||||
switch (numeric_type) {
|
switch (numeric_type) {
|
||||||
@ -44,6 +104,10 @@ operator << (ostream &out, GeomEnums::NumericType numeric_type) {
|
|||||||
return out << "**invalid numeric type (" << (int)numeric_type << ")**";
|
return out << "**invalid numeric type (" << (int)numeric_type << ")**";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: GeomEnums::Contents output operator
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
ostream &
|
ostream &
|
||||||
operator << (ostream &out, GeomEnums::Contents contents) {
|
operator << (ostream &out, GeomEnums::Contents contents) {
|
||||||
switch (contents) {
|
switch (contents) {
|
||||||
|
@ -67,7 +67,7 @@ PUBLISHED:
|
|||||||
UH_static,
|
UH_static,
|
||||||
|
|
||||||
// UH_unspecified: the usage is unspecified. This is intended as
|
// UH_unspecified: the usage is unspecified. This is intended as
|
||||||
// a "don't care" option for abstract objects, it should not be
|
// a "don't care" option for abstract objects; it should not be
|
||||||
// applied to any actual geometry to be rendered. You take your
|
// applied to any actual geometry to be rendered. You take your
|
||||||
// chances if a geom actually gets into the scene graph with this
|
// chances if a geom actually gets into the scene graph with this
|
||||||
// set.
|
// set.
|
||||||
@ -211,6 +211,8 @@ PUBLISHED:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::UsageHint usage_hint);
|
||||||
|
EXPCL_PANDA_GOBJ istream &operator >> (istream &in, GeomEnums::UsageHint &usage_hint);
|
||||||
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::NumericType numeric_type);
|
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::NumericType numeric_type);
|
||||||
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
|
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
|
||||||
|
|
||||||
|
@ -72,3 +72,37 @@ get_num_prepared() const {
|
|||||||
get_num_prepared_vertex_buffers() +
|
get_num_prepared_vertex_buffers() +
|
||||||
get_num_prepared_index_buffers());
|
get_num_prepared_index_buffers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PreparedGraphicsObjects::BufferCacheKey::operator <
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool PreparedGraphicsObjects::BufferCacheKey::
|
||||||
|
operator < (const PreparedGraphicsObjects::BufferCacheKey &other) const {
|
||||||
|
if (_data_size_bytes != other._data_size_bytes) {
|
||||||
|
return _data_size_bytes < other._data_size_bytes;
|
||||||
|
}
|
||||||
|
return (int)_usage_hint < (int)other._usage_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PreparedGraphicsObjects::BufferCacheKey::operator ==
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool PreparedGraphicsObjects::BufferCacheKey::
|
||||||
|
operator == (const PreparedGraphicsObjects::BufferCacheKey &other) const {
|
||||||
|
return (_data_size_bytes == other._data_size_bytes &&
|
||||||
|
_usage_hint == other._usage_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PreparedGraphicsObjects::BufferCacheKey::operator !=
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool PreparedGraphicsObjects::BufferCacheKey::
|
||||||
|
operator != (const PreparedGraphicsObjects::BufferCacheKey &other) const {
|
||||||
|
return !operator == (other);
|
||||||
|
}
|
||||||
|
@ -42,7 +42,9 @@ PreparedGraphicsObjects() :
|
|||||||
_name(init_name()),
|
_name(init_name()),
|
||||||
_texture_residency(_name, "texture"),
|
_texture_residency(_name, "texture"),
|
||||||
_vbuffer_residency(_name, "vbuffer"),
|
_vbuffer_residency(_name, "vbuffer"),
|
||||||
_ibuffer_residency(_name, "ibuffer")
|
_ibuffer_residency(_name, "ibuffer"),
|
||||||
|
_vertex_buffer_cache_size(0),
|
||||||
|
_index_buffer_cache_size(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,68 +61,41 @@ PreparedGraphicsObjects::
|
|||||||
// cleaned up. Quietly erase these remaining objects.
|
// cleaned up. Quietly erase these remaining objects.
|
||||||
ReMutexHolder holder(_lock);
|
ReMutexHolder holder(_lock);
|
||||||
|
|
||||||
|
release_all_textures();
|
||||||
Textures::iterator tci;
|
Textures::iterator tci;
|
||||||
for (tci = _prepared_textures.begin();
|
for (tci = _released_textures.begin();
|
||||||
tci != _prepared_textures.end();
|
tci != _released_textures.end();
|
||||||
++tci) {
|
++tci) {
|
||||||
TextureContext *tc = (*tci);
|
TextureContext *tc = (*tci);
|
||||||
tc->get_texture()->clear_prepared(this);
|
|
||||||
tc->set_owning_chain(NULL);
|
tc->set_owning_chain(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
_prepared_textures.clear();
|
|
||||||
_released_textures.clear();
|
_released_textures.clear();
|
||||||
_enqueued_textures.clear();
|
|
||||||
|
|
||||||
Geoms::iterator gci;
|
release_all_geoms();
|
||||||
for (gci = _prepared_geoms.begin();
|
|
||||||
gci != _prepared_geoms.end();
|
|
||||||
++gci) {
|
|
||||||
GeomContext *gc = (*gci);
|
|
||||||
gc->_geom->clear_prepared(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_prepared_geoms.clear();
|
|
||||||
_released_geoms.clear();
|
_released_geoms.clear();
|
||||||
_enqueued_geoms.clear();
|
|
||||||
|
|
||||||
Shaders::iterator sci;
|
release_all_shaders();
|
||||||
for (sci = _prepared_shaders.begin();
|
|
||||||
sci != _prepared_shaders.end();
|
|
||||||
++sci) {
|
|
||||||
ShaderContext *sc = (*sci);
|
|
||||||
sc->_expansion->clear_prepared(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_prepared_shaders.clear();
|
|
||||||
_released_shaders.clear();
|
_released_shaders.clear();
|
||||||
_enqueued_shaders.clear();
|
|
||||||
|
|
||||||
VertexBuffers::iterator vbci;
|
release_all_vertex_buffers();
|
||||||
for (vbci = _prepared_vertex_buffers.begin();
|
Buffers::iterator vbci;
|
||||||
vbci != _prepared_vertex_buffers.end();
|
for (vbci = _released_vertex_buffers.begin();
|
||||||
|
vbci != _released_vertex_buffers.end();
|
||||||
++vbci) {
|
++vbci) {
|
||||||
VertexBufferContext *vbc = (*vbci);
|
VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
|
||||||
vbc->_data->clear_prepared(this);
|
|
||||||
vbc->set_owning_chain(NULL);
|
vbc->set_owning_chain(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
_prepared_vertex_buffers.clear();
|
|
||||||
_released_vertex_buffers.clear();
|
_released_vertex_buffers.clear();
|
||||||
_enqueued_vertex_buffers.clear();
|
|
||||||
|
|
||||||
IndexBuffers::iterator ibci;
|
release_all_index_buffers();
|
||||||
for (ibci = _prepared_index_buffers.begin();
|
Buffers::iterator ibci;
|
||||||
ibci != _prepared_index_buffers.end();
|
for (ibci = _released_index_buffers.begin();
|
||||||
|
ibci != _released_index_buffers.end();
|
||||||
++ibci) {
|
++ibci) {
|
||||||
IndexBufferContext *ibc = (*ibci);
|
IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
|
||||||
ibc->_data->clear_prepared(this);
|
|
||||||
ibc->set_owning_chain(NULL);
|
ibc->set_owning_chain(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
_prepared_index_buffers.clear();
|
|
||||||
_released_index_buffers.clear();
|
_released_index_buffers.clear();
|
||||||
_enqueued_index_buffers.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -772,6 +747,9 @@ release_vertex_buffer(VertexBufferContext *vbc) {
|
|||||||
|
|
||||||
vbc->_data->clear_prepared(this);
|
vbc->_data->clear_prepared(this);
|
||||||
|
|
||||||
|
size_t data_size_bytes = vbc->_data->get_data_size_bytes();
|
||||||
|
GeomEnums::UsageHint usage_hint = vbc->_data->get_usage_hint();
|
||||||
|
|
||||||
// We have to set the Data pointer to NULL at this point, since
|
// 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
|
// the Data itself might destruct at any time after it has been
|
||||||
// released.
|
// released.
|
||||||
@ -780,7 +758,11 @@ release_vertex_buffer(VertexBufferContext *vbc) {
|
|||||||
bool removed = (_prepared_vertex_buffers.erase(vbc) != 0);
|
bool removed = (_prepared_vertex_buffers.erase(vbc) != 0);
|
||||||
nassertv(removed);
|
nassertv(removed);
|
||||||
|
|
||||||
_released_vertex_buffers.insert(vbc);
|
cache_unprepared_buffer(vbc, data_size_bytes, usage_hint,
|
||||||
|
_vertex_buffer_cache,
|
||||||
|
_vertex_buffer_cache_lru, _vertex_buffer_cache_size,
|
||||||
|
released_vbuffer_cache_size,
|
||||||
|
_released_vertex_buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -797,11 +779,11 @@ release_all_vertex_buffers() {
|
|||||||
|
|
||||||
int num_vertex_buffers = (int)_prepared_vertex_buffers.size() + (int)_enqueued_vertex_buffers.size();
|
int num_vertex_buffers = (int)_prepared_vertex_buffers.size() + (int)_enqueued_vertex_buffers.size();
|
||||||
|
|
||||||
VertexBuffers::iterator vbci;
|
Buffers::iterator vbci;
|
||||||
for (vbci = _prepared_vertex_buffers.begin();
|
for (vbci = _prepared_vertex_buffers.begin();
|
||||||
vbci != _prepared_vertex_buffers.end();
|
vbci != _prepared_vertex_buffers.end();
|
||||||
++vbci) {
|
++vbci) {
|
||||||
VertexBufferContext *vbc = (*vbci);
|
VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
|
||||||
vbc->_data->clear_prepared(this);
|
vbc->_data->clear_prepared(this);
|
||||||
vbc->_data = (GeomVertexArrayData *)NULL;
|
vbc->_data = (GeomVertexArrayData *)NULL;
|
||||||
|
|
||||||
@ -811,6 +793,23 @@ release_all_vertex_buffers() {
|
|||||||
_prepared_vertex_buffers.clear();
|
_prepared_vertex_buffers.clear();
|
||||||
_enqueued_vertex_buffers.clear();
|
_enqueued_vertex_buffers.clear();
|
||||||
|
|
||||||
|
// Also clear the cache of recently-unprepared vertex buffers.
|
||||||
|
BufferCache::iterator bci;
|
||||||
|
for (bci = _vertex_buffer_cache.begin();
|
||||||
|
bci != _vertex_buffer_cache.end();
|
||||||
|
++bci) {
|
||||||
|
BufferList &buffer_list = (*bci).second;
|
||||||
|
nassertr(!buffer_list.empty(), num_vertex_buffers);
|
||||||
|
BufferList::iterator li;
|
||||||
|
for (li = buffer_list.begin(); li != buffer_list.end(); ++li) {
|
||||||
|
VertexBufferContext *vbc = (VertexBufferContext *)(*li);
|
||||||
|
_released_vertex_buffers.insert(vbc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_vertex_buffer_cache.clear();
|
||||||
|
_vertex_buffer_cache_lru.clear();
|
||||||
|
_vertex_buffer_cache_size = 0;
|
||||||
|
|
||||||
return num_vertex_buffers;
|
return num_vertex_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,11 +861,24 @@ VertexBufferContext *PreparedGraphicsObjects::
|
|||||||
prepare_vertex_buffer_now(GeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
|
prepare_vertex_buffer_now(GeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
|
||||||
ReMutexHolder holder(_lock);
|
ReMutexHolder holder(_lock);
|
||||||
|
|
||||||
// Ask the GSG to create a brand new VertexBufferContext. There might
|
// First, see if there might be a cached context of the appropriate
|
||||||
// be several GSG's sharing the same set of datas; if so, it
|
// size.
|
||||||
// doesn't matter which of them creates the context (since they're
|
size_t data_size_bytes = data->get_data_size_bytes();
|
||||||
// all shared anyway).
|
GeomEnums::UsageHint usage_hint = data->get_usage_hint();
|
||||||
VertexBufferContext *vbc = gsg->prepare_vertex_buffer(data);
|
VertexBufferContext *vbc = (VertexBufferContext *)
|
||||||
|
get_cached_buffer(data_size_bytes, usage_hint,
|
||||||
|
_vertex_buffer_cache, _vertex_buffer_cache_lru,
|
||||||
|
_vertex_buffer_cache_size);
|
||||||
|
if (vbc != (VertexBufferContext *)NULL) {
|
||||||
|
vbc->_data = data;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Ask the GSG to create a brand new VertexBufferContext. There
|
||||||
|
// might be several GSG's sharing the same set of datas; if so, it
|
||||||
|
// doesn't matter which of them creates the context (since they're
|
||||||
|
// all shared anyway).
|
||||||
|
vbc = gsg->prepare_vertex_buffer(data);
|
||||||
|
}
|
||||||
|
|
||||||
if (vbc != (VertexBufferContext *)NULL) {
|
if (vbc != (VertexBufferContext *)NULL) {
|
||||||
bool prepared = _prepared_vertex_buffers.insert(vbc).second;
|
bool prepared = _prepared_vertex_buffers.insert(vbc).second;
|
||||||
@ -960,6 +972,9 @@ release_index_buffer(IndexBufferContext *ibc) {
|
|||||||
|
|
||||||
ibc->_data->clear_prepared(this);
|
ibc->_data->clear_prepared(this);
|
||||||
|
|
||||||
|
size_t data_size_bytes = ibc->_data->get_data_size_bytes();
|
||||||
|
GeomEnums::UsageHint usage_hint = ibc->_data->get_usage_hint();
|
||||||
|
|
||||||
// We have to set the Data pointer to NULL at this point, since
|
// 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
|
// the Data itself might destruct at any time after it has been
|
||||||
// released.
|
// released.
|
||||||
@ -968,7 +983,11 @@ release_index_buffer(IndexBufferContext *ibc) {
|
|||||||
bool removed = (_prepared_index_buffers.erase(ibc) != 0);
|
bool removed = (_prepared_index_buffers.erase(ibc) != 0);
|
||||||
nassertv(removed);
|
nassertv(removed);
|
||||||
|
|
||||||
_released_index_buffers.insert(ibc);
|
cache_unprepared_buffer(ibc, data_size_bytes, usage_hint,
|
||||||
|
_index_buffer_cache,
|
||||||
|
_index_buffer_cache_lru, _index_buffer_cache_size,
|
||||||
|
released_ibuffer_cache_size,
|
||||||
|
_released_index_buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -985,11 +1004,11 @@ release_all_index_buffers() {
|
|||||||
|
|
||||||
int num_index_buffers = (int)_prepared_index_buffers.size() + (int)_enqueued_index_buffers.size();
|
int num_index_buffers = (int)_prepared_index_buffers.size() + (int)_enqueued_index_buffers.size();
|
||||||
|
|
||||||
IndexBuffers::iterator ibci;
|
Buffers::iterator ibci;
|
||||||
for (ibci = _prepared_index_buffers.begin();
|
for (ibci = _prepared_index_buffers.begin();
|
||||||
ibci != _prepared_index_buffers.end();
|
ibci != _prepared_index_buffers.end();
|
||||||
++ibci) {
|
++ibci) {
|
||||||
IndexBufferContext *ibc = (*ibci);
|
IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
|
||||||
ibc->_data->clear_prepared(this);
|
ibc->_data->clear_prepared(this);
|
||||||
ibc->_data = (GeomPrimitive *)NULL;
|
ibc->_data = (GeomPrimitive *)NULL;
|
||||||
|
|
||||||
@ -999,6 +1018,23 @@ release_all_index_buffers() {
|
|||||||
_prepared_index_buffers.clear();
|
_prepared_index_buffers.clear();
|
||||||
_enqueued_index_buffers.clear();
|
_enqueued_index_buffers.clear();
|
||||||
|
|
||||||
|
// Also clear the cache of recently-unprepared index buffers.
|
||||||
|
BufferCache::iterator bci;
|
||||||
|
for (bci = _index_buffer_cache.begin();
|
||||||
|
bci != _index_buffer_cache.end();
|
||||||
|
++bci) {
|
||||||
|
BufferList &buffer_list = (*bci).second;
|
||||||
|
nassertr(!buffer_list.empty(), num_index_buffers);
|
||||||
|
BufferList::iterator li;
|
||||||
|
for (li = buffer_list.begin(); li != buffer_list.end(); ++li) {
|
||||||
|
IndexBufferContext *vbc = (IndexBufferContext *)(*li);
|
||||||
|
_released_index_buffers.insert(vbc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_index_buffer_cache.clear();
|
||||||
|
_index_buffer_cache_lru.clear();
|
||||||
|
_index_buffer_cache_size = 0;
|
||||||
|
|
||||||
return num_index_buffers;
|
return num_index_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1050,11 +1086,24 @@ IndexBufferContext *PreparedGraphicsObjects::
|
|||||||
prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
|
prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
|
||||||
ReMutexHolder holder(_lock);
|
ReMutexHolder holder(_lock);
|
||||||
|
|
||||||
// Ask the GSG to create a brand new IndexBufferContext. There might
|
// First, see if there might be a cached context of the appropriate
|
||||||
// be several GSG's sharing the same set of datas; if so, it
|
// size.
|
||||||
// doesn't matter which of them creates the context (since they're
|
size_t data_size_bytes = data->get_data_size_bytes();
|
||||||
// all shared anyway).
|
GeomEnums::UsageHint usage_hint = data->get_usage_hint();
|
||||||
IndexBufferContext *ibc = gsg->prepare_index_buffer(data);
|
IndexBufferContext *ibc = (IndexBufferContext *)
|
||||||
|
get_cached_buffer(data_size_bytes, usage_hint,
|
||||||
|
_index_buffer_cache, _index_buffer_cache_lru,
|
||||||
|
_index_buffer_cache_size);
|
||||||
|
if (ibc != (IndexBufferContext *)NULL) {
|
||||||
|
ibc->_data = data;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Ask the GSG to create a brand new IndexBufferContext. There
|
||||||
|
// might be several GSG's sharing the same set of datas; if so, it
|
||||||
|
// doesn't matter which of them creates the context (since they're
|
||||||
|
// all shared anyway).
|
||||||
|
ibc = gsg->prepare_index_buffer(data);
|
||||||
|
}
|
||||||
|
|
||||||
if (ibc != (IndexBufferContext *)NULL) {
|
if (ibc != (IndexBufferContext *)NULL) {
|
||||||
bool prepared = _prepared_index_buffers.insert(ibc).second;
|
bool prepared = _prepared_index_buffers.insert(ibc).second;
|
||||||
@ -1114,21 +1163,21 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
|
|||||||
|
|
||||||
_released_shaders.clear();
|
_released_shaders.clear();
|
||||||
|
|
||||||
VertexBuffers::iterator vbci;
|
Buffers::iterator vbci;
|
||||||
for (vbci = _released_vertex_buffers.begin();
|
for (vbci = _released_vertex_buffers.begin();
|
||||||
vbci != _released_vertex_buffers.end();
|
vbci != _released_vertex_buffers.end();
|
||||||
++vbci) {
|
++vbci) {
|
||||||
VertexBufferContext *vbc = (*vbci);
|
VertexBufferContext *vbc = (VertexBufferContext *)(*vbci);
|
||||||
gsg->release_vertex_buffer(vbc);
|
gsg->release_vertex_buffer(vbc);
|
||||||
}
|
}
|
||||||
|
|
||||||
_released_vertex_buffers.clear();
|
_released_vertex_buffers.clear();
|
||||||
|
|
||||||
IndexBuffers::iterator ibci;
|
Buffers::iterator ibci;
|
||||||
for (ibci = _released_index_buffers.begin();
|
for (ibci = _released_index_buffers.begin();
|
||||||
ibci != _released_index_buffers.end();
|
ibci != _released_index_buffers.end();
|
||||||
++ibci) {
|
++ibci) {
|
||||||
IndexBufferContext *ibc = (*ibci);
|
IndexBufferContext *ibc = (IndexBufferContext *)(*ibci);
|
||||||
gsg->release_index_buffer(ibc);
|
gsg->release_index_buffer(ibc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1221,3 +1270,96 @@ init_name() {
|
|||||||
strm << "context" << _name_index;
|
strm << "context" << _name_index;
|
||||||
return strm.str();
|
return strm.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PreparedGraphicsObjects::cache_unprepared_buffer
|
||||||
|
// Access: Private
|
||||||
|
// Description: Called when a vertex or index buffer is no longer
|
||||||
|
// officially "prepared". However, we still have the
|
||||||
|
// context on the graphics card, and we might be able to
|
||||||
|
// reuse that context if we're about to re-prepare a
|
||||||
|
// different buffer, especially one exactly the same
|
||||||
|
// size. So instead of immediately enqueuing the vertex
|
||||||
|
// buffer for release, we cache it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PreparedGraphicsObjects::
|
||||||
|
cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes,
|
||||||
|
GeomEnums::UsageHint usage_hint,
|
||||||
|
PreparedGraphicsObjects::BufferCache &buffer_cache,
|
||||||
|
PreparedGraphicsObjects::BufferCacheLRU &buffer_cache_lru,
|
||||||
|
size_t &buffer_cache_size,
|
||||||
|
int released_buffer_cache_size,
|
||||||
|
PreparedGraphicsObjects::Buffers &released_buffers) {
|
||||||
|
BufferCacheKey key;
|
||||||
|
key._data_size_bytes = data_size_bytes;
|
||||||
|
key._usage_hint = usage_hint;
|
||||||
|
|
||||||
|
buffer_cache[key].push_back(buffer);
|
||||||
|
buffer_cache_size += data_size_bytes;
|
||||||
|
|
||||||
|
// Move the key to the head of the LRU.
|
||||||
|
BufferCacheLRU::iterator li =
|
||||||
|
find(buffer_cache_lru.begin(), buffer_cache_lru.end(), key);
|
||||||
|
if (li != buffer_cache_lru.end()) {
|
||||||
|
buffer_cache_lru.erase(li);
|
||||||
|
}
|
||||||
|
buffer_cache_lru.insert(buffer_cache_lru.begin(), key);
|
||||||
|
|
||||||
|
// Now release not-recently-used buffers until we fit within the
|
||||||
|
// constrained size.
|
||||||
|
while ((int)buffer_cache_size > released_buffer_cache_size) {
|
||||||
|
nassertv(!buffer_cache_lru.empty());
|
||||||
|
const BufferCacheKey &release_key = *buffer_cache_lru.rbegin();
|
||||||
|
BufferList &buffer_list = buffer_cache[release_key];
|
||||||
|
while (!buffer_list.empty() &&
|
||||||
|
(int)buffer_cache_size > released_buffer_cache_size) {
|
||||||
|
BufferContext *released_buffer = buffer_list.back();
|
||||||
|
buffer_list.pop_back();
|
||||||
|
released_buffers.insert(released_buffer);
|
||||||
|
buffer_cache_size -= release_key._data_size_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_list.empty()) {
|
||||||
|
buffer_cache.erase(release_key);
|
||||||
|
buffer_cache_lru.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PreparedGraphicsObjects::get_cached_buffer
|
||||||
|
// Access: Private
|
||||||
|
// Description: Returns a previously-cached buffer from the cache, or
|
||||||
|
// NULL if there is no such buffer.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
BufferContext *PreparedGraphicsObjects::
|
||||||
|
get_cached_buffer(size_t data_size_bytes, GeomEnums::UsageHint usage_hint,
|
||||||
|
PreparedGraphicsObjects::BufferCache &buffer_cache,
|
||||||
|
PreparedGraphicsObjects::BufferCacheLRU &buffer_cache_lru,
|
||||||
|
size_t &buffer_cache_size) {
|
||||||
|
BufferCacheKey key;
|
||||||
|
key._data_size_bytes = data_size_bytes;
|
||||||
|
key._usage_hint = usage_hint;
|
||||||
|
|
||||||
|
BufferCache::iterator bci = buffer_cache.find(key);
|
||||||
|
if (bci == buffer_cache.end()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferList &buffer_list = (*bci).second;
|
||||||
|
nassertr(!buffer_list.empty(), NULL);
|
||||||
|
|
||||||
|
BufferContext *buffer = buffer_list.back();
|
||||||
|
buffer_list.pop_back();
|
||||||
|
if (buffer_list.empty()) {
|
||||||
|
buffer_cache.erase(bci);
|
||||||
|
BufferCacheLRU::iterator li =
|
||||||
|
find(buffer_cache_lru.begin(), buffer_cache_lru.end(), key);
|
||||||
|
if (li != buffer_cache_lru.end()) {
|
||||||
|
buffer_cache_lru.erase(li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_cache_size -= data_size_bytes;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
@ -144,11 +144,35 @@ private:
|
|||||||
typedef phash_set< PT(Geom) > EnqueuedGeoms;
|
typedef phash_set< PT(Geom) > EnqueuedGeoms;
|
||||||
typedef phash_set<ShaderContext *, pointer_hash> Shaders;
|
typedef phash_set<ShaderContext *, pointer_hash> Shaders;
|
||||||
typedef phash_set< PT(ShaderExpansion) > EnqueuedShaders;
|
typedef phash_set< PT(ShaderExpansion) > EnqueuedShaders;
|
||||||
typedef phash_set<VertexBufferContext *, pointer_hash> VertexBuffers;
|
typedef phash_set<BufferContext *, pointer_hash> Buffers;
|
||||||
typedef phash_set< PT(GeomVertexArrayData) > EnqueuedVertexBuffers;
|
typedef phash_set< PT(GeomVertexArrayData) > EnqueuedVertexBuffers;
|
||||||
typedef phash_set<IndexBufferContext *, pointer_hash> IndexBuffers;
|
|
||||||
typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers;
|
typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers;
|
||||||
|
|
||||||
|
class BufferCacheKey {
|
||||||
|
public:
|
||||||
|
INLINE bool operator < (const BufferCacheKey &other) const;
|
||||||
|
INLINE bool operator == (const BufferCacheKey &other) const;
|
||||||
|
INLINE bool operator != (const BufferCacheKey &other) const;
|
||||||
|
size_t _data_size_bytes;
|
||||||
|
GeomEnums::UsageHint _usage_hint;
|
||||||
|
};
|
||||||
|
typedef pvector<BufferContext *> BufferList;
|
||||||
|
typedef pmap<BufferCacheKey, BufferList> BufferCache;
|
||||||
|
typedef plist<BufferCacheKey> BufferCacheLRU;
|
||||||
|
|
||||||
|
void cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes,
|
||||||
|
GeomEnums::UsageHint usage_hint,
|
||||||
|
BufferCache &buffer_cache,
|
||||||
|
BufferCacheLRU &buffer_cache_lru,
|
||||||
|
size_t &buffer_cache_size,
|
||||||
|
int released_buffer_cache_size,
|
||||||
|
Buffers &released_buffers);
|
||||||
|
BufferContext *get_cached_buffer(size_t data_size_bytes,
|
||||||
|
GeomEnums::UsageHint usage_hint,
|
||||||
|
BufferCache &buffer_cache,
|
||||||
|
BufferCacheLRU &buffer_cache_lru,
|
||||||
|
size_t &buffer_cache_size);
|
||||||
|
|
||||||
ReMutex _lock;
|
ReMutex _lock;
|
||||||
string _name;
|
string _name;
|
||||||
Textures _prepared_textures, _released_textures;
|
Textures _prepared_textures, _released_textures;
|
||||||
@ -157,11 +181,19 @@ private:
|
|||||||
EnqueuedGeoms _enqueued_geoms;
|
EnqueuedGeoms _enqueued_geoms;
|
||||||
Shaders _prepared_shaders, _released_shaders;
|
Shaders _prepared_shaders, _released_shaders;
|
||||||
EnqueuedShaders _enqueued_shaders;
|
EnqueuedShaders _enqueued_shaders;
|
||||||
VertexBuffers _prepared_vertex_buffers, _released_vertex_buffers;
|
Buffers _prepared_vertex_buffers, _released_vertex_buffers;
|
||||||
EnqueuedVertexBuffers _enqueued_vertex_buffers;
|
EnqueuedVertexBuffers _enqueued_vertex_buffers;
|
||||||
IndexBuffers _prepared_index_buffers, _released_index_buffers;
|
Buffers _prepared_index_buffers, _released_index_buffers;
|
||||||
EnqueuedIndexBuffers _enqueued_index_buffers;
|
EnqueuedIndexBuffers _enqueued_index_buffers;
|
||||||
|
|
||||||
|
BufferCache _vertex_buffer_cache;
|
||||||
|
BufferCacheLRU _vertex_buffer_cache_lru;
|
||||||
|
size_t _vertex_buffer_cache_size;
|
||||||
|
|
||||||
|
BufferCache _index_buffer_cache;
|
||||||
|
BufferCacheLRU _index_buffer_cache_lru;
|
||||||
|
size_t _index_buffer_cache_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BufferResidencyTracker _texture_residency;
|
BufferResidencyTracker _texture_residency;
|
||||||
BufferResidencyTracker _vbuffer_residency;
|
BufferResidencyTracker _vbuffer_residency;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user