Various optimizations to reduce performance overhead of rendering

This commit is contained in:
rdb 2017-02-21 02:20:06 +01:00
parent f6e2e2ea05
commit edb83fe89a
37 changed files with 537 additions and 317 deletions

View File

@ -53,7 +53,7 @@ inc_memory_usage(MemoryClass memory_class, size_t size) {
// cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " <<
// rnode->_memory_usage[memory_class] << "\n";
if (rnode->_memory_usage[memory_class] < 0) {
cerr << "Memory usage overflow for type " << *this << ".\n";
cerr << "Memory usage overflow for type " << rnode->_name << ".\n";
abort();
}
}
@ -98,7 +98,7 @@ allocate_array(size_t size) {
assert(rnode != (TypeRegistryNode *)NULL);
AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)alloc_size);
if (rnode->_memory_usage[MC_array] < 0) {
cerr << "Memory usage overflow for type " << *this << ".\n";
cerr << "Memory usage overflow for type " << rnode->_name << ".\n";
abort();
}
}

View File

@ -23,6 +23,19 @@ freshen_derivations() {
}
}
/**
* Returns the pointer to the global TypeRegistry object.
*/
INLINE TypeRegistry *TypeRegistry::
ptr() {
// It's OK that we don't acquire the lock, because we guarantee that this is
// called at static init time.
if (_global_pointer == NULL) {
init_global_pointer();
}
return _global_pointer;
}
/**
* Ensures the lock pointer has been allocated.
*/

View File

@ -488,20 +488,6 @@ write(ostream &out) const {
_lock->release();
}
/**
* Returns the pointer to the global TypeRegistry object.
*/
TypeRegistry *TypeRegistry::
ptr() {
init_lock();
_lock->acquire();
if (_global_pointer == NULL) {
init_global_pointer();
}
_lock->release();
return _global_pointer;
}
/**
*
*/
@ -531,6 +517,7 @@ TypeRegistry() {
*/
void TypeRegistry::
init_global_pointer() {
init_lock();
init_memory_hook();
_global_pointer = new TypeRegistry;
}

View File

@ -77,7 +77,7 @@ PUBLISHED:
void write(ostream &out) const;
// ptr() returns the pointer to the global TypeRegistry object.
static TypeRegistry *ptr();
static INLINE TypeRegistry *ptr();
MAKE_SEQ_PROPERTY(typehandles, get_num_typehandles, get_typehandle);
MAKE_SEQ_PROPERTY(root_classes, get_num_root_classes, get_root_class);

View File

@ -1290,7 +1290,7 @@ def CompileCxx(obj,src,opts):
cmd += " -fno-strict-aliasing"
if optlevel >= 3:
cmd += " -ffast-math"
cmd += " -ffast-math -fno-stack-protector -fno-stack-check"
if optlevel == 3:
# Fast math is nice, but we'd like to see NaN in dev builds.
cmd += " -fno-finite-math-only"

View File

@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
void CullBinBackToFront::
draw(bool force, Thread *current_thread) {
PStatTimer timer(_draw_this_pcollector, current_thread);
GeomPipelineReader geom_reader(current_thread);
GeomVertexDataPipelineReader data_reader(current_thread);
Objects::const_iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
CullableObject *object = (*oi)._object;
CullHandler::draw(object, _gsg, force, current_thread);
if (object->_draw_callback == nullptr) {
nassertd(object->_geom != nullptr) continue;
_gsg->set_state_and_transform(object->_state, object->_internal_transform);
data_reader.set_object(object->_munged_data);
data_reader.check_array_readers();
geom_reader.set_object(object->_geom);
geom_reader.draw(_gsg, object->_munger, &data_reader, force);
} else {
// It has a callback associated.
object->draw_callback(_gsg, force, current_thread);
// Now the callback has taken care of drawing.
}
}
}

View File

@ -70,10 +70,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
void CullBinFixed::
draw(bool force, Thread *current_thread) {
PStatTimer timer(_draw_this_pcollector, current_thread);
GeomPipelineReader geom_reader(current_thread);
GeomVertexDataPipelineReader data_reader(current_thread);
Objects::const_iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
CullableObject *object = (*oi)._object;
CullHandler::draw(object, _gsg, force, current_thread);
if (object->_draw_callback == nullptr) {
nassertd(object->_geom != nullptr) continue;
_gsg->set_state_and_transform(object->_state, object->_internal_transform);
data_reader.set_object(object->_munged_data);
data_reader.check_array_readers();
geom_reader.set_object(object->_geom);
geom_reader.draw(_gsg, object->_munger, &data_reader, force);
} else {
// It has a callback associated.
object->draw_callback(_gsg, force, current_thread);
// Now the callback has taken care of drawing.
}
}
}

View File

@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
void CullBinFrontToBack::
draw(bool force, Thread *current_thread) {
PStatTimer timer(_draw_this_pcollector, current_thread);
GeomPipelineReader geom_reader(current_thread);
GeomVertexDataPipelineReader data_reader(current_thread);
Objects::const_iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
CullableObject *object = (*oi)._object;
CullHandler::draw(object, _gsg, force, current_thread);
if (object->_draw_callback == nullptr) {
nassertd(object->_geom != nullptr) continue;
_gsg->set_state_and_transform(object->_state, object->_internal_transform);
data_reader.set_object(object->_munged_data);
data_reader.check_array_readers();
geom_reader.set_object(object->_geom);
geom_reader.draw(_gsg, object->_munger, &data_reader, force);
} else {
// It has a callback associated.
object->draw_callback(_gsg, force, current_thread);
// Now the callback has taken care of drawing.
}
}
}

View File

@ -69,10 +69,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
void CullBinStateSorted::
draw(bool force, Thread *current_thread) {
PStatTimer timer(_draw_this_pcollector, current_thread);
GeomPipelineReader geom_reader(current_thread);
GeomVertexDataPipelineReader data_reader(current_thread);
Objects::const_iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
CullableObject *object = (*oi)._object;
CullHandler::draw(object, _gsg, force, current_thread);
if (object->_draw_callback == nullptr) {
nassertd(object->_geom != nullptr) continue;
_gsg->set_state_and_transform(object->_state, object->_internal_transform);
data_reader.set_object(object->_munged_data);
data_reader.check_array_readers();
geom_reader.set_object(object->_geom);
geom_reader.draw(_gsg, object->_munger, &data_reader, force);
} else {
// It has a callback associated.
object->draw_callback(_gsg, force, current_thread);
// Now the callback has taken care of drawing.
}
}
}

View File

@ -54,10 +54,27 @@ add_object(CullableObject *object, Thread *current_thread) {
void CullBinUnsorted::
draw(bool force, Thread *current_thread) {
PStatTimer timer(_draw_this_pcollector, current_thread);
GeomPipelineReader geom_reader(current_thread);
GeomVertexDataPipelineReader data_reader(current_thread);
Objects::iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
CullableObject *object = (*oi);
CullHandler::draw(object, _gsg, force, current_thread);
if (object->_draw_callback == nullptr) {
nassertd(object->_geom != nullptr) continue;
_gsg->set_state_and_transform(object->_state, object->_internal_transform);
data_reader.set_object(object->_munged_data);
data_reader.check_array_readers();
geom_reader.set_object(object->_geom);
geom_reader.draw(_gsg, object->_munger, &data_reader, force);
} else {
// It has a callback associated.
object->draw_callback(_gsg, force, current_thread);
// Now the callback has taken care of drawing.
}
}
}

View File

@ -95,8 +95,7 @@ clear(Thread *current_thread) {
return;
}
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
if (glgsg->_glClearBufferfv == NULL) {
// We can't efficiently clear the buffer. Fall back to the inefficient
@ -254,8 +253,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
// until we call glBlitFramebuffer.
#ifndef OPENGLES_1
if (gl_enable_memory_barriers && _fbo_multisample == 0) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, _gsg, false);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
TextureContexts::iterator it;
for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
@ -285,8 +283,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
*/
bool CLP(GraphicsBuffer)::
check_fbo() {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, _gsg, false);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
@ -341,8 +338,7 @@ rebuild_bitplanes() {
return;
}
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
if (!_needs_rebuild) {
if (_fbo_multisample != 0) {
@ -685,8 +681,7 @@ rebuild_bitplanes() {
*/
void CLP(GraphicsBuffer)::
bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
Texture *tex = attach[slot];
@ -1020,8 +1015,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
*/
void CLP(GraphicsBuffer)::
bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
if ((_rbm[slot] != 0)&&(!rb_resize)) {
return;
@ -1144,8 +1138,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
*/
void CLP(GraphicsBuffer)::
attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
if (view >= attach->get_num_views()) {
attach->set_num_views(view + 1);
@ -1215,8 +1208,7 @@ generate_mipmaps() {
return;
}
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
// PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
@ -1253,8 +1245,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
// Unbind the FBO. TODO: calling bind_fbo is slow, so we should probably
// move this to begin_frame to prevent unnecessary calls.
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
glgsg->bind_fbo(0);
_bound_tex_page = -1;
@ -1293,8 +1284,7 @@ void CLP(GraphicsBuffer)::
select_target_tex_page(int page) {
nassertv(page >= 0 && page < _fbo.size());
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
bool switched_page = (_bound_tex_page != page);
@ -1689,8 +1679,7 @@ report_my_errors(int line, const char *file) {
GLCAT.error() << file << ", line " << line << ": GL error " << (int)error_code << "\n";
}
} else {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
glgsg->report_my_errors(line, file);
}
}
@ -1723,8 +1712,7 @@ void CLP(GraphicsBuffer)::
resolve_multisamples() {
nassertv(_fbo.size() > 0);
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
PStatGPUTimer timer(glgsg, _resolve_multisample_pcollector);

View File

@ -51,7 +51,7 @@ get_geom_rendering() const {
INLINE CPT(GeomVertexData) Geom::
get_vertex_data(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
return cdata->_data.get_read_pointer();
return cdata->_data.get_read_pointer(current_thread);
}
/**
@ -514,6 +514,18 @@ CData(const Geom::CData &copy) :
{
}
/**
*
*/
INLINE GeomPipelineReader::
GeomPipelineReader(Thread *current_thread) :
_object(nullptr),
_current_thread(current_thread),
_cdata(nullptr)
{
}
/**
*
*/
@ -531,34 +543,22 @@ GeomPipelineReader(const Geom *object, Thread *current_thread) :
#endif // DO_PIPELINING
}
/**
* Don't attempt to copy these objects.
*/
INLINE GeomPipelineReader::
GeomPipelineReader(const GeomPipelineReader &) {
nassertv(false);
}
/**
* Don't attempt to copy these objects.
*/
INLINE void GeomPipelineReader::
operator = (const GeomPipelineReader &) {
nassertv(false);
}
/**
*
*/
INLINE GeomPipelineReader::
~GeomPipelineReader() {
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
if (_object != nullptr) {
nassertv(_object->test_ref_count_nonzero());
}
#endif // _DEBUG
// _object->_cycler.release_read(_cdata);
#ifdef DO_PIPELINING
unref_delete((CycleData *)_cdata);
if (_cdata != nullptr) {
unref_delete((CycleData *)_cdata);
}
#endif // DO_PIPELINING
#ifdef _DEBUG
@ -567,6 +567,30 @@ INLINE GeomPipelineReader::
#endif // _DEBUG
}
/**
*
*/
INLINE void GeomPipelineReader::
set_object(const Geom *object) {
if (object != _object) {
// _object->_cycler.release_read(_cdata);
#ifdef DO_PIPELINING
if (_cdata != NULL) {
unref_delete((CycleData *)_cdata);
}
#endif // DO_PIPELINING
_cdata = object->_cycler.read_unlocked(_current_thread);
#ifdef DO_PIPELINING
_cdata->ref();
#endif // DO_PIPELINING
_object = object;
}
}
/**
*
*/

View File

@ -236,7 +236,7 @@ make_nonindexed(bool composite_only) {
int num_changed = 0;
CDWriter cdata(_cycler, true, current_thread);
CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer();
CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread);
PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
new_data->clear_rows();
@ -247,7 +247,7 @@ make_nonindexed(bool composite_only) {
Primitives new_prims;
new_prims.reserve(cdata->_primitives.size());
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy();
PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy();
new_prims.push_back(primitive.p());
// GeomPoints are considered "composite" for the purposes of making
@ -298,7 +298,7 @@ set_primitive(int i, const GeomPrimitive *primitive) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
nassertv(i >= 0 && i < (int)cdata->_primitives.size());
nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
// All primitives within a particular Geom must have the same fundamental
// primitive type (triangles, points, or lines).
@ -339,7 +339,7 @@ add_primitive(const GeomPrimitive *primitive) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
// All primitives within a particular Geom must have the same fundamental
// primitive type (triangles, points, or lines).
@ -426,11 +426,11 @@ decompose_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->decompose();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -460,11 +460,11 @@ doubleside_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->doubleside();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -494,11 +494,11 @@ reverse_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->reverse();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -528,11 +528,11 @@ rotate_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->rotate();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -596,7 +596,7 @@ unify_in_place(int max_indices, bool preserve_order) {
Primitives::const_iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread);
NewPrims::iterator npi = new_prims.find(primitive->get_type());
if (npi == new_prims.end()) {
// This is the first primitive of this type.
@ -648,7 +648,7 @@ unify_in_place(int max_indices, bool preserve_order) {
for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
GeomPrimitive *prim = (*npi).second;
nassertv(prim->check_valid(cdata->_data.get_read_pointer()));
nassertv(prim->check_valid(cdata->_data.get_read_pointer(current_thread)));
// Each new primitive, naturally, inherits the Geom's overall shade model.
prim->set_shade_model(cdata->_shade_model);
@ -706,11 +706,11 @@ make_lines_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_lines();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_lines();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -740,11 +740,11 @@ make_points_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -774,11 +774,11 @@ make_patches_in_place() {
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_patches();
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches();
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
@ -865,7 +865,9 @@ get_num_bytes() const {
*/
bool Geom::
request_resident() const {
CDReader cdata(_cycler);
Thread *current_thread = Thread::get_current_thread();
CDReader cdata(_cycler, current_thread);
bool resident = true;
@ -873,7 +875,7 @@ request_resident() const {
for (pi = cdata->_primitives.begin();
pi != cdata->_primitives.end();
++pi) {
if (!(*pi).get_read_pointer()->request_resident()) {
if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
resident = false;
}
}
@ -1197,7 +1199,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
int num_vertices = 0;
// Get the vertex data, after animation.
CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer();
CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread);
vertex_data = vertex_data->animate_vertices(true, current_thread);
// Now actually compute the bounding volume. We do this by using
@ -1296,7 +1298,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
for (pi = cdata->_primitives.begin();
pi != cdata->_primitives.end();
++pi) {
CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
num_vertices += prim->get_num_vertices();
}
@ -1327,7 +1329,7 @@ do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
for (pi = cdata->_primitives.begin();
pi != cdata->_primitives.end();
++pi) {
CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
found_any, vertex_data, got_mat, mat,
column_name, current_thread);
@ -1345,7 +1347,7 @@ do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
for (pi = cdata->_primitives.begin();
pi != cdata->_primitives.end();
++pi) {
CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
prim->calc_sphere_radius(center, sq_radius, found_any,
vertex_data, current_thread);
}
@ -1469,8 +1471,10 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
a_prim->append_unused_vertices(a_vertices, b_vertex);
}
PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread);
CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread);
PT(GeomVertexArrayDataHandle) a_handle =
new GeomVertexArrayDataHandle(move(a_vertices), current_thread);
CPT(GeomVertexArrayDataHandle) b_handle =
new GeomVertexArrayDataHandle(move(b_vertices), current_thread);
size_t orig_a_vertices = a_handle->get_num_rows();
@ -1683,8 +1687,7 @@ check_valid(const GeomVertexDataPipelineReader *data_reader) const {
for (pi = _cdata->_primitives.begin();
pi != _cdata->_primitives.end();
++pi) {
CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
GeomPrimitivePipelineReader reader(primitive, _current_thread);
GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
reader.check_minmax();
if (!reader.check_valid(data_reader)) {
return false;
@ -1707,12 +1710,11 @@ draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger,
for (pi = _cdata->_primitives.begin();
pi != _cdata->_primitives.end();
++pi) {
CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
GeomPrimitivePipelineReader reader(primitive, _current_thread);
GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
if (reader.get_num_vertices() != 0) {
reader.check_minmax();
nassertr(reader.check_valid(data_reader), false);
if (!primitive->draw(gsg, &reader, force)) {
if (!reader.draw(gsg, force)) {
all_ok = false;
}
}

View File

@ -401,15 +401,17 @@ private:
*/
class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
public:
INLINE GeomPipelineReader(Thread *current_thread);
INLINE GeomPipelineReader(const Geom *object, Thread *current_thread);
private:
INLINE GeomPipelineReader(const GeomPipelineReader &copy);
INLINE void operator = (const GeomPipelineReader &copy);
GeomPipelineReader(const GeomPipelineReader &copy) DELETED;
GeomPipelineReader &operator = (const GeomPipelineReader &copy) DELETED_ASSIGN;
public:
INLINE ~GeomPipelineReader();
ALLOC_DELETED_CHAIN(GeomPipelineReader);
INLINE void set_object(const Geom *object);
INLINE const Geom *get_object() const;
INLINE Thread *get_current_thread() const;
@ -433,7 +435,7 @@ public:
private:
const Geom *_object;
Thread *_current_thread;
Thread *const _current_thread;
const Geom::CData *_cdata;
public:

View File

@ -95,8 +95,8 @@ PT(GeomCacheEntry) GeomCacheEntry::
erase() {
nassertr(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL, NULL);
PT(GeomCacheEntry) keepme = this;
unref();
PT(GeomCacheEntry) keepme;
keepme.cheat() = this;
if (gobj_cat.is_debug()) {
gobj_cat.debug()

View File

@ -235,6 +235,24 @@ get_vertices() const {
return cdata->_vertices.get_read_pointer();
}
/**
* Equivalent to get_vertices().get_handle().
*/
INLINE CPT(GeomVertexArrayDataHandle) GeomPrimitive::
get_vertices_handle(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
return new GeomVertexArrayDataHandle(cdata->_vertices.get_read_pointer(current_thread), current_thread);
}
/**
* Equivalent to modify_vertices().get_handle().
*/
INLINE PT(GeomVertexArrayDataHandle) GeomPrimitive::
modify_vertices_handle(Thread *current_thread) {
CDWriter cdata(_cycler, true, current_thread);
return new GeomVertexArrayDataHandle(do_modify_vertices(cdata), current_thread);
}
/**
* A convenience function to return the gap between successive index numbers,
* in bytes, of the index data.
@ -414,38 +432,32 @@ CData(const GeomPrimitive::CData &copy) :
*
*/
INLINE GeomPrimitivePipelineReader::
GeomPrimitivePipelineReader(const GeomPrimitive *object,
GeomPrimitivePipelineReader(CPT(GeomPrimitive) object,
Thread *current_thread) :
_object(object),
_object(move(object)),
_current_thread(current_thread),
_cdata(object->_cycler.read_unlocked(current_thread)),
_vertices_reader(NULL)
#ifndef CPPPARSER
_cdata(_object->_cycler.read_unlocked(current_thread)),
#endif
_vertices_cdata(NULL)
{
nassertv(_object->test_ref_count_nonzero());
#ifdef DO_PIPELINING
_cdata->ref();
#endif // DO_PIPELINING
if (!_cdata->_vertices.is_null()) {
_vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle();
_vertices = _cdata->_vertices.get_read_pointer(current_thread);
_vertices_cdata = _vertices->_cycler.read_unlocked(current_thread);
#ifdef DO_PIPELINING
_vertices_cdata->ref();
#endif // DO_PIPELINING
// We must grab the lock *after* we have incremented the reference count,
// above.
_vertices_cdata->_rw_lock.acquire();
}
}
/**
* Don't attempt to copy these objects.
*/
INLINE GeomPrimitivePipelineReader::
GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &) {
nassertv(false);
}
/**
* Don't attempt to copy these objects.
*/
INLINE void GeomPrimitivePipelineReader::
operator = (const GeomPrimitivePipelineReader &) {
nassertv(false);
}
/**
*
*/
@ -460,8 +472,17 @@ INLINE GeomPrimitivePipelineReader::
unref_delete((CycleData *)_cdata);
#endif // DO_PIPELINING
if (_vertices_cdata != nullptr) {
// We must release the lock *before* we decrement the reference count,
// below.
_vertices_cdata->_rw_lock.release();
#ifdef DO_PIPELINING
unref_delete((CycleData *)_vertices_cdata);
#endif // DO_PIPELINING
}
#ifdef _DEBUG
_vertices_reader = NULL;
_object = NULL;
_cdata = NULL;
#endif // _DEBUG
@ -512,7 +533,7 @@ get_index_type() const {
*/
INLINE bool GeomPrimitivePipelineReader::
is_indexed() const {
return (!_cdata->_vertices.is_null());
return (!_vertices.is_null());
}
/**
@ -523,8 +544,10 @@ get_num_vertices() const {
if (_cdata->_num_vertices != -1) {
return _cdata->_num_vertices;
} else {
nassertr(!_cdata->_vertices.is_null(), 0);
return _vertices_reader->get_num_rows();
nassertr(!_vertices.is_null(), 0);
size_t stride = _vertices->_array_format->get_stride();
nassertr(stride != 0, 0);
return get_data_size_bytes() / stride;
}
}
@ -551,7 +574,7 @@ get_max_vertex() const {
*/
INLINE int GeomPrimitivePipelineReader::
get_data_size_bytes() const {
return _vertices_reader->get_data_size_bytes();
return _vertices_cdata->_buffer.get_size();
}
/**
@ -568,15 +591,7 @@ get_modified() const {
INLINE int GeomPrimitivePipelineReader::
get_index_stride() const {
nassertr(is_indexed(), 0);
return _cdata->_vertices.get_read_pointer()->get_array_format()->get_stride();
}
/**
*
*/
INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader::
get_vertices_reader() const {
return _vertices_reader;
return _vertices->_array_format->get_stride();
}
/**
@ -584,7 +599,8 @@ get_vertices_reader() const {
*/
INLINE const unsigned char *GeomPrimitivePipelineReader::
get_read_pointer(bool force) const {
return _vertices_reader->get_read_pointer(force);
((GeomVertexArrayData *)_vertices.p())->mark_used();
return _vertices_cdata->_buffer.get_read_pointer(force);
}
/**
@ -632,6 +648,14 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
return ((GeomPrimitive *)_object.p())->prepare_now(prepared_objects, gsg);
}
/**
* Calls the appropriate method on the GSG to draw the primitive.
*/
INLINE bool GeomPrimitivePipelineReader::
draw(GraphicsStateGuardianBase *gsg, bool force) const {
return _object->draw(gsg, this, force);
}
INLINE ostream &
operator << (ostream &out, const GeomPrimitive &obj) {
obj.output(out);

View File

@ -1036,23 +1036,23 @@ get_num_bytes() const {
* shortly; try again later.
*/
bool GeomPrimitive::
request_resident() const {
CDReader cdata(_cycler);
request_resident(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
bool resident = true;
if (!cdata->_vertices.is_null() &&
!cdata->_vertices.get_read_pointer()->request_resident()) {
!cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) {
resident = false;
}
if (is_composite() && cdata->_got_minmax) {
if (!cdata->_mins.is_null() &&
!cdata->_mins.get_read_pointer()->request_resident()) {
!cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) {
resident = false;
}
if (!cdata->_maxs.is_null() &&
!cdata->_maxs.get_read_pointer()->request_resident()) {
!cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) {
resident = false;
}
}
@ -2178,14 +2178,17 @@ check_minmax() const {
*/
int GeomPrimitivePipelineReader::
get_first_vertex() const {
if (_cdata->_vertices.is_null()) {
if (_vertices.is_null()) {
return _cdata->_first_vertex;
} else if (_vertices_reader->get_num_rows() == 0) {
return 0;
} else {
GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0);
return index.get_data1i();
}
size_t size = _vertices_cdata->_buffer.get_size();
if (size == 0) {
return 0;
}
GeomVertexReader index(_vertices, 0);
return index.get_data1i();
}
/**
@ -2193,11 +2196,11 @@ get_first_vertex() const {
*/
int GeomPrimitivePipelineReader::
get_vertex(int i) const {
if (!_cdata->_vertices.is_null()) {
if (!_vertices.is_null()) {
// The indexed case.
nassertr(i >= 0 && i < _vertices_reader->get_num_rows(), -1);
nassertr(i >= 0 && i < get_num_vertices(), -1);
GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0);
GeomVertexReader index(_vertices, 0);
index.set_row_unsafe(i);
return index.get_data1i();

View File

@ -142,7 +142,7 @@ PUBLISHED:
MAKE_PROPERTY(data_size_bytes, get_data_size_bytes);
MAKE_PROPERTY(modified, get_modified);
bool request_resident() const;
bool request_resident(Thread *current_thread = Thread::get_current_thread()) const;
INLINE bool check_valid(const GeomVertexData *vertex_data) const;
@ -162,7 +162,9 @@ PUBLISHED:
*/
INLINE CPT(GeomVertexArrayData) get_vertices() const;
INLINE CPT(GeomVertexArrayDataHandle) get_vertices_handle(Thread *current_thread) const;
PT(GeomVertexArrayData) modify_vertices(int num_vertices = -1);
INLINE PT(GeomVertexArrayDataHandle) modify_vertices_handle(Thread *current_thread);
void set_vertices(const GeomVertexArrayData *vertices, int num_vertices = -1);
void set_nonindexed_vertices(int first_vertex, int num_vertices);
@ -347,10 +349,10 @@ private:
*/
class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums {
public:
INLINE GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread);
INLINE GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread);
private:
INLINE GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &copy);
INLINE void operator = (const GeomPrimitivePipelineReader &copy);
GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &copy) DELETED;
GeomPrimitivePipelineReader &operator = (const GeomPrimitivePipelineReader &copy) DELETED_ASSIGN;
public:
INLINE ~GeomPrimitivePipelineReader();
@ -375,7 +377,6 @@ public:
INLINE UpdateSeq get_modified() const;
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(bool force) const;
INLINE int get_strip_cut_index() const;
INLINE CPTA_int get_ends() const;
@ -384,13 +385,15 @@ public:
INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg) const;
INLINE bool draw(GraphicsStateGuardianBase *gsg, bool force) const;
private:
CPT(GeomPrimitive) _object;
Thread *_current_thread;
Thread *const _current_thread;
const GeomPrimitive::CData *_cdata;
CPT(GeomVertexArrayDataHandle) _vertices_reader;
CPT(GeomVertexArrayData) _vertices;
const GeomVertexArrayData::CData *_vertices_cdata;
public:
static TypeHandle get_class_type() {

View File

@ -130,9 +130,20 @@ get_modified() const {
* back into memory shortly; try again later.
*/
INLINE bool GeomVertexArrayData::
request_resident() const {
CPT(GeomVertexArrayDataHandle) handle = get_handle();
return handle->request_resident();
request_resident(Thread *current_thread) const {
#ifdef DO_PIPELINING
CPT(GeomVertexArrayData::CData) cdata = _cycler.read_unlocked(current_thread);
#else
const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread);
#endif
cdata->_rw_lock.acquire();
((GeomVertexArrayData *)this)->mark_used();
bool is_resident = (cdata->_buffer.get_read_pointer(false) != nullptr);
cdata->_rw_lock.release();
return is_resident;
}
/**
@ -143,9 +154,7 @@ request_resident() const {
*/
INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData::
get_handle(Thread *current_thread) const {
const CData *cdata = _cycler.read_unlocked(current_thread);
return new GeomVertexArrayDataHandle(this, current_thread,
cdata, false);
return new GeomVertexArrayDataHandle(this, current_thread);
}
/**
@ -156,9 +165,7 @@ get_handle(Thread *current_thread) const {
*/
INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData::
modify_handle(Thread *current_thread) {
CData *cdata = _cycler.write_upstream(true, current_thread);
return new GeomVertexArrayDataHandle(this, current_thread,
cdata, true);
return new GeomVertexArrayDataHandle(PT(GeomVertexArrayData)(this), current_thread);
}
/**
@ -202,6 +209,17 @@ set_lru_size(size_t lru_size) {
}
}
/**
*/
INLINE void GeomVertexArrayData::
mark_used() {
if ((int)get_lru_size() <= vertex_data_small_size) {
SimpleLruPage::mark_used_lru(&_small_lru);
} else {
SimpleLruPage::mark_used_lru(&_independent_lru);
}
}
/**
*
*/
@ -238,15 +256,40 @@ operator = (const GeomVertexArrayData::CData &copy) {
*
*/
INLINE GeomVertexArrayDataHandle::
GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
Thread *current_thread,
const GeomVertexArrayData::CData *cdata,
bool writable) :
_object((GeomVertexArrayData *)object),
GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object,
Thread *current_thread) :
_current_thread(current_thread),
_cdata((GeomVertexArrayData::CData *)cdata),
_writable(writable)
_cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)),
_writable(false)
{
_object.swap(object);
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
#endif // _DEBUG
#ifdef DO_PIPELINING
_cdata->ref();
#endif // DO_PIPELINING
// We must grab the lock *after* we have incremented the reference count,
// above.
_cdata->_rw_lock.acquire();
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
#endif
}
/**
*
*/
INLINE GeomVertexArrayDataHandle::
GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object,
Thread *current_thread) :
_current_thread(current_thread),
_cdata(object->_cycler.write_upstream(true, current_thread)),
_writable(true)
{
_object.swap(object);
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
#endif // _DEBUG
@ -265,7 +308,8 @@ GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
* Don't attempt to copy these objects.
*/
INLINE GeomVertexArrayDataHandle::
GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy) {
GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy)
: _current_thread(copy._current_thread) {
nassertv(false);
}
@ -448,7 +492,7 @@ get_subdata(size_t start, size_t size) const {
*/
void GeomVertexArrayDataHandle::
mark_used() const {
_object->set_lru_size(_object->get_lru_size());
_object->mark_used();
}
INLINE ostream &

View File

@ -95,7 +95,7 @@ PUBLISHED:
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
INLINE bool request_resident() const;
INLINE bool request_resident(Thread *current_thread = Thread::get_current_thread()) 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());
@ -124,6 +124,7 @@ public:
private:
INLINE void set_lru_size(size_t lru_size);
INLINE void mark_used();
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
void reverse_data_endianness(unsigned char *dest,
@ -230,6 +231,7 @@ private:
friend class GeomVertexData;
friend class PreparedGraphicsObjects;
friend class GeomVertexArrayDataHandle;
friend class GeomPrimitivePipelineReader;
};
/**
@ -246,10 +248,10 @@ private:
*/
class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums {
private:
INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
Thread *current_thread,
const GeomVertexArrayData::CData *_cdata,
bool writable);
INLINE GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object,
Thread *current_thread);
INLINE GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object,
Thread *current_thread);
INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &);
INLINE void operator = (const GeomVertexArrayDataHandle &);
@ -316,7 +318,7 @@ PUBLISHED:
private:
PT(GeomVertexArrayData) _object;
Thread *_current_thread;
Thread *const _current_thread;
GeomVertexArrayData::CData *_cdata;
bool _writable;
@ -333,6 +335,11 @@ public:
private:
static TypeHandle _type_handle;
friend class Geom;
friend class GeomPrimitive;
friend class GeomVertexData;
friend class GeomVertexDataPipelineReader;
friend class GeomVertexDataPipelineWriter;
friend class GeomVertexArrayData;
};

View File

@ -147,6 +147,17 @@ get_array(int i) const {
return cdata->_arrays[i].get_read_pointer();
}
/**
* Equivalent to get_array(i).get_handle().
*/
INLINE CPT(GeomVertexArrayDataHandle) GeomVertexData::
get_array_handle(int i) const {
Thread *current_thread = Thread::get_current_thread();
CDReader cdata(_cycler, current_thread);
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
return new GeomVertexArrayDataHandle(cdata->_arrays[i].get_read_pointer(), current_thread);
}
/**
* Returns a modifiable pointer to the indicated vertex array, so that
* application code may directly manipulate the data. You should avoid
@ -162,6 +173,16 @@ modify_array(int i) {
return writer.modify_array(i);
}
/**
* Equivalent to modify_array(i).modify_handle().
*/
INLINE PT(GeomVertexArrayDataHandle) GeomVertexData::
modify_array_handle(int i) {
Thread *current_thread = Thread::get_current_thread();
GeomVertexDataPipelineWriter writer(this, true, current_thread);
return new GeomVertexArrayDataHandle(writer.modify_array(i), current_thread);
}
/**
* Replaces the indicated vertex data array with a completely new array. You
* should be careful that the new array has the same length and format as the
@ -575,6 +596,17 @@ CData(const GeomVertexData::CData &copy) :
{
}
/**
*
*/
INLINE GeomVertexDataPipelineBase::
GeomVertexDataPipelineBase(Thread *current_thread) :
_object(nullptr),
_current_thread(current_thread),
_cdata(nullptr)
{
}
/**
*
*/
@ -600,11 +632,15 @@ GeomVertexDataPipelineBase(GeomVertexData *object,
INLINE GeomVertexDataPipelineBase::
~GeomVertexDataPipelineBase() {
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
if (_object != nullptr) {
nassertv(_object->test_ref_count_nonzero());
}
#endif // _DEBUG
#ifdef DO_PIPELINING
unref_delete((CycleData *)_cdata);
if (_cdata != nullptr) {
unref_delete((CycleData *)_cdata);
}
#endif // DO_PIPELINING
#ifdef _DEBUG
@ -694,6 +730,16 @@ get_modified() const {
return _cdata->_modified;
}
/**
*
*/
INLINE GeomVertexDataPipelineReader::
GeomVertexDataPipelineReader(Thread *current_thread) :
GeomVertexDataPipelineBase(current_thread),
_got_array_readers(false)
{
}
/**
*
*/
@ -706,33 +752,23 @@ GeomVertexDataPipelineReader(const GeomVertexData *object,
{
}
/**
* Don't attempt to copy these objects.
*/
INLINE GeomVertexDataPipelineReader::
GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy) :
GeomVertexDataPipelineBase(copy)
{
nassertv(false);
}
/**
* Don't attempt to copy these objects.
*/
INLINE void GeomVertexDataPipelineReader::
operator = (const GeomVertexDataPipelineReader &) {
nassertv(false);
}
/**
*
*/
INLINE GeomVertexDataPipelineReader::
~GeomVertexDataPipelineReader() {
if (_got_array_readers) {
delete_array_readers();
INLINE void GeomVertexDataPipelineReader::
set_object(CPT(GeomVertexData) object) {
#ifdef DO_PIPELINING
if (_cdata != NULL) {
unref_delete((CycleData *)_cdata);
}
// _object->_cycler.release_read(_cdata);
#endif // DO_PIPELINING
_array_readers.clear();
_object.swap(object);
_cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread);
_got_array_readers = false;
_cdata->ref();
}
/**
@ -819,24 +855,6 @@ GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
#endif // _DEBUG
}
/**
* Don't attempt to copy these objects.
*/
INLINE GeomVertexDataPipelineWriter::
GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy) :
GeomVertexDataPipelineBase(copy)
{
nassertv(false);
}
/**
* Don't attempt to copy these objects.
*/
INLINE void GeomVertexDataPipelineWriter::
operator = (const GeomVertexDataPipelineWriter &) {
nassertv(false);
}
/**
*
*/

View File

@ -516,9 +516,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
if (keep_data_objects) {
// Copy the data, but keep the same GeomVertexArrayData object.
PT(GeomVertexArrayData) dest_data = modify_array(dest_i);
CPT(GeomVertexArrayData) source_data = source->get_array(source_i);
dest_data->modify_handle()->copy_data_from(source_data->get_handle());
modify_array_handle(dest_i)->copy_data_from(source->get_array_handle(source_i));
} else {
// Copy the GeomVertexArrayData object.
if (get_array(dest_i) != source->get_array(source_i)) {
@ -533,13 +531,16 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
}
// Now make sure the arrays we didn't share are all filled in.
reserve_num_rows(num_rows);
set_num_rows(num_rows);
{
GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread());
writer.check_array_writers();
writer.reserve_num_rows(num_rows);
writer.set_num_rows(num_rows);
}
// Now go back through and copy any data that's left over.
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();
CPT(GeomVertexArrayDataHandle) array_handle = source->get_array_handle(source_i);
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();
@ -557,8 +558,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
if (dest_column->is_bytewise_equivalent(*source_column)) {
// We can do a quick bytewise copy.
PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
unsigned char *dest_array_data = dest_handle->get_write_pointer();
bytewise_copy(dest_array_data + dest_column->get_start(),
@ -569,8 +569,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
} else if (dest_column->is_packed_argb() &&
source_column->is_uint8_rgba()) {
// A common special case: OpenGL color to DirectX color.
PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
unsigned char *dest_array_data = dest_handle->get_write_pointer();
uint8_rgba_to_packed_argb
@ -582,8 +581,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
} else if (dest_column->is_uint8_rgba() &&
source_column->is_packed_argb()) {
// Another common special case: DirectX color to OpenGL color.
PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
unsigned char *dest_array_data = dest_handle->get_write_pointer();
packed_argb_to_uint8_rgba
@ -700,12 +698,10 @@ copy_row_from(int dest_row, const GeomVertexData *source,
int num_arrays = source_format->get_num_arrays();
for (int i = 0; i < num_arrays; ++i) {
PT(GeomVertexArrayData) dest_array_obj = modify_array(i);
PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i);
unsigned char *dest_array_data = dest_handle->get_write_pointer();
CPT(GeomVertexArrayData) source_array_obj = source->get_array(i);
CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle();
CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i);
const unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
const GeomVertexArrayFormat *array_format = source_format->get_array(i);
@ -1144,8 +1140,7 @@ do_set_color(GeomVertexData *vdata, const LColor &color) {
packer->set_data4f(buffer, color);
#endif
PT(GeomVertexArrayDataHandle) handle =
vdata->modify_array(array_index)->modify_handle();
PT(GeomVertexArrayDataHandle) handle = vdata->modify_array_handle(array_index);
unsigned char *write_ptr = handle->get_write_pointer();
unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes();
write_ptr += column->get_start();
@ -1586,7 +1581,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
}
// Then apply the transforms.
CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer();
CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(current_thread);
if (tb_table != (TransformBlendTable *)NULL) {
// Recompute all the blends up front, so we don't have to test each one
// for staleness at each vertex.
@ -1617,7 +1612,8 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
if (blend_array_format->get_stride() == 2 &&
blend_array_format->get_column(0)->get_component_bytes() == 2) {
// The blend indices are a table of ushorts. Optimize this common case.
CPT(GeomVertexArrayDataHandle) blend_array_handle = cdata->_arrays[blend_array_index].get_read_pointer()->get_handle(current_thread);
CPT(GeomVertexArrayDataHandle) blend_array_handle =
new GeomVertexArrayDataHandle(cdata->_arrays[blend_array_index].get_read_pointer(current_thread), current_thread);
const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true);
size_t ci;
@ -2399,24 +2395,12 @@ make_array_readers() {
_array_readers.reserve(_cdata->_arrays.size());
GeomVertexData::Arrays::const_iterator ai;
for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer();
_array_readers.push_back(array_obj->get_handle(_current_thread));
_array_readers.push_back(new GeomVertexArrayDataHandle((*ai).get_read_pointer(_current_thread), _current_thread));
}
_got_array_readers = true;
}
/**
*
*/
void GeomVertexDataPipelineReader::
delete_array_readers() {
nassertv(_got_array_readers);
_array_readers.clear();
_got_array_readers = false;
}
/**
*
*/
@ -2610,7 +2594,7 @@ set_array(int i, const GeomVertexArrayData *array) {
_cdata->_animated_vertices_modified = UpdateSeq();
if (_got_array_writers) {
_array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread);
_array_writers[i] = new GeomVertexArrayDataHandle(_cdata->_arrays[i].get_write_pointer(), _current_thread);
}
}
@ -2624,8 +2608,7 @@ make_array_writers() {
_array_writers.reserve(_cdata->_arrays.size());
GeomVertexData::Arrays::iterator ai;
for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer();
_array_writers.push_back(array_obj->modify_handle(_current_thread));
_array_writers.push_back(new GeomVertexArrayDataHandle((*ai).get_write_pointer(), _current_thread));
}
_object->clear_cache_stage();

View File

@ -107,8 +107,10 @@ PUBLISHED:
INLINE int get_num_arrays() const;
INLINE CPT(GeomVertexArrayData) get_array(int i) const;
INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(int i) const;
MAKE_SEQ(get_arrays, get_num_arrays, get_array);
INLINE PT(GeomVertexArrayData) modify_array(int i);
INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(int i);
INLINE void set_array(int i, const GeomVertexArrayData *array);
MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array);
@ -402,6 +404,7 @@ private:
*/
class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums {
protected:
INLINE GeomVertexDataPipelineBase(Thread *current_thread);
INLINE GeomVertexDataPipelineBase(GeomVertexData *object,
Thread *current_thread,
GeomVertexData::CData *cdata);
@ -426,7 +429,7 @@ public:
protected:
PT(GeomVertexData) _object;
Thread *_current_thread;
Thread *const _current_thread;
GeomVertexData::CData *_cdata;
};
@ -436,15 +439,16 @@ protected:
*/
class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipelineBase {
public:
INLINE GeomVertexDataPipelineReader(Thread *current_thread);
INLINE GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread);
private:
INLINE GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy);
INLINE void operator = (const GeomVertexDataPipelineReader &copy);
GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy) DELETED;
GeomVertexDataPipelineReader &operator = (const GeomVertexDataPipelineReader &copy) DELETED_ASSIGN;
public:
INLINE ~GeomVertexDataPipelineReader();
ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader);
INLINE void set_object(CPT(GeomVertexData) object);
INLINE const GeomVertexData *get_object() const;
INLINE void check_array_readers() const;
@ -480,7 +484,6 @@ public:
private:
void make_array_readers();
void delete_array_readers();
bool _got_array_readers;
typedef pvector<CPT(GeomVertexArrayDataHandle) > ArrayReaders;
@ -507,8 +510,8 @@ public:
INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
Thread *current_thread);
private:
INLINE GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy);
INLINE void operator = (const GeomVertexDataPipelineWriter &copy);
GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy) DELETED;
GeomVertexDataPipelineWriter &operator = (const GeomVertexDataPipelineWriter &copy) DELETED_ASSIGN;
public:
INLINE ~GeomVertexDataPipelineWriter();

View File

@ -14,7 +14,7 @@
#include "geomVertexWriter.h"
#ifndef NDEBUG
#ifdef _DEBUG
// This is defined just for the benefit of having something non-NULL to
// return from a nassertr() call.
unsigned char GeomVertexWriter::empty_buffer[100] = { 0 };

View File

@ -212,7 +212,7 @@ private:
int _start_row;
#ifndef NDEBUG
#ifdef _DEBUG
// This is defined just for the benefit of having something non-NULL to
// return from a nassertr() call.
static unsigned char empty_buffer[100];

View File

@ -528,7 +528,7 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat
state = state->set_attrib(current_shader_attrib, 10000);
// Emit chunk
CullableObject *object = new CullableObject(_chunk_geom, state, modelview_transform);
CullableObject *object = new CullableObject(_chunk_geom, move(state), move(modelview_transform));
trav->get_cull_handler()->record_object(object, trav);
// After rendering, increment the view index

View File

@ -101,7 +101,7 @@ apply_transform_and_state(CullTraverser *trav,
if (clip_plane_cull) {
_cull_planes = _cull_planes->apply_state(trav, this,
(const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()),
DCAST(ClipPlaneAttrib, off_clip_planes),
(const ClipPlaneAttrib *)off_clip_planes,
(const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type()));
}
}

View File

@ -26,11 +26,11 @@ CullableObject() {
* render state and transform.
*/
INLINE CullableObject::
CullableObject(const Geom *geom, const RenderState *state,
const TransformState *internal_transform) :
_geom(geom),
_state(state),
_internal_transform(internal_transform)
CullableObject(CPT(Geom) geom, CPT(RenderState) state,
CPT(TransformState) internal_transform) :
_geom(move(geom)),
_state(move(state)),
_internal_transform(move(internal_transform))
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
@ -135,6 +135,21 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread)
_geom->draw(gsg, _munger, _munged_data, force, current_thread);
}
/**
* Invokes the draw callback, assuming one is set. Crashes if not.
*/
INLINE void CullableObject::
draw_callback(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) {
gsg->clear_before_callback();
gsg->set_state_and_transform(_state, _internal_transform);
GeomDrawCallbackData cbdata(this, gsg, force);
_draw_callback->do_callback(&cbdata);
if (cbdata.get_lost_state()) {
// Tell the GSG to forget its state.
gsg->clear_state_and_transform();
}
}
/**
*
*/

View File

@ -46,8 +46,8 @@ class EXPCL_PANDA_PGRAPH CullableObject
{
public:
INLINE CullableObject();
INLINE CullableObject(const Geom *geom, const RenderState *state,
const TransformState *internal_transform);
INLINE CullableObject(CPT(Geom) geom, CPT(RenderState) state,
CPT(TransformState) internal_transform);
INLINE CullableObject(const CullableObject &copy);
INLINE void operator = (const CullableObject &copy);
@ -63,6 +63,11 @@ public:
INLINE void set_draw_callback(CallbackObject *draw_callback);
INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
bool force, Thread *current_thread);
INLINE void draw_callback(GraphicsStateGuardianBase *gsg,
bool force, Thread *current_thread);
public:
ALLOC_DELETED_CHAIN(CullableObject);
@ -82,9 +87,6 @@ private:
static CPT(RenderState) get_flash_cpu_state();
static CPT(RenderState) get_flash_hardware_state();
INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
bool force, Thread *current_thread);
private:
// This class is used internally by munge_points_to_quads().
class PointData {

View File

@ -515,7 +515,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
CPT(TransformState) internal_transform = data.get_internal_transform(trav);
for (int i = 0; i < num_geoms; i++) {
const Geom *geom = geoms.get_geom(i);
CPT(Geom) geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
}
@ -558,7 +558,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
}
CullableObject *object =
new CullableObject(geom, state, internal_transform);
new CullableObject(move(geom), move(state), internal_transform);
trav->get_cull_handler()->record_object(object, trav);
}
}

View File

@ -1243,16 +1243,14 @@ apply_collect_changes() {
void GeomTransformer::NewCollectedData::
append_vdata(const GeomVertexData *vdata, int vertex_offset) {
for (int i = 0; i < vdata->get_num_arrays(); ++i) {
PT(GeomVertexArrayData) new_array = _new_data->modify_array(i);
CPT(GeomVertexArrayData) old_array = vdata->get_array(i);
PT(GeomVertexArrayDataHandle) new_handle = _new_data->modify_array_handle(i);
CPT(GeomVertexArrayDataHandle) old_handle = vdata->get_array_handle(i);
size_t stride = (size_t)_new_format->get_array(i)->get_stride();
size_t start_byte = (size_t)vertex_offset * stride;
size_t copy_bytes = old_array->get_data_size_bytes();
nassertv(start_byte + copy_bytes <= new_array->get_data_size_bytes());
size_t copy_bytes = old_handle->get_data_size_bytes();
nassertv(start_byte + copy_bytes <= new_handle->get_data_size_bytes());
new_array->modify_handle()->copy_subdata_from
(start_byte, copy_bytes,
old_array->get_handle(), 0, copy_bytes);
new_handle->copy_subdata_from(start_byte, copy_bytes, old_handle, 0, copy_bytes);
}
// Also, copy the animation data (if any). This means combining transform

View File

@ -43,10 +43,10 @@ WorkingNodePath(const WorkingNodePath &copy) :
* traversal to the next node.
*/
INLINE WorkingNodePath::
WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) {
_next = &parent;
_start = (NodePathComponent *)NULL;
_node = child;
WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) :
_next(&parent),
_start(nullptr),
_node(child) {
nassertv(_node != _next->_node);
}

View File

@ -73,7 +73,16 @@ get_unique_id() const {
*/
INLINE int Thread::
get_pipeline_stage() const {
return _pipeline_stage;
#if !defined(_DEBUG) && defined(__has_builtin) && __has_builtin(__builtin_assume)
// Because this is a signed int, this results in a sign extend on x86-64.
// However, since we guarantee that this is never less than zero, clang
// offers a nice way to avoid that.
int pipeline_stage = _pipeline_stage;
__builtin_assume(_pipeline_stage >= 0);
return pipeline_stage;
#else
return pipeline_stage;
#endif
}
/**

View File

@ -166,7 +166,7 @@ operator < (const CopyOnWritePointer &other) const {
* This flavor of the method is written for the non-threaded case.
*/
INLINE const CopyOnWriteObject *CopyOnWritePointer::
get_read_pointer() const {
get_read_pointer(Thread *current_thread) const {
return _cow_object;
}
#endif // COW_THREADED
@ -362,8 +362,14 @@ operator = (PointerTo<T> &&from) NOEXCEPT {
*/
template<class T>
INLINE CPT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
get_read_pointer() const {
return (const To *)(CopyOnWritePointer::get_read_pointer().p());
get_read_pointer(Thread *current_thread) const {
// This is necessary because we don't currently have a way to cast between
// two compatible PointerTo types without losing the reference count.
CPT(TYPENAME CopyOnWritePointerTo<T>::To) to;
CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread);
to.cheat() = (const To *)from.p();
from.cheat() = nullptr;
return to;
}
#else // COW_THREADED
/**
@ -371,8 +377,8 @@ get_read_pointer() const {
*/
template<class T>
INLINE const TYPENAME CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<T>::
get_read_pointer() const {
return (const To *)CopyOnWritePointer::get_read_pointer();
get_read_pointer(Thread *current_thread) const {
return (const To *)CopyOnWritePointer::get_read_pointer(current_thread);
}
#endif // COW_THREADED
#endif // CPPPARSER
@ -385,7 +391,13 @@ get_read_pointer() const {
template<class T>
INLINE PT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
get_write_pointer() {
return (To *)(CopyOnWritePointer::get_write_pointer().p());
// This is necessary because we don't currently have a way to cast between
// two compatible PointerTo types without losing the reference count.
PT(TYPENAME CopyOnWritePointerTo<T>::To) to;
PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer();
to.cheat() = (To *)from.p();
from.cheat() = nullptr;
return to;
}
#else // COW_THREADED
/**

View File

@ -23,13 +23,11 @@
* This flavor of the method is written for the threaded case.
*/
CPT(CopyOnWriteObject) CopyOnWritePointer::
get_read_pointer() const {
get_read_pointer(Thread *current_thread) const {
if (_cow_object == (CopyOnWriteObject *)NULL) {
return NULL;
}
Thread *current_thread = Thread::get_current_thread();
MutexHolder holder(_cow_object->_lock_mutex);
while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
if (_cow_object->_locking_thread == current_thread) {

View File

@ -48,10 +48,10 @@ public:
INLINE bool operator < (const CopyOnWritePointer &other) const;
#ifdef COW_THREADED
CPT(CopyOnWriteObject) get_read_pointer() const;
CPT(CopyOnWriteObject) get_read_pointer(Thread *current_thread) const;
PT(CopyOnWriteObject) get_write_pointer();
#else
INLINE const CopyOnWriteObject *get_read_pointer() const;
INLINE const CopyOnWriteObject *get_read_pointer(Thread *current_thread) const;
INLINE CopyOnWriteObject *get_write_pointer();
#endif // COW_THREADED
@ -93,10 +93,10 @@ public:
#endif
#ifdef COW_THREADED
INLINE CPT(To) get_read_pointer() const;
INLINE CPT(To) get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const;
INLINE PT(To) get_write_pointer();
#else
INLINE const To *get_read_pointer() const;
INLINE const To *get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const;
INLINE To *get_write_pointer();
#endif // COW_THREADED

View File

@ -1142,7 +1142,6 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
} else {
tris->set_index_type(GeomEnums::NT_uint16);
}
PT(GeomVertexArrayData) indices = tris->modify_vertices();
int i = 0;
@ -1150,9 +1149,10 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
// bottleneck. So, I've written this out the hard way instead. Two
// versions of the loop: one for 32-bit indices, one for 16-bit.
{
PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array(0)->modify_handle();
PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array_handle(0);
vtx_handle->unclean_set_num_rows(quads.size() * 4);
Thread *current_thread = Thread::get_current_thread();
unsigned char *write_ptr = vtx_handle->get_write_pointer();
size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32);
@ -1163,7 +1163,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
if (tris->get_index_type() == GeomEnums::NT_uint32) {
// 32-bit index case.
PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle();
PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
idx_handle->unclean_set_num_rows(quads.size() * 6);
uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
@ -1219,7 +1219,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
}
} else {
// 16-bit index case.
PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle();
PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
idx_handle->unclean_set_num_rows(quads.size() * 6);
uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();