mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
add allow-incomplete-render
This commit is contained in:
parent
8b01f4f426
commit
39dc3d9c3e
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -55,19 +55,6 @@ VertexDataBuffer(const VertexDataBuffer ©) :
|
||||
(*this) = copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
operator = (const VertexDataBuffer ©) {
|
||||
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);
|
||||
}
|
||||
|
@ -21,6 +21,32 @@
|
||||
|
||||
TypeHandle VertexDataBuffer::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
operator = (const VertexDataBuffer ©) {
|
||||
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;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
INLINE VertexDataBuffer();
|
||||
INLINE VertexDataBuffer(size_t size);
|
||||
INLINE VertexDataBuffer(const VertexDataBuffer ©);
|
||||
INLINE void operator = (const VertexDataBuffer ©);
|
||||
void operator = (const VertexDataBuffer ©);
|
||||
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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user