add allow-incomplete-render

This commit is contained in:
David Rose 2007-06-06 21:05:17 +00:00
parent 8b01f4f426
commit 39dc3d9c3e
38 changed files with 599 additions and 284 deletions

View File

@ -22,6 +22,7 @@
#include "transformState.h"
#include "renderState.h"
#include "graphicsStateGuardianBase.h"
#include "config_pgraph.h"
////////////////////////////////////////////////////////////////////
@ -35,10 +36,16 @@ void DrawCullHandler::
record_object(CullableObject *object, const CullTraverser *traverser) {
// Munge vertices as needed for the GSG's requirements, and the
// object's current state.
bool force = !allow_incomplete_render;
Thread *current_thread = traverser->get_current_thread();
object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser);
// And draw the object, then dispense with it.
draw(object, _gsg, current_thread);
if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) {
if (force || object->request_resident()) {
// Now we can immediately draw the object.
draw(object, _gsg, current_thread);
}
}
// Dispense with the object.
delete object;
}

View File

@ -169,8 +169,9 @@ munge_data_impl(const GeomVertexData *data) {
// Access: Protected, Virtual
// Description: Converts a Geom and/or its data as necessary.
////////////////////////////////////////////////////////////////////
bool StandardMunger::
munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, Thread *) {
void StandardMunger::
munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
Thread *) {
int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
int unsupported_bits = geom->get_geom_rendering() & ~supported_geom_rendering;
@ -208,8 +209,6 @@ munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, Thread *) {
vertex_data = new_geom->get_vertex_data();
}
}
return true;
}
////////////////////////////////////////////////////////////////////
@ -217,7 +216,7 @@ munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, Thread *) {
// Access: Protected, Virtual
// Description: Converts a Geom and/or its data as necessary.
////////////////////////////////////////////////////////////////////
bool StandardMunger::
void StandardMunger::
premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
@ -256,8 +255,6 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
vertex_data = new_geom->get_vertex_data();
}
}
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -47,9 +47,9 @@ public:
protected:
virtual CPT(GeomVertexData) munge_data_impl(const GeomVertexData *data);
virtual int compare_to_impl(const GeomMunger *other) const;
virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
virtual void munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Thread *current_thread);
virtual bool premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
virtual void premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
virtual int geom_compare_to_impl(const GeomMunger *other) const;
virtual CPT(RenderState) munge_state_impl(const RenderState *state);

View File

@ -542,7 +542,7 @@ recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
PT(GeomVertexData) modify_vdata = geom->modify_vertex_data();
// Maybe the vdata has animation that we should consider.
CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(current_thread);
CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread);
GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread);
GeomVertexWriter color(modify_vdata, current_thread);

View File

@ -930,9 +930,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
(D3DPT_TRIANGLELIST,
min_vertex, max_vertex,
reader->get_num_primitives(),
reader->get_read_pointer(),
reader->get_read_pointer(true),
index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -949,7 +949,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -990,8 +990,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
(D3DPT_TRIANGLESTRIP,
min_vertex, max_vertex,
reader->get_num_vertices() - 2,
reader->get_read_pointer(), index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
reader->get_read_pointer(true), index_type,
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -1008,7 +1008,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
reader->get_num_vertices() - 2,
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -1050,9 +1050,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
} else {
// Indexed, client arrays, individual triangle strips.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
const unsigned char *vertices = reader->get_read_pointer();
const unsigned char *vertices = reader->get_read_pointer(true);
D3DFORMAT index_type = get_index_type(reader->get_index_type());
unsigned int start = 0;
@ -1087,7 +1087,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
} else {
// Nonindexed, client arrays, individual triangle strips.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
unsigned int start = 0;
@ -1150,9 +1150,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
} else {
// Indexed, client arrays.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
const unsigned char *vertices = reader->get_read_pointer();
const unsigned char *vertices = reader->get_read_pointer(true);
D3DFORMAT index_type = get_index_type(reader->get_index_type());
unsigned int start = 0;
@ -1187,7 +1187,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
} else {
// Nonindexed, client arrays.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
unsigned int start = 0;
@ -1238,9 +1238,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
(D3DPT_LINELIST,
min_vertex, max_vertex,
reader->get_num_primitives(),
reader->get_read_pointer(),
reader->get_read_pointer(true),
index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -1256,7 +1256,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -1299,7 +1299,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}

View File

@ -1493,9 +1493,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
(D3DPT_TRIANGLELIST,
min_vertex, max_vertex,
reader->get_num_primitives(),
reader->get_read_pointer(),
reader->get_read_pointer(true),
index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -1517,7 +1517,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -1568,8 +1568,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
(D3DPT_TRIANGLESTRIP,
min_vertex, max_vertex,
reader->get_num_vertices() - 2,
reader->get_read_pointer(), index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
reader->get_read_pointer(true), index_type,
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -1589,7 +1589,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
reader->get_num_vertices() - 2,
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -1632,9 +1632,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
} else {
// Indexed, client arrays, individual triangle strips.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
const unsigned char *vertices = reader->get_read_pointer();
const unsigned char *vertices = reader->get_read_pointer(true);
D3DFORMAT index_type = get_index_type(reader->get_index_type());
unsigned int start = 0;
@ -1669,7 +1669,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
} else {
// Nonindexed, client arrays, individual triangle strips.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
unsigned int start = 0;
@ -1735,9 +1735,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
} else {
// Indexed, client arrays.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
const unsigned char *vertices = reader->get_read_pointer();
const unsigned char *vertices = reader->get_read_pointer(true);
D3DFORMAT index_type = get_index_type(reader->get_index_type());
unsigned int start = 0;
@ -1772,7 +1772,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
} else {
// Nonindexed, client arrays.
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer();
const unsigned char *array_data = _data_reader->get_array_reader(0)->get_read_pointer(true);
int stride = _data_reader->get_format()->get_array(0)->get_stride();
unsigned int start = 0;
@ -1824,9 +1824,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
(D3DPT_LINELIST,
min_vertex, max_vertex,
reader->get_num_primitives(),
reader->get_read_pointer(),
reader->get_read_pointer(true),
index_type,
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
} else {
@ -1842,7 +1842,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}
@ -1885,7 +1885,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) {
draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
reader->get_first_vertex(),
reader->get_num_vertices(),
_data_reader->get_array_reader(0)->get_read_pointer(),
_data_reader->get_array_reader(0)->get_read_pointer(true),
_data_reader->get_format()->get_array(0)->get_stride());
}
}

View File

@ -2745,12 +2745,12 @@ apply_vertex_buffer(VertexBufferContext *vbc,
if (num_bytes != 0) {
if (gvbc->changed_size(reader) || gvbc->changed_usage_hint(reader)) {
_glBufferData(GL_ARRAY_BUFFER, num_bytes,
reader->get_read_pointer(),
reader->get_read_pointer(true),
get_usage(reader->get_usage_hint()));
} else {
_glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes,
reader->get_read_pointer());
reader->get_read_pointer(true));
}
_data_transferred_pcollector.add_level(num_bytes);
}
@ -2819,7 +2819,7 @@ const unsigned char *CLP(GraphicsStateGuardian)::
setup_array_data(const GeomVertexArrayDataHandle *array_reader) {
if (!_supports_buffers) {
// No support for buffer objects; always render from client.
return array_reader->get_read_pointer();
return array_reader->get_read_pointer(true);
}
if (!vertex_buffers || _geom_display_list != 0 ||
array_reader->get_usage_hint() == Geom::UH_client) {
@ -2833,12 +2833,12 @@ setup_array_data(const GeomVertexArrayDataHandle *array_reader) {
_glBindBuffer(GL_ARRAY_BUFFER, 0);
_current_vbuffer_index = 0;
}
return array_reader->get_read_pointer();
return array_reader->get_read_pointer(true);
}
// Prepare the buffer object and bind it.
VertexBufferContext *vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_read_pointer());
nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_read_pointer(true));
apply_vertex_buffer(vbc, array_reader);
// NULL is the OpenGL convention for the first byte of the buffer object.
@ -2915,12 +2915,12 @@ apply_index_buffer(IndexBufferContext *ibc,
if (num_bytes != 0) {
if (gibc->changed_size(reader) || gibc->changed_usage_hint(reader)) {
_glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes,
reader->get_read_pointer(),
reader->get_read_pointer(true),
get_usage(reader->get_usage_hint()));
} else {
_glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes,
reader->get_read_pointer());
reader->get_read_pointer(true));
}
_data_transferred_pcollector.add_level(num_bytes);
}
@ -2988,7 +2988,7 @@ const unsigned char *CLP(GraphicsStateGuardian)::
setup_primitive(const GeomPrimitivePipelineReader *reader) {
if (!_supports_buffers) {
// No support for buffer objects; always render from client.
return reader->get_read_pointer();
return reader->get_read_pointer(true);
}
if (!vertex_buffers || _geom_display_list != 0 ||
reader->get_usage_hint() == Geom::UH_client) {
@ -3002,12 +3002,12 @@ setup_primitive(const GeomPrimitivePipelineReader *reader) {
_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
_current_ibuffer_index = 0;
}
return reader->get_read_pointer();
return reader->get_read_pointer(true);
}
// Prepare the buffer object and bind it.
IndexBufferContext *ibc = ((GeomPrimitive *)reader->get_object())->prepare_now(get_prepared_objects(), this);
nassertr(ibc != (IndexBufferContext *)NULL, reader->get_read_pointer());
nassertr(ibc != (IndexBufferContext *)NULL, reader->get_read_pointer(true));
apply_index_buffer(ibc, reader);
// NULL is the OpenGL convention for the first byte of the buffer object.

View File

@ -710,6 +710,35 @@ get_num_bytes() const {
return num_bytes;
}
////////////////////////////////////////////////////////////////////
// Function: Geom::request_resident
// Access: Published
// Description: Returns true if all the primitive arrays are
// currently resident in memory. If this returns false,
// the data will be brought back into memory shortly;
// try again later.
//
// This does not also test the Geom's associated
// GeomVertexData. That must be tested separately.
////////////////////////////////////////////////////////////////////
bool Geom::
request_resident() const {
CDReader cdata(_cycler);
bool resident = true;
Primitives::const_iterator pi;
for (pi = cdata->_primitives.begin();
pi != cdata->_primitives.end();
++pi) {
if (!(*pi).get_read_pointer()->request_resident()) {
resident = false;
}
}
return resident;
}
////////////////////////////////////////////////////////////////////
// Function: Geom::transform_vertices
// Access: Published
@ -1078,7 +1107,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
// Get the vertex data, after animation.
CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer();
vertex_data = vertex_data->animate_vertices(current_thread);
vertex_data = vertex_data->animate_vertices(true, current_thread);
// Now actually compute the bounding volume. We do this by using
// calc_tight_bounds to determine our box first.

View File

@ -110,6 +110,8 @@ PUBLISHED:
int get_num_bytes() const;
INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const;
bool request_resident() const;
void transform_vertices(const LMatrix4f &mat);
bool check_valid() const;
bool check_valid(const GeomVertexData *vertex_data) const;

View File

@ -104,10 +104,15 @@ remove_data(const GeomVertexData *data) {
// The assumption is that for a particular geom and a
// particular munger, the result will always be the
// same; so this result may be cached.
//
// If force is false, this may do nothing and return
// false if the vertex data is nonresident. If force is
// true, this will always return true, but it may have
// to block while the vertex data is paged in.
////////////////////////////////////////////////////////////////////
void GeomMunger::
bool GeomMunger::
munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Thread *current_thread) {
bool force, Thread *current_thread) {
CPT(GeomVertexData) source_data = data;
// Look up the munger in the geom's cache--maybe we've recently
@ -123,7 +128,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
} else {
entry = (*ci).second;
geom->_cache_lock.release();
nassertv(entry->_source == geom);
nassertr(entry->_source == geom, false);
// Here's an element in the cache for this computation. Record a
// cache hit, so this element will stay in the cache a while
@ -140,7 +145,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
geom = cdata->_geom_result;
data = cdata->_data_result;
return;
return true;
}
// The cache entry is stale, but we'll recompute it below. Note
@ -149,6 +154,11 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
// compute the same result.
}
if (!force && (!geom->request_resident() || !data->request_resident())) {
// Oh dear, the data isn't resident. We can't munge it, so give up.
return false;
}
// Ok, invoke the munger.
PStatTimer timer(_munge_pcollector, current_thread);
@ -166,7 +176,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
if (!inserted) {
// Some other thread must have beat us to the punch. Never
// mind.
return;
return true;
}
}
@ -180,6 +190,8 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Geom::CDCacheWriter cdata(entry->_cycler, true, current_thread);
cdata->_source = (Geom *)orig_geom.p();
cdata->set_result(geom, data);
return true;
}
////////////////////////////////////////////////////////////////////
@ -255,11 +267,10 @@ munge_data_impl(const GeomVertexData *data) {
// Access: Protected, Virtual
// Description: Converts a Geom and/or its data as necessary.
////////////////////////////////////////////////////////////////////
bool GeomMunger::
void GeomMunger::
munge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &, Thread *) {
// The default implementation does nothing (the work has already
// been done in munge_format_impl() and munge_data_impl()).
return true;
}
////////////////////////////////////////////////////////////////////
@ -331,11 +342,10 @@ premunge_data_impl(const GeomVertexData *data) {
// Access: Protected, Virtual
// Description: Converts a Geom and/or its data as necessary.
////////////////////////////////////////////////////////////////////
bool GeomMunger::
void GeomMunger::
premunge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &) {
// The default implementation does nothing (the work has already
// been done in premunge_format_impl() and premunge_data_impl()).
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -76,8 +76,8 @@ public:
INLINE CPT(GeomVertexData) munge_data(const GeomVertexData *data) const;
void remove_data(const GeomVertexData *data);
void munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Thread *current_thread);
bool munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
bool force, Thread *current_thread);
INLINE CPT(GeomVertexFormat) premunge_format(const GeomVertexFormat *format) const;
INLINE CPT(GeomVertexData) premunge_data(const GeomVertexData *data) const;
@ -96,14 +96,14 @@ protected:
virtual CPT(GeomVertexFormat) munge_format_impl(const GeomVertexFormat *orig,
const GeomVertexAnimationSpec &animation);
virtual CPT(GeomVertexData) munge_data_impl(const GeomVertexData *data);
virtual bool munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
virtual void munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Thread *current_thread);
CPT(GeomVertexFormat) do_premunge_format(const GeomVertexFormat *format);
virtual CPT(GeomVertexFormat) premunge_format_impl(const GeomVertexFormat *orig);
virtual CPT(GeomVertexData) premunge_data_impl(const GeomVertexData *data);
virtual bool premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
virtual void premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
virtual int compare_to_impl(const GeomMunger *other) const;
virtual int geom_compare_to_impl(const GeomMunger *other) const;

View File

@ -666,8 +666,8 @@ get_vertices_reader() const {
// Description:
////////////////////////////////////////////////////////////////////
INLINE const unsigned char *GeomPrimitivePipelineReader::
get_read_pointer() const {
return _vertices_reader->get_read_pointer();
get_read_pointer(bool force) const {
return _vertices_reader->get_read_pointer(force);
}
////////////////////////////////////////////////////////////////////

View File

@ -798,6 +798,39 @@ get_num_bytes() const {
return num_bytes;
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::request_resident
// Access: Published
// Description: Returns true if the primitive data is currently
// resident in memory. If this returns false, the
// primitive data will be brought back into memory
// shortly; try again later.
////////////////////////////////////////////////////////////////////
bool GeomPrimitive::
request_resident() const {
CDReader cdata(_cycler);
bool resident = true;
if (!cdata->_vertices.is_null() &&
!cdata->_vertices.get_read_pointer()->request_resident()) {
resident = false;
}
if (is_composite() && cdata->_got_minmax) {
if (!cdata->_mins.is_null() &&
!cdata->_mins.get_read_pointer()->request_resident()) {
resident = false;
}
if (!cdata->_maxs.is_null() &&
!cdata->_maxs.get_read_pointer()->request_resident()) {
resident = false;
}
}
return resident;
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::output
// Access: Published, Virtual

View File

@ -136,6 +136,8 @@ PUBLISHED:
INLINE int get_data_size_bytes() const;
INLINE UpdateSeq get_modified() const;
bool request_resident() const;
INLINE bool check_valid(const GeomVertexData *vertex_data) const;
virtual void output(ostream &out) const;
@ -346,7 +348,7 @@ public:
bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
INLINE int get_index_stride() const;
INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
INLINE const unsigned char *get_read_pointer() const;
INLINE const unsigned char *get_read_pointer(bool force) const;
INLINE CPTA_int get_ends() const;
INLINE CPT(GeomVertexArrayData) get_mins() const;
INLINE CPT(GeomVertexArrayData) get_maxs() const;

View File

@ -145,6 +145,21 @@ get_modified() const {
return cdata->_modified;
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayData::request_resident
// Access: Published
// Description: Returns true if the vertex data is currently resident
// in memory. If this returns true, the next call to
// get_handle()->get_read_pointer() will probably not
// block. If this returns false, the vertex data will
// be brought back into memory shortly; try again later.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexArrayData::
request_resident() const {
CPT(GeomVertexArrayDataHandle) handle = get_handle();
return (handle->get_read_pointer(false) != (const unsigned char *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayData::get_handle
// Access: Published
@ -379,7 +394,7 @@ get_object() {
////////////////////////////////////////////////////////////////////
INLINE const unsigned char *GeomVertexArrayDataHandle::
get_read_pointer(bool force) const {
check_resident();
mark_used();
return _cdata->_buffer.get_read_pointer(force);
}
@ -453,7 +468,7 @@ get_modified() const {
////////////////////////////////////////////////////////////////////
INLINE string GeomVertexArrayDataHandle::
get_data() const {
check_resident();
mark_used();
return string((const char *)_cdata->_buffer.get_read_pointer(true), _cdata->_buffer.get_size());
}
@ -467,20 +482,19 @@ get_data() const {
////////////////////////////////////////////////////////////////////
INLINE string GeomVertexArrayDataHandle::
get_subdata(size_t start, size_t size) const {
check_resident();
mark_used();
start = min(start, _cdata->_buffer.get_size());
size = min(size, _cdata->_buffer.get_size() - start);
return string((const char *)_cdata->_buffer.get_read_pointer(true) + start, size);
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayDataHandle::check_resident
// Function: GeomVertexArrayDataHandle::mark_used
// Access: Published
// Description: Forces the vertex data into system RAM, if it is not
// already there; also, marks it recently-used.
// Description: Marks the array data recently-used.
////////////////////////////////////////////////////////////////////
void GeomVertexArrayDataHandle::
check_resident() const {
mark_used() const {
_object->set_lru_size(_object->get_lru_size());
}

View File

@ -642,7 +642,7 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
unsigned char *GeomVertexArrayDataHandle::
get_write_pointer() {
nassertr(_writable, NULL);
check_resident();
mark_used();
_cdata->_modified = Geom::get_next_modified();
return _cdata->_buffer.get_write_pointer();
}
@ -655,7 +655,7 @@ get_write_pointer() {
bool GeomVertexArrayDataHandle::
set_num_rows(int n) {
nassertr(_writable, false);
check_resident();
mark_used();
int stride = _object->_array_format->get_stride();
size_t new_size = n * stride;
@ -689,7 +689,7 @@ set_num_rows(int n) {
bool GeomVertexArrayDataHandle::
unclean_set_num_rows(int n) {
nassertr(_writable, false);
check_resident();
mark_used();
int stride = _object->_array_format->get_stride();
size_t new_size = n * stride;
@ -719,8 +719,8 @@ unclean_set_num_rows(int n) {
void GeomVertexArrayDataHandle::
copy_data_from(const GeomVertexArrayDataHandle *other) {
nassertv(_writable);
check_resident();
other->check_resident();
mark_used();
other->mark_used();
_cdata->_buffer.unclean_realloc(other->_cdata->_buffer.get_size());
memcpy(_cdata->_buffer.get_write_pointer(),
@ -747,8 +747,8 @@ copy_subdata_from(size_t to_start, size_t to_size,
const GeomVertexArrayDataHandle *other,
size_t from_start, size_t from_size) {
nassertv(_writable);
check_resident();
other->check_resident();
mark_used();
other->mark_used();
VertexDataBuffer &to_buffer = _cdata->_buffer;
size_t to_buffer_orig_size = to_buffer.get_size();
@ -779,7 +779,7 @@ copy_subdata_from(size_t to_start, size_t to_size,
// Now copy the data.
memcpy(to_buffer.get_write_pointer() + to_start,
other->get_read_pointer() + from_start,
other->get_read_pointer(true) + from_start,
from_size);
_cdata->_modified = Geom::get_next_modified();
@ -798,7 +798,7 @@ copy_subdata_from(size_t to_start, size_t to_size,
void GeomVertexArrayDataHandle::
set_data(const string &data) {
nassertv(_writable);
check_resident();
mark_used();
_cdata->_buffer.unclean_realloc(data.size());
memcpy(_cdata->_buffer.get_write_pointer(), data.data(), data.size());
@ -823,7 +823,7 @@ set_data(const string &data) {
void GeomVertexArrayDataHandle::
set_subdata(size_t start, size_t size, const string &data) {
nassertv(_writable);
check_resident();
mark_used();
VertexDataBuffer &to_buffer = _cdata->_buffer;
size_t to_buffer_orig_size = to_buffer.get_size();

View File

@ -96,6 +96,8 @@ PUBLISHED:
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
INLINE bool request_resident() const;
INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const;
INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread());
@ -258,7 +260,7 @@ public:
INLINE const GeomVertexArrayData *get_object() const;
INLINE GeomVertexArrayData *get_object();
INLINE const unsigned char *get_read_pointer(bool force = true) const;
INLINE const unsigned char *get_read_pointer(bool force) const;
unsigned char *get_write_pointer();
PUBLISHED:
@ -283,7 +285,7 @@ PUBLISHED:
INLINE string get_subdata(size_t start, size_t size) const;
void set_subdata(size_t start, size_t size, const string &data);
INLINE void check_resident() const;
INLINE void mark_used() const;
private:
ReMutexHolder _holder;

View File

@ -415,6 +415,31 @@ set_slider_table(const SliderTable *table) {
cdata->_animated_vertices_modified = UpdateSeq();
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexData::request_resident
// Access: Published
// Description: Returns true if the vertex data is currently resident
// in memory. If this returns false, the vertex data will
// be brought back into memory shortly; try again later.
////////////////////////////////////////////////////////////////////
bool GeomVertexData::
request_resident() const {
CDReader cdata(_cycler);
bool resident = true;
Arrays::const_iterator ai;
for (ai = cdata->_arrays.begin();
ai != cdata->_arrays.end();
++ai) {
if (!(*ai).get_read_pointer()->request_resident()) {
resident = false;
}
}
return resident;
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexData::copy_from
// Access: Published
@ -489,7 +514,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
for (source_i = 0; source_i < num_arrays; ++source_i) {
CPT(GeomVertexArrayData) array_obj = source->get_array(source_i);
CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle();
const unsigned char *array_data = array_handle->get_read_pointer();
const unsigned char *array_data = array_handle->get_read_pointer(true);
const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
int num_columns = source_array_format->get_num_columns();
for (int di = 0; di < num_columns; ++di) {
@ -660,7 +685,7 @@ copy_row_from(int dest_row, const GeomVertexData *source,
CPT(GeomVertexArrayData) source_array_obj = source->get_array(i);
CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle();
const unsigned char *source_array_data = source_array_handle->get_read_pointer();
const unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
const GeomVertexArrayFormat *array_format = source_format->get_array(i);
int stride = array_format->get_stride();
@ -915,9 +940,15 @@ set_color(const Colorf &color, int num_components,
// still return the same pointer, but with its contents
// modified (this is preferred, since it allows the
// graphics backend to update vertex buffers optimally).
//
// If force is false, this method may return immediately
// with stale data, if the vertex data is not completely
// resident. If force is true, this method will never
// return stale data, but may block until the data is
// available.
////////////////////////////////////////////////////////////////////
CPT(GeomVertexData) GeomVertexData::
animate_vertices(Thread *current_thread) const {
animate_vertices(bool force, Thread *current_thread) const {
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_format->get_animation().get_animation_type() != AT_panda) {
@ -948,6 +979,16 @@ animate_vertices(Thread *current_thread) const {
// No changes.
return cdata->_animated_vertices;
}
if (!force && !request_resident()) {
// The vertex data isn't resident. Return the best information
// we've got.
if (cdata->_animated_vertices != (GeomVertexData *)NULL) {
return cdata->_animated_vertices;
}
return this;
}
CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false);
cdataw->_animated_vertices_modified = modified;
((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread);

View File

@ -130,6 +130,8 @@ PUBLISHED:
INLINE int get_num_bytes() const;
INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const;
bool request_resident() const;
void copy_from(const GeomVertexData *source, bool keep_data_objects,
Thread *current_thread = Thread::get_current_thread());
void copy_row_from(int dest_row, const GeomVertexData *source,
@ -146,7 +148,7 @@ PUBLISHED:
set_color(const Colorf &color, int num_components,
NumericType numeric_type, Contents contents) const;
CPT(GeomVertexData) animate_vertices(Thread *current_thread) const;
CPT(GeomVertexData) animate_vertices(bool force, Thread *current_thread) const;
PT(GeomVertexData)
replace_column(InternalName *name, int num_components,

View File

@ -576,7 +576,7 @@ write_with_data(ostream &out, int indent_level,
<< data->get_num_rows() << " rows.\n";
for (size_t i = 0; i < _arrays.size(); i++) {
CPT(GeomVertexArrayDataHandle) handle = data->get_array(i)->get_handle();
const unsigned char *array_data = handle->get_read_pointer();
const unsigned char *array_data = handle->get_read_pointer(true);
indent(out, indent_level)
<< "Array " << i << " (" << (void *)array_data << ", "
<< *_arrays[i] << "):\n";

View File

@ -508,7 +508,7 @@ get_packer() const {
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexReader::
set_pointer(int row) {
_pointer_begin = _handle->get_read_pointer();
_pointer_begin = _handle->get_read_pointer(true);
_pointer_end = _pointer_begin + _handle->get_data_size_bytes();
quick_set_pointer(row);
}
@ -526,7 +526,7 @@ quick_set_pointer(int row) {
#if defined(_DEBUG)
// Make sure we still have the same pointer as stored in the array.
nassertv(_pointer_begin == _handle->get_read_pointer());
nassertv(_pointer_begin == _handle->get_read_pointer(true));
#endif
_pointer = _pointer_begin + _packer->_column->get_start() + _stride * row;
@ -547,7 +547,7 @@ inc_pointer() {
#if defined(_DEBUG)
nassertr(_pointer < _pointer_end, empty_buffer);
// Make sure we still have the same pointer as stored in the array.
nassertr(_pointer_begin == _handle->get_read_pointer(), empty_buffer);
nassertr(_pointer_begin == _handle->get_read_pointer(true), empty_buffer);
nassertr(_pointer < _pointer_begin + _handle->get_data_size_bytes(), empty_buffer);
#endif

View File

@ -48,5 +48,5 @@ get_page(int n) const {
INLINE VertexDataPage *VertexDataBook::
create_new_page(size_t size) {
size_t page_size = ((size + _block_size - 1) / _block_size) * _block_size;
return new VertexDataPage(page_size);
return new VertexDataPage(this, page_size);
}

View File

@ -49,21 +49,26 @@ alloc(size_t size) {
MutexHolder holder(_lock);
// First, try to allocate from the last page that worked; then
// continue to the end of the list.
// continue to the end of the list. We consider only pages that are
// currently resident (or that are empty), to minimize unnecessary
// swapping.
size_t pi = _next_pi;
while (pi < _pages.size()) {
VertexDataBlock *block = _pages[pi]->alloc(size);
if (block != (VertexDataBlock *)NULL) {
_next_pi = pi;
return block;
}
if (_pages[pi]->is_empty()) {
// This page is empty, but must have been too small. Create a
// new page in its place.
delete _pages[pi];
_pages[pi] = create_new_page(size);
if (_pages[pi]->get_ram_class() == VertexDataPage::RC_resident ||
_pages[pi]->is_empty()) {
VertexDataBlock *block = _pages[pi]->alloc(size);
return block;
if (block != (VertexDataBlock *)NULL) {
_next_pi = pi;
return block;
}
if (_pages[pi]->is_empty()) {
// This page is empty, but must have been too small. Create a
// new page in its place.
delete _pages[pi];
_pages[pi] = create_new_page(size);
VertexDataBlock *block = _pages[pi]->alloc(size);
return block;
}
}
++pi;
}
@ -72,17 +77,20 @@ alloc(size_t size) {
pi = 0;
_next_pi = min(_next_pi, _pages.size());
while (pi < _next_pi) {
VertexDataBlock *block = _pages[pi]->alloc(size);
if (block != (VertexDataBlock *)NULL) {
_next_pi = pi;
return block;
}
if (_pages[pi]->is_empty()) {
// This page is empty, but must have been too small. Create a
// new page in its place.
delete _pages[pi];
_pages[pi] = create_new_page(size);
return _pages[pi]->alloc(size);
if (_pages[pi]->get_ram_class() == VertexDataPage::RC_resident ||
_pages[pi]->is_empty()) {
VertexDataBlock *block = _pages[pi]->alloc(size);
if (block != (VertexDataBlock *)NULL) {
_next_pi = pi;
return block;
}
if (_pages[pi]->is_empty()) {
// This page is empty, but must have been too small. Create a
// new page in its place.
delete _pages[pi];
_pages[pi] = create_new_page(size);
return _pages[pi]->alloc(size);
}
}
++pi;
}
@ -95,6 +103,76 @@ alloc(size_t size) {
return block;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBook::count_total_page_size
// Access: Published
// Description: Returns the total size of all bytes owned by all
// pages owned by this book.
////////////////////////////////////////////////////////////////////
size_t VertexDataBook::
count_total_page_size() const {
size_t total = 0;
Pages::const_iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
total += (*pi)->get_max_size();
}
return total;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBook::count_total_page_size
// Access: Published
// Description: Returns the total size of all bytes owned by all
// pages owned by this book that have the indicated ram
// class.
////////////////////////////////////////////////////////////////////
size_t VertexDataBook::
count_total_page_size(VertexDataPage::RamClass ram_class) const {
size_t total = 0;
Pages::const_iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
if ((*pi)->get_ram_class() == ram_class) {
total += (*pi)->get_max_size();
}
}
return total;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBook::count_allocated_size
// Access: Published
// Description: Returns the total size of all bytes allocated within
// pages owned by this book.
////////////////////////////////////////////////////////////////////
size_t VertexDataBook::
count_allocated_size() const {
size_t total = 0;
Pages::const_iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
total += (*pi)->get_total_size();
}
return total;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBook::count_allocated_size
// Access: Published
// Description: Returns the total size of all bytes allocated within
// pages owned by this book that have the indicated ram
// class.
////////////////////////////////////////////////////////////////////
size_t VertexDataBook::
count_allocated_size(VertexDataPage::RamClass ram_class) const {
size_t total = 0;
Pages::const_iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
if ((*pi)->get_ram_class() == ram_class) {
total += (*pi)->get_total_size();
}
}
return total;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBook::save_to_disk
// Access: Published

View File

@ -41,6 +41,11 @@ PUBLISHED:
INLINE int get_num_pages() const;
INLINE VertexDataPage *get_page(int n) const;
size_t count_total_page_size() const;
size_t count_total_page_size(VertexDataPage::RamClass ram_class) const;
size_t count_allocated_size() const;
size_t count_allocated_size(VertexDataPage::RamClass ram_class) const;
void save_to_disk();
private:

View File

@ -55,19 +55,6 @@ VertexDataBuffer(const VertexDataBuffer &copy) :
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void VertexDataBuffer::
operator = (const VertexDataBuffer &copy) {
MutexHolder holder(_lock);
do_unclean_realloc(copy.get_size());
memcpy(_resident_data, copy.get_read_pointer(true), _size);
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::Destructor
// Access: Public
@ -93,14 +80,16 @@ INLINE const unsigned char *VertexDataBuffer::
get_read_pointer(bool force) const {
MutexHolder holder(_lock);
if (_block != (VertexDataBlock *)NULL) {
// We don't necessarily need to page the buffer all the way into
// independent status; it's sufficient just to return the block's
// pointer, which will force its page to resident status.
return _block->get_pointer(force);
if (_resident_data != (unsigned char *)NULL || _size == 0) {
return _resident_data;
}
return _resident_data;
nassertr(_block != (VertexDataBlock *)NULL, NULL);
// We don't necessarily need to page the buffer all the way into
// independent status; it's sufficient just to return the block's
// pointer, which will force its page to resident status.
return _block->get_pointer(force);
}
////////////////////////////////////////////////////////////////////
@ -112,8 +101,7 @@ INLINE unsigned char *VertexDataBuffer::
get_write_pointer() {
MutexHolder holder(_lock);
if (_block != (VertexDataBlock *)NULL ||
_resident_data == (unsigned char *)NULL) {
if (_resident_data == (unsigned char *)NULL && _size != 0) {
do_page_in();
}
return _resident_data;
@ -205,19 +193,3 @@ swap(VertexDataBuffer &other) {
other._size = size;
other._block = block;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::do_unclean_realloc
// Access: Private
// Description: Changes the size of the buffer, without regard to
// preserving its data. The buffer may contain random
// data after this call.
//
// Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
INLINE void VertexDataBuffer::
do_unclean_realloc(size_t size) {
// At the moment, this has no distinct definition, since the system
// realloc() call doesn't have an unclean variant.
do_clean_realloc(size);
}

View File

@ -21,6 +21,32 @@
TypeHandle VertexDataBuffer::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void VertexDataBuffer::
operator = (const VertexDataBuffer &copy) {
MutexHolder holder(_lock);
MutexHolder holder2(copy._lock);
if (_resident_data != (unsigned char *)NULL) {
nassertv(_size != 0);
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
free(_resident_data);
_resident_data = NULL;
}
if (copy._resident_data != (unsigned char *)NULL) {
nassertv(copy._size != 0);
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)copy._size);
_resident_data = (unsigned char *)malloc(copy._size);
memcpy(_resident_data, copy._resident_data, copy._size);
}
_size = copy._size;
_block = copy._block;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::do_clean_realloc
// Access: Private
@ -35,32 +61,56 @@ void VertexDataBuffer::
do_clean_realloc(size_t size) {
if (size != _size) {
if (size == 0) {
// If we're going to size 0, we don't necessarily need to page
// in first. But if we're paged out, discard the page.
_block = NULL;
if (_resident_data != (unsigned char *)NULL) {
free(_resident_data);
_resident_data = NULL;
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
}
_block = NULL;
do_unclean_realloc(size);
return;
}
// Page in if we're currently paged out.
if (_size != 0 && _resident_data == (unsigned char *)NULL) {
do_page_in();
}
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size - (int)_size);
if (_size == 0) {
nassertv(_resident_data == (unsigned char *)NULL);
_resident_data = (unsigned char *)malloc(size);
} else {
// Page in if we're currently paged out.
if (_block != (VertexDataBlock *)NULL ||
_resident_data == (unsigned char *)NULL) {
do_page_in();
}
if (_resident_data == (unsigned char *)NULL) {
_resident_data = (unsigned char *)malloc(size);
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size);
} else {
_resident_data = (unsigned char *)::realloc(_resident_data, size);
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size - (int)_size);
}
nassertv(_resident_data != (unsigned char *)NULL);
_resident_data = (unsigned char *)realloc(_resident_data, size);
}
nassertv(_resident_data != (unsigned char *)NULL);
_size = size;
}
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataBuffer::do_unclean_realloc
// Access: Private
// Description: Changes the size of the buffer, without regard to
// preserving its data. The buffer may contain random
// data after this call.
//
// Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void VertexDataBuffer::
do_unclean_realloc(size_t size) {
if (size != _size || _resident_data == (unsigned char *)NULL) {
// If we're paged out, discard the page.
_block = NULL;
if (_resident_data != (unsigned char *)NULL) {
nassertv(_size != 0);
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
free(_resident_data);
_resident_data = NULL;
_size = 0;
}
if (size != 0) {
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size);
nassertv(_resident_data == (unsigned char *)NULL);
_resident_data = (unsigned char *)malloc(size);
}
_size = size;
@ -93,9 +143,9 @@ do_page_out(VertexDataBook &book) {
nassertv(pointer != (unsigned char *)NULL);
memcpy(pointer, _resident_data, _size);
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
free(_resident_data);
_resident_data = NULL;
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
}
////////////////////////////////////////////////////////////////////
@ -109,17 +159,16 @@ do_page_out(VertexDataBook &book) {
////////////////////////////////////////////////////////////////////
void VertexDataBuffer::
do_page_in() {
if (_block == (VertexDataBlock *)NULL) {
if (_resident_data != (unsigned char *)NULL || _size == 0) {
// We're already paged in.
return;
}
nassertv(_resident_data == (unsigned char *)NULL);
nassertv(_block != (VertexDataBlock *)NULL);
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
_resident_data = (unsigned char *)malloc(_size);
nassertv(_resident_data != (unsigned char *)NULL);
get_class_type().inc_memory_usage(TypeHandle::MC_array, _size);
memcpy(_resident_data, _block->get_pointer(true), _size);
_block = NULL;
}

View File

@ -65,7 +65,7 @@ public:
INLINE VertexDataBuffer();
INLINE VertexDataBuffer(size_t size);
INLINE VertexDataBuffer(const VertexDataBuffer &copy);
INLINE void operator = (const VertexDataBuffer &copy);
void operator = (const VertexDataBuffer &copy);
INLINE ~VertexDataBuffer();
INLINE const unsigned char *get_read_pointer(bool force) const;
@ -82,7 +82,7 @@ public:
private:
void do_clean_realloc(size_t size);
INLINE void do_unclean_realloc(size_t size);
void do_unclean_realloc(size_t size);
void do_page_out(VertexDataBook &book);
void do_page_in();

View File

@ -72,14 +72,13 @@ get_first_block() const {
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataPage::get_total_page_size
// Access: Published, Static
// Description: Returns the byte count allocated to all
// VertexDataPages currently in existance.
// Function: VertexDataPage::get_book
// Access: Published
// Description: Returns a pointer to the book that owns this page.
////////////////////////////////////////////////////////////////////
INLINE size_t VertexDataPage::
get_total_page_size() {
return _total_page_size;
INLINE VertexDataBook *VertexDataPage::
get_book() const {
return _book;
}
////////////////////////////////////////////////////////////////////
@ -155,7 +154,9 @@ get_page_data(bool force) {
make_resident_now();
} else {
request_ram_class(RC_resident);
return NULL;
if (_ram_class != RC_resident) {
return NULL;
}
}
}

View File

@ -19,6 +19,7 @@
#include "vertexDataPage.h"
#include "configVariableInt.h"
#include "vertexDataSaveFile.h"
#include "vertexDataBook.h"
#include "pStatTimer.h"
#include "mutexHolder.h"
@ -68,13 +69,13 @@ SimpleLru *VertexDataPage::_global_lru[RC_end_of_list] = {
&VertexDataPage::_disk_lru,
};
size_t VertexDataPage::_total_page_size = 0;
VertexDataSaveFile *VertexDataPage::_save_file;
PStatCollector VertexDataPage::_vdata_compress_pcollector("*:Vertex Data:Compress");
PStatCollector VertexDataPage::_vdata_decompress_pcollector("*:Vertex Data:Decompress");
PStatCollector VertexDataPage::_vdata_save_pcollector("*:Vertex Data:Save");
PStatCollector VertexDataPage::_vdata_restore_pcollector("*:Vertex Data:Restore");
PStatCollector VertexDataPage::_thread_wait_pcollector("*:Wait:Idle");
TypeHandle VertexDataPage::_type_handle;
@ -84,12 +85,18 @@ TypeHandle VertexDataPage::_type_handle;
// Description:
////////////////////////////////////////////////////////////////////
VertexDataPage::
VertexDataPage(size_t page_size) : SimpleAllocator(page_size), SimpleLruPage(page_size) {
_page_data = new unsigned char[get_max_size()];
VertexDataPage(VertexDataBook *book, size_t page_size) :
SimpleAllocator(page_size),
SimpleLruPage(page_size),
_book(book)
{
nassertv(page_size == get_max_size());
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)page_size);
_page_data = new unsigned char[page_size];
_size = page_size;
_uncompressed_size = _size;
_total_page_size += _size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
_pending_ram_class = RC_resident;
set_ram_class(RC_resident);
}
@ -101,11 +108,20 @@ VertexDataPage(size_t page_size) : SimpleAllocator(page_size), SimpleLruPage(pag
////////////////////////////////////////////////////////////////////
VertexDataPage::
~VertexDataPage() {
_total_page_size -= _size;
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
MutexHolder holder(_lock);
{
MutexHolder holder2(_tlock);
if (_pending_ram_class != _ram_class) {
nassertv(_thread != (PageThread *)NULL);
_thread->remove_page(this);
}
}
if (_page_data != NULL) {
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
delete[] _page_data;
_size = 0;
}
}
@ -121,15 +137,11 @@ VertexDataPage::
VertexDataBlock *VertexDataPage::
alloc(size_t size) {
MutexHolder holder(_lock);
if (_ram_class != RC_resident) {
make_resident_now();
}
VertexDataBlock *block = (VertexDataBlock *)SimpleAllocator::alloc(size);
if (block != (VertexDataBlock *)NULL) {
// When we allocate a new block within the page, we have to clear
// the disk cache (since we have just invalidated it).
if (block != (VertexDataBlock *)NULL && _ram_class != RC_disk) {
// When we allocate a new block within a resident page, we have to
// clear the disk cache (since we have just invalidated it).
_saved_block.clear();
}
@ -269,15 +281,11 @@ make_resident() {
}
nassertv(dest_len == _uncompressed_size);
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size -= _size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_uncompressed_size - (int)_size);
delete[] _page_data;
_page_data = new_data;
_size = _uncompressed_size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size += _size;
#endif
set_lru_size(_size);
@ -329,16 +337,11 @@ make_compressed() {
unsigned char *new_data = new unsigned char[buffer_size];
memcpy(new_data, buffer, buffer_size);
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size -= _size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)buffer_size - (int)_size);
delete[] _page_data;
_page_data = new_data;
_size = buffer_size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size += _size;
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Compressed " << *this << " from " << _uncompressed_size
@ -376,8 +379,6 @@ make_disk() {
}
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size -= _size;
delete[] _page_data;
_page_data = NULL;
_size = 0;
@ -454,12 +455,11 @@ do_restore_from_disk() {
nassert_raise("read error");
}
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)buffer_size);
nassertv(_page_data == (unsigned char *)NULL);
_page_data = new_data;
_size = buffer_size;
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
_total_page_size += _size;
set_lru_size(_size);
if (_saved_block->get_compressed()) {
set_ram_class(RC_compressed);
@ -501,7 +501,11 @@ request_ram_class(RamClass ram_class) {
case RC_disk:
make_disk();
break;
case RC_end_of_list:
break;
}
_pending_ram_class = ram_class;
return;
}
@ -580,12 +584,15 @@ add_page(VertexDataPage *page, RamClass ram_class) {
////////////////////////////////////////////////////////////////////
void VertexDataPage::PageThread::
remove_page(VertexDataPage *page) {
nassertv(page != (VertexDataPage *)NULL);
if (page == _working_page) {
// Oops, the thread is currently working on this one. We'll have
// to wait for the thread to finish.
page->_lock.release();
while (page == _working_page) {
_working_cvar.wait();
}
page->_lock.lock();
return;
}
@ -621,6 +628,7 @@ thread_main() {
_tlock.release();
return;
}
PStatTimer timer(_thread_wait_pcollector);
_pending_cvar.wait();
}
@ -650,6 +658,9 @@ thread_main() {
case RC_disk:
_working_page->make_disk();
break;
case RC_end_of_list:
break;
}
}

View File

@ -30,6 +30,7 @@
#include "mutexHolder.h"
#include "pdeque.h"
class VertexDataBook;
class VertexDataBlock;
////////////////////////////////////////////////////////////////////
@ -40,8 +41,9 @@ class VertexDataBlock;
// cache file, if necessary.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA VertexDataPage : public SimpleAllocator, public SimpleLruPage {
public:
VertexDataPage(VertexDataBook *book, size_t page_size);
PUBLISHED:
VertexDataPage(size_t page_size);
~VertexDataPage();
// These are used to indicate the current residency state of the
@ -62,7 +64,8 @@ PUBLISHED:
VertexDataBlock *alloc(size_t size);
INLINE VertexDataBlock *get_first_block() const;
INLINE static size_t get_total_page_size();
INLINE VertexDataBook *get_book() const;
INLINE static SimpleLru *get_global_lru(RamClass rclass);
INLINE static SimpleLru *get_pending_lru();
INLINE static VertexDataSaveFile *get_save_file();
@ -126,19 +129,21 @@ private:
RamClass _pending_ram_class; // Protected by _tlock.
VertexDataBook *_book; // never changes.
static SimpleLru _resident_lru;
static SimpleLru _compressed_lru;
static SimpleLru _disk_lru;
static SimpleLru _pending_lru;
static SimpleLru *_global_lru[RC_end_of_list];
static size_t _total_page_size;
static VertexDataSaveFile *_save_file;
static PStatCollector _vdata_compress_pcollector;
static PStatCollector _vdata_decompress_pcollector;
static PStatCollector _vdata_save_pcollector;
static PStatCollector _vdata_restore_pcollector;
static PStatCollector _thread_wait_pcollector;
public:
static TypeHandle get_class_type() {

View File

@ -894,7 +894,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
PT(Geom) geom = orig_geom->make_copy();
// Ensure that any vertex animation has been applied.
geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(current_thread));
geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread));
// Now get a modifiable pointer to the vertex data in the new
// Geom. This will actually perform a deep copy of the vertex

View File

@ -319,6 +319,15 @@ ConfigVariableString default_model_extension
"Panda's loader; new code should probably give the correct name "
"for each model file they intend to load."));
ConfigVariableBool allow_incomplete_render
("allow-incomplete-render", false,
PRC_DESC("When this is true, the frame may be rendered even if some of the "
"geometry in the scene has been paged out. The nonresident "
"geometry will be rendered as soon as it can be paged back in, "
"which may be several frames in the future. When this is false, "
"geometry is always paged in when needed, holding up the frame "
"render if necessary."));
////////////////////////////////////////////////////////////////////
// Function: init_libpgraph
// Description: Initializes the library. This must be called at

View File

@ -69,6 +69,7 @@ extern ConfigVariableBool m_dual_flash;
extern ConfigVariableList load_file_type;
extern ConfigVariableString default_model_extension;
extern ConfigVariableBool allow_incomplete_render;
extern EXPCL_PANDA void init_libpgraph();

View File

@ -98,6 +98,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
static const Colorf flash_multisample_color(0.78f, 0.05f, 0.81f, 1.0f);
static const Colorf flash_dual_color(0.92f, 0.01f, 0.01f, 1.0f);
bool force = !allow_incomplete_render;
Thread *current_thread = traverser->get_current_thread();
// Check to see if there's a special transparency setting.
@ -167,15 +168,18 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
get_dual_transparent_state_decals() :
get_dual_transparent_state();
transparent_part->_state = state->compose(transparent_state);
transparent_part->munge_geom
(_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
traverser);
CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
nassertv(bin != (CullBin *)NULL);
if (transparent_part->munge_geom
(_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
traverser, force)) {
CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
nassertv(bin != (CullBin *)NULL);
#ifndef NDEBUG
check_flash_bin(transparent_part->_state, bin);
check_flash_bin(transparent_part->_state, bin);
#endif
bin->add_object(transparent_part, current_thread);
if (force || transparent_part->request_resident()) {
bin->add_object(transparent_part, current_thread);
}
}
}
// Now we can draw the opaque part, with decals. This will
@ -208,8 +212,11 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
// Munge vertices as needed for the GSG's requirements, and the
// object's current state.
object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser);
bin->add_object(object, current_thread);
if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) {
if (force || object->request_resident()) {
bin->add_object(object, current_thread);
}
}
}
////////////////////////////////////////////////////////////////////

View File

@ -130,6 +130,26 @@ draw(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
_geom->draw(gsg, _munger, _munged_data, current_thread);
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::request_resident
// Access: Published
// Description: Returns true if all the data necessary to render this
// object is currently resident in memory. If this
// returns false, the data will be brought back into
// memory shortly; try again later.
////////////////////////////////////////////////////////////////////
INLINE bool CullableObject::
request_resident() const {
bool resident = true;
if (!_geom->request_resident()) {
resident = false;
}
if (!_munged_data->request_resident()) {
resident = false;
}
return resident;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::flush_level
// Access: Public, Static

View File

@ -50,10 +50,16 @@ TypeHandle CullableObject::_type_handle;
// Access: Public
// Description: Uses the indicated GeomMunger to transform the geom
// and/or its vertices.
//
// If force is false, this may do nothing and return
// false if the vertex data is nonresident. If force is
// true, this will always return true, but it may have
// to block while the vertex data is paged in.
////////////////////////////////////////////////////////////////////
void CullableObject::
bool CullableObject::
munge_geom(GraphicsStateGuardianBase *gsg,
GeomMunger *munger, const CullTraverser *traverser) {
GeomMunger *munger, const CullTraverser *traverser,
bool force) {
Thread *current_thread = traverser->get_current_thread();
if (_geom != (Geom *)NULL) {
_munger = munger;
@ -65,7 +71,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
{
GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
data_reader.check_array_readers();
nassertv(geom_reader.check_valid(&data_reader));
nassertr(geom_reader.check_valid(&data_reader), false);
}
#endif // _DEBUG
@ -94,7 +100,9 @@ munge_geom(GraphicsStateGuardianBase *gsg,
<< hex << geom_rendering << ", unsupported: "
<< (unsupported_bits & Geom::GR_point_bits) << dec << "\n";
}
munge_points_to_quads(traverser);
if (!munge_points_to_quads(traverser, force)) {
return false;
}
}
bool cpu_animated = false;
@ -104,20 +112,24 @@ munge_geom(GraphicsStateGuardianBase *gsg,
// the vertices in the CPU--and we have to do it before we call
// munge_geom(), which might lose the tangent and binormal.
CPT(GeomVertexData) animated_vertices =
_munged_data->animate_vertices(current_thread);
_munged_data->animate_vertices(force, current_thread);
if (animated_vertices != _munged_data) {
cpu_animated = true;
_munged_data = animated_vertices;
}
munge_texcoord_light_vector(traverser);
if (!munge_texcoord_light_vector(traverser, force)) {
return false;
}
}
// Now invoke the munger to ensure the resulting geometry is in
// a GSG-friendly form.
munger->munge_geom(_geom, _munged_data, current_thread);
if (!munger->munge_geom(_geom, _munged_data, force, current_thread)) {
return false;
}
StateMunger *state_munger;
DCAST_INTO_V(state_munger, munger);
DCAST_INTO_R(state_munger, munger, false);
_state = state_munger->munge_state(_state);
if (!cpu_animated) {
@ -126,7 +138,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
// animation in hardware--then we have to calculate that
// animation now.
CPT(GeomVertexData) animated_vertices =
_munged_data->animate_vertices(current_thread);
_munged_data->animate_vertices(force, current_thread);
if (animated_vertices != _munged_data) {
cpu_animated = true;
_munged_data = animated_vertices;
@ -151,11 +163,13 @@ munge_geom(GraphicsStateGuardianBase *gsg,
if (_next != (CullableObject *)NULL) {
if (_next->_state != (RenderState *)NULL) {
_next->munge_geom(gsg, gsg->get_geom_munger(_next->_state, current_thread),
traverser);
traverser, force);
} else {
_next->munge_geom(gsg, munger, traverser);
_next->munge_geom(gsg, munger, traverser, force);
}
}
return true;
}
////////////////////////////////////////////////////////////////////
@ -193,8 +207,12 @@ output(ostream &out) const {
//
// This may replace _geom, _munged_data, and _state.
////////////////////////////////////////////////////////////////////
void CullableObject::
munge_points_to_quads(const CullTraverser *traverser) {
bool CullableObject::
munge_points_to_quads(const CullTraverser *traverser, bool force) {
if (!force && !_munged_data->request_resident()) {
return false;
}
Thread *current_thread = traverser->get_current_thread();
PStatTimer timer(_munge_sprites_pcollector, current_thread);
_sw_sprites_pcollector.add_level(_munged_data->get_num_rows());
@ -462,8 +480,8 @@ munge_points_to_quads(const CullTraverser *traverser) {
++vi;
}
nassertv(vi == orig_verts);
nassertv(new_data->get_num_rows() == new_verts);
nassertr(vi == orig_verts, false);
nassertr(new_data->get_num_rows() == new_verts, false);
}
PT(Geom) new_geom = new Geom(new_data);
@ -508,7 +526,7 @@ munge_points_to_quads(const CullTraverser *traverser) {
GeomVertexReader index(primitive->get_vertices(), 0, current_thread);
for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
unsigned int v = index.get_data1i();
nassertv(v < (unsigned int)orig_verts);
nassertr(v < (unsigned int)orig_verts, false);
(*vi) = v;
}
} else {
@ -516,7 +534,7 @@ munge_points_to_quads(const CullTraverser *traverser) {
unsigned int first_vertex = primitive->get_first_vertex();
for (int i = 0; i < num_vertices; ++i) {
unsigned int v = i + first_vertex;
nassertv(v < (unsigned int)orig_verts);
nassertr(v < (unsigned int)orig_verts, false);
vertices[i] = v;
}
}
@ -540,7 +558,7 @@ munge_points_to_quads(const CullTraverser *traverser) {
GeomVertexWriter index(new_index, 0);
for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
int new_vi = (*vi) * 4;
nassertv(new_vi + 3 < new_prim_verts);
nassertr(new_vi + 3 < new_prim_verts, false);
index.set_data1i(new_vi);
index.set_data1i(new_vi + 1);
index.set_data1i(new_vi + 2);
@ -561,6 +579,8 @@ munge_points_to_quads(const CullTraverser *traverser) {
_geom = new_geom.p();
_munged_data = new_data;
return true;
}
////////////////////////////////////////////////////////////////////
@ -571,29 +591,24 @@ munge_points_to_quads(const CullTraverser *traverser) {
//
// This may replace _geom, _munged_data, and _state.
////////////////////////////////////////////////////////////////////
void CullableObject::
munge_texcoord_light_vector(const CullTraverser *traverser) {
bool CullableObject::
munge_texcoord_light_vector(const CullTraverser *traverser, bool force) {
Thread *current_thread = traverser->get_current_thread();
PStatTimer timer(_munge_light_vector_pcollector, current_thread);
if (_net_transform->is_singular()) {
// If we're under a singular transform, never mind.
return;
return true;
}
/*
CPT(TransformState) net_transform =
traverser->get_camera_transform()->compose(_modelview_transform);
*/
if (!_munged_data->has_column(InternalName::get_vertex()) ||
!_munged_data->has_column(InternalName::get_normal())) {
// No vertex or normal; can't compute light vector.
return;
return true;
}
CPT(TexGenAttrib) tex_gen = _state->get_tex_gen();
nassertv(tex_gen != (TexGenAttrib *)NULL);
nassertr(tex_gen != (TexGenAttrib *)NULL, false);
const TexGenAttrib::LightVectors &light_vectors = tex_gen->get_light_vectors();
TexGenAttrib::LightVectors::const_iterator lvi;
@ -609,19 +624,12 @@ munge_texcoord_light_vector(const CullTraverser *traverser) {
if (attrib != (RenderAttrib *)NULL) {
CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
light = la->get_most_important_light();
/*
if (!light.is_empty()) {
// Remove that light, now that we're accounting for it in
// the normal map.
_state->set_attrib(la->remove_on_light(light));
}
*/
}
}
if (!light.is_empty()) {
string source_name = tex_gen->get_source_name(stage);
Light *light_obj = light.node()->as_light();
nassertv(light_obj != (Light *)NULL);
nassertr(light_obj != (Light *)NULL, false);
// Determine the names of the tangent and binormal columns
// associated with the stage's texcoord name.
@ -632,6 +640,12 @@ munge_texcoord_light_vector(const CullTraverser *traverser) {
if (_munged_data->has_column(tangent_name) &&
_munged_data->has_column(binormal_name)) {
if (!force && !_munged_data->request_resident()) {
// The data isn't resident; give up.
return false;
}
// Create a new column for the new texcoords.
PT(GeomVertexData) new_data = _munged_data->replace_column
(texcoord_name, 3, Geom::NT_float32, Geom::C_texcoord);
@ -668,6 +682,8 @@ munge_texcoord_light_vector(const CullTraverser *traverser) {
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -61,11 +61,13 @@ public:
INLINE bool has_decals() const;
void munge_geom(GraphicsStateGuardianBase *gsg,
GeomMunger *munger, const CullTraverser *traverser);
bool munge_geom(GraphicsStateGuardianBase *gsg,
GeomMunger *munger, const CullTraverser *traverser,
bool force);
INLINE void draw(GraphicsStateGuardianBase *gsg,
Thread *current_thread);
INLINE bool request_resident() const;
INLINE static void flush_level();
public:
@ -85,8 +87,8 @@ public:
CullableObject *_next;
private:
void munge_points_to_quads(const CullTraverser *traverser);
void munge_texcoord_light_vector(const CullTraverser *traverser);
bool munge_points_to_quads(const CullTraverser *traverser, bool force);
bool munge_texcoord_light_vector(const CullTraverser *traverser, bool force);
static CPT(RenderState) get_flash_cpu_state();
static CPT(RenderState) get_flash_hardware_state();

View File

@ -326,7 +326,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
CPT(Geom) geom = (*gi)._geom.get_read_pointer();
geom->calc_tight_bounds(min_point, max_point, found_any,
geom->get_vertex_data(current_thread)->animate_vertices(current_thread),
geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread),
!next_transform->is_identity(), mat,
current_thread);
}