787 lines
29 KiB
C++
787 lines
29 KiB
C++
// Filename: preparedGraphicsObjects.cxx
|
|
// Created by: drose (19Feb04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "preparedGraphicsObjects.h"
|
|
#include "textureContext.h"
|
|
#include "vertexBufferContext.h"
|
|
#include "indexBufferContext.h"
|
|
#include "texture.h"
|
|
#include "geom.h"
|
|
#include "qpgeomVertexArrayData.h"
|
|
#include "qpgeomPrimitive.h"
|
|
#include "mutexHolder.h"
|
|
|
|
PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
|
|
PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer size");
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PreparedGraphicsObjects::
|
|
PreparedGraphicsObjects() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::Destructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PreparedGraphicsObjects::
|
|
~PreparedGraphicsObjects() {
|
|
// There may be objects that are still prepared when we destruct.
|
|
// If this is so, then all of the GSG's that own them have already
|
|
// destructed, so we can assume their resources were internally
|
|
// cleaned up. Quietly erase these remaining objects.
|
|
|
|
MutexHolder holder(_lock);
|
|
|
|
Textures::iterator tci;
|
|
for (tci = _prepared_textures.begin();
|
|
tci != _prepared_textures.end();
|
|
++tci) {
|
|
TextureContext *tc = (*tci);
|
|
_total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
|
|
tc->_texture->clear_prepared(this);
|
|
}
|
|
|
|
_prepared_textures.clear();
|
|
_released_textures.clear();
|
|
_enqueued_textures.clear();
|
|
|
|
Geoms::iterator gci;
|
|
for (gci = _prepared_geoms.begin();
|
|
gci != _prepared_geoms.end();
|
|
++gci) {
|
|
GeomContext *gc = (*gci);
|
|
gc->_geom->clear_prepared(this);
|
|
}
|
|
|
|
_prepared_geoms.clear();
|
|
_released_geoms.clear();
|
|
_enqueued_geoms.clear();
|
|
|
|
VertexBuffers::iterator vbci;
|
|
for (vbci = _prepared_vertex_buffers.begin();
|
|
vbci != _prepared_vertex_buffers.end();
|
|
++vbci) {
|
|
VertexBufferContext *vbc = (*vbci);
|
|
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
|
|
vbc->_data->clear_prepared(this);
|
|
}
|
|
|
|
_prepared_vertex_buffers.clear();
|
|
_released_vertex_buffers.clear();
|
|
_enqueued_vertex_buffers.clear();
|
|
|
|
IndexBuffers::iterator ibci;
|
|
for (ibci = _prepared_index_buffers.begin();
|
|
ibci != _prepared_index_buffers.end();
|
|
++ibci) {
|
|
IndexBufferContext *ibc = (*ibci);
|
|
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
|
|
ibc->_data->clear_prepared(this);
|
|
}
|
|
|
|
_prepared_index_buffers.clear();
|
|
_released_index_buffers.clear();
|
|
_enqueued_index_buffers.clear();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::enqueue_texture
|
|
// Access: Public
|
|
// Description: Indicates that a texture would like to be put on the
|
|
// list to be prepared when the GSG is next ready to
|
|
// do this (presumably at the next frame).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
enqueue_texture(Texture *tex) {
|
|
MutexHolder holder(_lock);
|
|
|
|
_enqueued_textures.insert(tex);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::dequeue_texture
|
|
// Access: Public
|
|
// Description: Removes a texture from the queued list of textures to
|
|
// be prepared. Normally it is not necessary to call
|
|
// this, unless you change your mind about preparing it
|
|
// at the last minute, since the texture will
|
|
// automatically be dequeued and prepared at the next
|
|
// frame.
|
|
//
|
|
// The return value is true if the texture is
|
|
// successfully dequeued, false if it had not been
|
|
// queued.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PreparedGraphicsObjects::
|
|
dequeue_texture(Texture *tex) {
|
|
MutexHolder holder(_lock);
|
|
|
|
EnqueuedTextures::iterator qi = _enqueued_textures.find(tex);
|
|
if (qi != _enqueued_textures.end()) {
|
|
_enqueued_textures.erase(qi);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_texture
|
|
// Access: Public
|
|
// Description: Indicates that a texture context, created by a
|
|
// previous call to prepare_texture(), is no longer
|
|
// needed. The driver resources will not be freed until
|
|
// some GSG calls update(), indicating it is at a
|
|
// stage where it is ready to release textures--this
|
|
// prevents conflicts from threading or multiple GSG's
|
|
// sharing textures (we have no way of knowing which
|
|
// graphics context is currently active, or what state
|
|
// it's in, at the time release_texture is called).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
release_texture(TextureContext *tc) {
|
|
MutexHolder holder(_lock);
|
|
|
|
tc->_texture->clear_prepared(this);
|
|
_total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
|
|
|
|
// 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 = (Texture *)NULL;
|
|
|
|
bool removed = (_prepared_textures.erase(tc) != 0);
|
|
nassertv(removed);
|
|
|
|
_released_textures.insert(tc);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_all_textures
|
|
// Access: Public
|
|
// Description: Releases all textures at once. This will force them
|
|
// to be reloaded into texture memory for all GSG's that
|
|
// share this object. Returns the number of textures
|
|
// released.
|
|
////////////////////////////////////////////////////////////////////
|
|
int PreparedGraphicsObjects::
|
|
release_all_textures() {
|
|
MutexHolder holder(_lock);
|
|
|
|
int num_textures = (int)_prepared_textures.size();
|
|
|
|
Textures::iterator tci;
|
|
for (tci = _prepared_textures.begin();
|
|
tci != _prepared_textures.end();
|
|
++tci) {
|
|
TextureContext *tc = (*tci);
|
|
tc->_texture->clear_prepared(this);
|
|
_total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
|
|
tc->_texture = (Texture *)NULL;
|
|
|
|
_released_textures.insert(tc);
|
|
}
|
|
|
|
_prepared_textures.clear();
|
|
|
|
return num_textures;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::prepare_texture_now
|
|
// Access: Public
|
|
// Description: Immediately creates a new TextureContext for the
|
|
// indicated texture and returns it. This assumes that
|
|
// the GraphicsStateGuardian is the currently active
|
|
// rendering context and that it is ready to accept new
|
|
// textures. If this is not necessarily the case, you
|
|
// should use enqueue_texture() instead.
|
|
//
|
|
// Normally, this function is not called directly. Call
|
|
// Texture::prepare_now() instead.
|
|
//
|
|
// The TextureContext contains all of the pertinent
|
|
// information needed by the GSG to keep track of this
|
|
// one particular texture, and will exist as long as the
|
|
// texture is ready to be rendered.
|
|
//
|
|
// When either the Texture or the
|
|
// PreparedGraphicsObjects object destructs, the
|
|
// TextureContext will be deleted.
|
|
////////////////////////////////////////////////////////////////////
|
|
TextureContext *PreparedGraphicsObjects::
|
|
prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg) {
|
|
MutexHolder holder(_lock);
|
|
|
|
// Ask the GSG to create a brand new TextureContext. There might
|
|
// be several GSG's sharing the same set of textures; if so, it
|
|
// doesn't matter which of them creates the context (since they're
|
|
// all shared anyway).
|
|
TextureContext *tc = gsg->prepare_texture(tex);
|
|
|
|
if (tc != (TextureContext *)NULL) {
|
|
bool prepared = _prepared_textures.insert(tc).second;
|
|
nassertr(prepared, tc);
|
|
|
|
_total_texusage_pcollector.add_level(tc->estimate_texture_memory());
|
|
}
|
|
|
|
return tc;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::enqueue_geom
|
|
// Access: Public
|
|
// Description: Indicates that a geom would like to be put on the
|
|
// list to be prepared when the GSG is next ready to
|
|
// do this (presumably at the next frame).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
enqueue_geom(Geom *geom) {
|
|
MutexHolder holder(_lock);
|
|
|
|
_enqueued_geoms.insert(geom);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::dequeue_geom
|
|
// Access: Public
|
|
// Description: Removes a geom from the queued list of geoms to
|
|
// be prepared. Normally it is not necessary to call
|
|
// this, unless you change your mind about preparing it
|
|
// at the last minute, since the geom will
|
|
// automatically be dequeued and prepared at the next
|
|
// frame.
|
|
//
|
|
// The return value is true if the geom is
|
|
// successfully dequeued, false if it had not been
|
|
// queued.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PreparedGraphicsObjects::
|
|
dequeue_geom(Geom *geom) {
|
|
MutexHolder holder(_lock);
|
|
|
|
EnqueuedGeoms::iterator qi = _enqueued_geoms.find(geom);
|
|
if (qi != _enqueued_geoms.end()) {
|
|
_enqueued_geoms.erase(qi);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_geom
|
|
// Access: Public
|
|
// Description: Indicates that a geom context, created by a
|
|
// previous call to prepare_geom(), is no longer
|
|
// needed. The driver resources will not be freed until
|
|
// some GSG calls update(), indicating it is at a
|
|
// stage where it is ready to release geoms--this
|
|
// prevents conflicts from threading or multiple GSG's
|
|
// sharing geoms (we have no way of knowing which
|
|
// graphics context is currently active, or what state
|
|
// it's in, at the time release_geom is called).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
release_geom(GeomContext *gc) {
|
|
MutexHolder holder(_lock);
|
|
|
|
gc->_geom->clear_prepared(this);
|
|
|
|
// We have to set the Geom pointer to NULL at this point, since
|
|
// the Geom itself might destruct at any time after it has been
|
|
// released.
|
|
gc->_geom = (Geom *)NULL;
|
|
|
|
bool removed = (_prepared_geoms.erase(gc) != 0);
|
|
nassertv(removed);
|
|
|
|
_released_geoms.insert(gc);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_all_geoms
|
|
// Access: Public
|
|
// Description: Releases all geoms at once. This will force them
|
|
// to be reloaded into geom memory for all GSG's that
|
|
// share this object. Returns the number of geoms
|
|
// released.
|
|
////////////////////////////////////////////////////////////////////
|
|
int PreparedGraphicsObjects::
|
|
release_all_geoms() {
|
|
MutexHolder holder(_lock);
|
|
|
|
int num_geoms = (int)_prepared_geoms.size();
|
|
|
|
Geoms::iterator gci;
|
|
for (gci = _prepared_geoms.begin();
|
|
gci != _prepared_geoms.end();
|
|
++gci) {
|
|
GeomContext *gc = (*gci);
|
|
gc->_geom->clear_prepared(this);
|
|
gc->_geom = (Geom *)NULL;
|
|
|
|
_released_geoms.insert(gc);
|
|
}
|
|
|
|
_prepared_geoms.clear();
|
|
|
|
return num_geoms;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::prepare_geom_now
|
|
// Access: Public
|
|
// Description: Immediately creates a new GeomContext for the
|
|
// indicated geom and returns it. This assumes that
|
|
// the GraphicsStateGuardian is the currently active
|
|
// rendering context and that it is ready to accept new
|
|
// geoms. If this is not necessarily the case, you
|
|
// should use enqueue_geom() instead.
|
|
//
|
|
// Normally, this function is not called directly. Call
|
|
// Geom::prepare_now() instead.
|
|
//
|
|
// The GeomContext contains all of the pertinent
|
|
// information needed by the GSG to keep track of this
|
|
// one particular geom, and will exist as long as the
|
|
// geom is ready to be rendered.
|
|
//
|
|
// When either the Geom or the
|
|
// PreparedGraphicsObjects object destructs, the
|
|
// GeomContext will be deleted.
|
|
////////////////////////////////////////////////////////////////////
|
|
GeomContext *PreparedGraphicsObjects::
|
|
prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg) {
|
|
MutexHolder holder(_lock);
|
|
|
|
// Ask the GSG to create a brand new GeomContext. There might
|
|
// be several GSG's sharing the same set of geoms; if so, it
|
|
// doesn't matter which of them creates the context (since they're
|
|
// all shared anyway).
|
|
GeomContext *gc = gsg->prepare_geom(geom);
|
|
|
|
if (gc != (GeomContext *)NULL) {
|
|
bool prepared = _prepared_geoms.insert(gc).second;
|
|
nassertr(prepared, gc);
|
|
}
|
|
|
|
return gc;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::enqueue_vertex_buffer
|
|
// Access: Public
|
|
// Description: Indicates that a buffer would like to be put on the
|
|
// list to be prepared when the GSG is next ready to
|
|
// do this (presumably at the next frame).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
enqueue_vertex_buffer(qpGeomVertexArrayData *data) {
|
|
MutexHolder holder(_lock);
|
|
|
|
_enqueued_vertex_buffers.insert(data);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::dequeue_vertex_buffer
|
|
// Access: Public
|
|
// Description: Removes a buffer from the queued list of data
|
|
// arrays to be prepared. Normally it is not necessary
|
|
// to call this, unless you change your mind about
|
|
// preparing it at the last minute, since the data will
|
|
// automatically be dequeued and prepared at the next
|
|
// frame.
|
|
//
|
|
// The return value is true if the buffer is
|
|
// successfully dequeued, false if it had not been
|
|
// queued.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PreparedGraphicsObjects::
|
|
dequeue_vertex_buffer(qpGeomVertexArrayData *data) {
|
|
MutexHolder holder(_lock);
|
|
|
|
EnqueuedVertexBuffers::iterator qi = _enqueued_vertex_buffers.find(data);
|
|
if (qi != _enqueued_vertex_buffers.end()) {
|
|
_enqueued_vertex_buffers.erase(qi);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_vertex_buffer
|
|
// Access: Public
|
|
// Description: Indicates that a data context, created by a
|
|
// previous call to prepare_vertex_buffer(), is no longer
|
|
// needed. The driver resources will not be freed until
|
|
// some GSG calls update(), indicating it is at a
|
|
// stage where it is ready to release datas--this
|
|
// prevents conflicts from threading or multiple GSG's
|
|
// sharing datas (we have no way of knowing which
|
|
// graphics context is currently active, or what state
|
|
// it's in, at the time release_vertex_buffer is called).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
release_vertex_buffer(VertexBufferContext *vbc) {
|
|
MutexHolder holder(_lock);
|
|
|
|
vbc->_data->clear_prepared(this);
|
|
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
|
|
|
|
// 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 = (qpGeomVertexArrayData *)NULL;
|
|
|
|
bool removed = (_prepared_vertex_buffers.erase(vbc) != 0);
|
|
nassertv(removed);
|
|
|
|
_released_vertex_buffers.insert(vbc);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_all_vertex_buffers
|
|
// Access: Public
|
|
// Description: Releases all datas at once. This will force them
|
|
// to be reloaded into data memory for all GSG's that
|
|
// share this object. Returns the number of datas
|
|
// released.
|
|
////////////////////////////////////////////////////////////////////
|
|
int PreparedGraphicsObjects::
|
|
release_all_vertex_buffers() {
|
|
MutexHolder holder(_lock);
|
|
|
|
int num_vertex_buffers = (int)_prepared_vertex_buffers.size();
|
|
|
|
VertexBuffers::iterator vbci;
|
|
for (vbci = _prepared_vertex_buffers.begin();
|
|
vbci != _prepared_vertex_buffers.end();
|
|
++vbci) {
|
|
VertexBufferContext *vbc = (*vbci);
|
|
vbc->_data->clear_prepared(this);
|
|
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
|
|
vbc->_data = (qpGeomVertexArrayData *)NULL;
|
|
|
|
_released_vertex_buffers.insert(vbc);
|
|
}
|
|
|
|
_prepared_vertex_buffers.clear();
|
|
|
|
return num_vertex_buffers;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::prepare_vertex_buffer_now
|
|
// Access: Public
|
|
// Description: Immediately creates a new VertexBufferContext for the
|
|
// indicated data and returns it. This assumes that
|
|
// the GraphicsStateGuardian is the currently active
|
|
// rendering context and that it is ready to accept new
|
|
// datas. If this is not necessarily the case, you
|
|
// should use enqueue_vertex_buffer() instead.
|
|
//
|
|
// Normally, this function is not called directly. Call
|
|
// Data::prepare_now() instead.
|
|
//
|
|
// The VertexBufferContext contains all of the pertinent
|
|
// information needed by the GSG to keep track of this
|
|
// one particular data, and will exist as long as the
|
|
// data is ready to be rendered.
|
|
//
|
|
// When either the Data or the
|
|
// PreparedGraphicsObjects object destructs, the
|
|
// VertexBufferContext will be deleted.
|
|
////////////////////////////////////////////////////////////////////
|
|
VertexBufferContext *PreparedGraphicsObjects::
|
|
prepare_vertex_buffer_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
|
|
MutexHolder holder(_lock);
|
|
|
|
// 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).
|
|
VertexBufferContext *vbc = gsg->prepare_vertex_buffer(data);
|
|
|
|
if (vbc != (VertexBufferContext *)NULL) {
|
|
bool prepared = _prepared_vertex_buffers.insert(vbc).second;
|
|
nassertr(prepared, vbc);
|
|
|
|
// The size has already been counted by
|
|
// GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to
|
|
// count it again here.
|
|
//_total_buffers_pcollector.add_level(vbc->get_data_size_bytes());
|
|
}
|
|
|
|
return vbc;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::enqueue_index_buffer
|
|
// Access: Public
|
|
// Description: Indicates that a buffer would like to be put on the
|
|
// list to be prepared when the GSG is next ready to
|
|
// do this (presumably at the next frame).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
enqueue_index_buffer(qpGeomPrimitive *data) {
|
|
MutexHolder holder(_lock);
|
|
|
|
_enqueued_index_buffers.insert(data);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::dequeue_index_buffer
|
|
// Access: Public
|
|
// Description: Removes a buffer from the queued list of data
|
|
// arrays to be prepared. Normally it is not necessary
|
|
// to call this, unless you change your mind about
|
|
// preparing it at the last minute, since the data will
|
|
// automatically be dequeued and prepared at the next
|
|
// frame.
|
|
//
|
|
// The return value is true if the buffer is
|
|
// successfully dequeued, false if it had not been
|
|
// queued.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PreparedGraphicsObjects::
|
|
dequeue_index_buffer(qpGeomPrimitive *data) {
|
|
MutexHolder holder(_lock);
|
|
|
|
EnqueuedIndexBuffers::iterator qi = _enqueued_index_buffers.find(data);
|
|
if (qi != _enqueued_index_buffers.end()) {
|
|
_enqueued_index_buffers.erase(qi);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_index_buffer
|
|
// Access: Public
|
|
// Description: Indicates that a data context, created by a
|
|
// previous call to prepare_index_buffer(), is no longer
|
|
// needed. The driver resources will not be freed until
|
|
// some GSG calls update(), indicating it is at a
|
|
// stage where it is ready to release datas--this
|
|
// prevents conflicts from threading or multiple GSG's
|
|
// sharing datas (we have no way of knowing which
|
|
// graphics context is currently active, or what state
|
|
// it's in, at the time release_index_buffer is called).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
release_index_buffer(IndexBufferContext *ibc) {
|
|
MutexHolder holder(_lock);
|
|
|
|
ibc->_data->clear_prepared(this);
|
|
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
|
|
|
|
// 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 = (qpGeomPrimitive *)NULL;
|
|
|
|
bool removed = (_prepared_index_buffers.erase(ibc) != 0);
|
|
nassertv(removed);
|
|
|
|
_released_index_buffers.insert(ibc);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::release_all_index_buffers
|
|
// Access: Public
|
|
// Description: Releases all datas at once. This will force them
|
|
// to be reloaded into data memory for all GSG's that
|
|
// share this object. Returns the number of datas
|
|
// released.
|
|
////////////////////////////////////////////////////////////////////
|
|
int PreparedGraphicsObjects::
|
|
release_all_index_buffers() {
|
|
MutexHolder holder(_lock);
|
|
|
|
int num_index_buffers = (int)_prepared_index_buffers.size();
|
|
|
|
IndexBuffers::iterator ibci;
|
|
for (ibci = _prepared_index_buffers.begin();
|
|
ibci != _prepared_index_buffers.end();
|
|
++ibci) {
|
|
IndexBufferContext *ibc = (*ibci);
|
|
ibc->_data->clear_prepared(this);
|
|
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
|
|
ibc->_data = (qpGeomPrimitive *)NULL;
|
|
|
|
_released_index_buffers.insert(ibc);
|
|
}
|
|
|
|
_prepared_index_buffers.clear();
|
|
|
|
return num_index_buffers;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::prepare_index_buffer_now
|
|
// Access: Public
|
|
// Description: Immediately creates a new IndexBufferContext for the
|
|
// indicated data and returns it. This assumes that
|
|
// the GraphicsStateGuardian is the currently active
|
|
// rendering context and that it is ready to accept new
|
|
// datas. If this is not necessarily the case, you
|
|
// should use enqueue_index_buffer() instead.
|
|
//
|
|
// Normally, this function is not called directly. Call
|
|
// Data::prepare_now() instead.
|
|
//
|
|
// The IndexBufferContext contains all of the pertinent
|
|
// information needed by the GSG to keep track of this
|
|
// one particular data, and will exist as long as the
|
|
// data is ready to be rendered.
|
|
//
|
|
// When either the Data or the
|
|
// PreparedGraphicsObjects object destructs, the
|
|
// IndexBufferContext will be deleted.
|
|
////////////////////////////////////////////////////////////////////
|
|
IndexBufferContext *PreparedGraphicsObjects::
|
|
prepare_index_buffer_now(qpGeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
|
|
MutexHolder holder(_lock);
|
|
|
|
// 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).
|
|
IndexBufferContext *ibc = gsg->prepare_index_buffer(data);
|
|
|
|
if (ibc != (IndexBufferContext *)NULL) {
|
|
bool prepared = _prepared_index_buffers.insert(ibc).second;
|
|
nassertr(prepared, ibc);
|
|
|
|
// The size has already been counted by
|
|
// GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to
|
|
// count it again here.
|
|
//_total_buffers_pcollector.add_level(ibc->get_data_size_bytes());
|
|
}
|
|
|
|
return ibc;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PreparedGraphicsObjects::update
|
|
// Access: Public
|
|
// Description: This is called by the GraphicsStateGuardian to
|
|
// indicate that it is in a state to load or release
|
|
// textures.
|
|
//
|
|
// Any texture contexts that were previously passed to
|
|
// release_texture() are actually passed to the GSG to
|
|
// be freed at this point; textures that were previously
|
|
// passed to prepare_texture are actually loaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PreparedGraphicsObjects::
|
|
update(GraphicsStateGuardianBase *gsg) {
|
|
MutexHolder holder(_lock);
|
|
|
|
// First, release all the textures, geoms, and buffers awaiting
|
|
// release.
|
|
Textures::iterator tci;
|
|
for (tci = _released_textures.begin();
|
|
tci != _released_textures.end();
|
|
++tci) {
|
|
TextureContext *tc = (*tci);
|
|
gsg->release_texture(tc);
|
|
}
|
|
|
|
_released_textures.clear();
|
|
|
|
Geoms::iterator gci;
|
|
for (gci = _released_geoms.begin();
|
|
gci != _released_geoms.end();
|
|
++gci) {
|
|
GeomContext *gc = (*gci);
|
|
gsg->release_geom(gc);
|
|
}
|
|
|
|
_released_geoms.clear();
|
|
|
|
VertexBuffers::iterator vbci;
|
|
for (vbci = _released_vertex_buffers.begin();
|
|
vbci != _released_vertex_buffers.end();
|
|
++vbci) {
|
|
VertexBufferContext *vbc = (*vbci);
|
|
gsg->release_vertex_buffer(vbc);
|
|
}
|
|
|
|
_released_vertex_buffers.clear();
|
|
|
|
IndexBuffers::iterator ibci;
|
|
for (ibci = _released_index_buffers.begin();
|
|
ibci != _released_index_buffers.end();
|
|
++ibci) {
|
|
IndexBufferContext *ibc = (*ibci);
|
|
gsg->release_index_buffer(ibc);
|
|
}
|
|
|
|
_released_index_buffers.clear();
|
|
|
|
// Now prepare all the textures, geoms, and buffers awaiting
|
|
// preparation.
|
|
EnqueuedTextures::iterator qti;
|
|
for (qti = _enqueued_textures.begin();
|
|
qti != _enqueued_textures.end();
|
|
++qti) {
|
|
Texture *tex = (*qti);
|
|
tex->prepare_now(this, gsg);
|
|
}
|
|
|
|
_enqueued_textures.clear();
|
|
|
|
EnqueuedGeoms::iterator qgi;
|
|
for (qgi = _enqueued_geoms.begin();
|
|
qgi != _enqueued_geoms.end();
|
|
++qgi) {
|
|
Geom *geom = (*qgi);
|
|
geom->prepare_now(this, gsg);
|
|
}
|
|
|
|
_enqueued_geoms.clear();
|
|
|
|
EnqueuedVertexBuffers::iterator qvbi;
|
|
for (qvbi = _enqueued_vertex_buffers.begin();
|
|
qvbi != _enqueued_vertex_buffers.end();
|
|
++qvbi) {
|
|
qpGeomVertexArrayData *data = (*qvbi);
|
|
data->prepare_now(this, gsg);
|
|
}
|
|
|
|
_enqueued_vertex_buffers.clear();
|
|
|
|
EnqueuedIndexBuffers::iterator qibi;
|
|
for (qibi = _enqueued_index_buffers.begin();
|
|
qibi != _enqueued_index_buffers.end();
|
|
++qibi) {
|
|
qpGeomPrimitive *data = (*qibi);
|
|
data->prepare_now(this, gsg);
|
|
}
|
|
|
|
_enqueued_index_buffers.clear();
|
|
}
|