From edb83fe89ac874bfa94127b01903518f9fedaa0b Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 21 Feb 2017 02:20:06 +0100 Subject: [PATCH] Various optimizations to reduce performance overhead of rendering --- dtool/src/dtoolbase/typeHandle.cxx | 4 +- dtool/src/dtoolbase/typeRegistry.I | 13 +++ dtool/src/dtoolbase/typeRegistry.cxx | 15 +-- dtool/src/dtoolbase/typeRegistry.h | 2 +- makepanda/makepanda.py | 2 +- panda/src/cull/cullBinBackToFront.cxx | 19 +++- panda/src/cull/cullBinFixed.cxx | 19 +++- panda/src/cull/cullBinFrontToBack.cxx | 19 +++- panda/src/cull/cullBinStateSorted.cxx | 19 +++- panda/src/cull/cullBinUnsorted.cxx | 19 +++- panda/src/glstuff/glGraphicsBuffer_src.cxx | 36 +++---- panda/src/gobj/geom.I | 62 ++++++++---- panda/src/gobj/geom.cxx | 68 +++++++------- panda/src/gobj/geom.h | 8 +- panda/src/gobj/geomCacheEntry.cxx | 4 +- panda/src/gobj/geomPrimitive.I | 96 ++++++++++++------- panda/src/gobj/geomPrimitive.cxx | 31 +++--- panda/src/gobj/geomPrimitive.h | 17 ++-- panda/src/gobj/geomVertexArrayData.I | 80 ++++++++++++---- panda/src/gobj/geomVertexArrayData.h | 19 ++-- panda/src/gobj/geomVertexData.I | 104 ++++++++++++--------- panda/src/gobj/geomVertexData.cxx | 57 ++++------- panda/src/gobj/geomVertexData.h | 17 ++-- panda/src/gobj/geomVertexWriter.cxx | 2 +- panda/src/gobj/geomVertexWriter.h | 2 +- panda/src/grutil/shaderTerrainMesh.cxx | 2 +- panda/src/pgraph/cullTraverserData.cxx | 2 +- panda/src/pgraph/cullableObject.I | 25 ++++- panda/src/pgraph/cullableObject.h | 12 ++- panda/src/pgraph/geomNode.cxx | 4 +- panda/src/pgraph/geomTransformer.cxx | 12 +-- panda/src/pgraph/workingNodePath.I | 8 +- panda/src/pipeline/thread.I | 11 ++- panda/src/putil/copyOnWritePointer.I | 24 +++-- panda/src/putil/copyOnWritePointer.cxx | 4 +- panda/src/putil/copyOnWritePointer.h | 8 +- panda/src/text/textAssembler.cxx | 8 +- 37 files changed, 537 insertions(+), 317 deletions(-) diff --git a/dtool/src/dtoolbase/typeHandle.cxx b/dtool/src/dtoolbase/typeHandle.cxx index 6f4d7bc1d1..4bbdbcbbb1 100644 --- a/dtool/src/dtoolbase/typeHandle.cxx +++ b/dtool/src/dtoolbase/typeHandle.cxx @@ -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(); } } diff --git a/dtool/src/dtoolbase/typeRegistry.I b/dtool/src/dtoolbase/typeRegistry.I index f0105c1eda..e35f37c207 100644 --- a/dtool/src/dtoolbase/typeRegistry.I +++ b/dtool/src/dtoolbase/typeRegistry.I @@ -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. */ diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 7349d20dd4..01b8ec498a 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -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; } diff --git a/dtool/src/dtoolbase/typeRegistry.h b/dtool/src/dtoolbase/typeRegistry.h index 828cee6c8c..651eb1904b 100644 --- a/dtool/src/dtoolbase/typeRegistry.h +++ b/dtool/src/dtoolbase/typeRegistry.h @@ -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); diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index e159e864d8..adc2064f21 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -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" diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index e472d0811d..57168aa866 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -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. + } } } diff --git a/panda/src/cull/cullBinFixed.cxx b/panda/src/cull/cullBinFixed.cxx index 3db9b9f7fb..6bbce5ed78 100644 --- a/panda/src/cull/cullBinFixed.cxx +++ b/panda/src/cull/cullBinFixed.cxx @@ -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. + } } } diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 1800b5636a..a532fef811 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -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. + } } } diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index c7ba58c295..07f3f9c9a3 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -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. + } } } diff --git a/panda/src/cull/cullBinUnsorted.cxx b/panda/src/cull/cullBinUnsorted.cxx index e9de061fb1..c9a68401b6 100644 --- a/panda/src/cull/cullBinUnsorted.cxx +++ b/panda/src/cull/cullBinUnsorted.cxx @@ -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. + } } } diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 706bb03049..a4daaf3931 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -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); diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index 33132b3be5..3457a8b265 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -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 ©) : { } + +/** + * + */ +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; + } +} + /** * */ diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 1d3e0a2a45..eb44a46abb 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -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 ¢er, 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; } } diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index cd02493d79..0ed8cc5193 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -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 ©); - INLINE void operator = (const GeomPipelineReader ©); + GeomPipelineReader(const GeomPipelineReader ©) DELETED; + GeomPipelineReader &operator = (const GeomPipelineReader ©) 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: diff --git a/panda/src/gobj/geomCacheEntry.cxx b/panda/src/gobj/geomCacheEntry.cxx index 27ab5a9e20..d16a7f6a08 100644 --- a/panda/src/gobj/geomCacheEntry.cxx +++ b/panda/src/gobj/geomCacheEntry.cxx @@ -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() diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 029063f864..1dceada335 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -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 ©) : * */ 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); diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 6f918eefdb..b96249cc83 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -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(); diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 9c24af0c45..41c575acd4 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -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 ©); - INLINE void operator = (const GeomPrimitivePipelineReader ©); + GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader ©) DELETED; + GeomPrimitivePipelineReader &operator = (const GeomPrimitivePipelineReader ©) 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() { diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index 3ee8d9311f..0c2b9904ea 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -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 ©) { * */ 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 ©) { +GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) + : _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 & diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index 9766a9cbd1..2104e74b52 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -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; }; diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index dfb2138c1a..888db97c88 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -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 ©) : { } +/** + * + */ +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 ©) : - 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 ©) : - GeomVertexDataPipelineBase(copy) -{ - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomVertexDataPipelineWriter:: -operator = (const GeomVertexDataPipelineWriter &) { - nassertv(false); -} - /** * */ diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 6b73e4fe0f..cfa47d9949 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -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(); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index cfb592529d..0261c05a93 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -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 ©); - INLINE void operator = (const GeomVertexDataPipelineReader ©); + GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©) DELETED; + GeomVertexDataPipelineReader &operator = (const GeomVertexDataPipelineReader ©) 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 ArrayReaders; @@ -507,8 +510,8 @@ public: INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, Thread *current_thread); private: - INLINE GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©); - INLINE void operator = (const GeomVertexDataPipelineWriter ©); + GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©) DELETED; + GeomVertexDataPipelineWriter &operator = (const GeomVertexDataPipelineWriter ©) DELETED_ASSIGN; public: INLINE ~GeomVertexDataPipelineWriter(); diff --git a/panda/src/gobj/geomVertexWriter.cxx b/panda/src/gobj/geomVertexWriter.cxx index b80a30fe67..ef05c3bc44 100644 --- a/panda/src/gobj/geomVertexWriter.cxx +++ b/panda/src/gobj/geomVertexWriter.cxx @@ -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 }; diff --git a/panda/src/gobj/geomVertexWriter.h b/panda/src/gobj/geomVertexWriter.h index 815ca6435f..aaedaf565b 100644 --- a/panda/src/gobj/geomVertexWriter.h +++ b/panda/src/gobj/geomVertexWriter.h @@ -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]; diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index 8c2d03cdd4..c01c851345 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -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 diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index d5ad3cba4f..b6bb5911f4 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -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())); } } diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index 242496587f..2aae972296 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -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(); + } +} + /** * */ diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 82fd0df3a5..aa4a3af3c2 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -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 ©); INLINE void operator = (const CullableObject ©); @@ -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 { diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index f0000d4ebb..7b850fafc6 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -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); } } diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 10648b7686..04207356bd 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -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 diff --git a/panda/src/pgraph/workingNodePath.I b/panda/src/pgraph/workingNodePath.I index 83010f2009..b74921827b 100644 --- a/panda/src/pgraph/workingNodePath.I +++ b/panda/src/pgraph/workingNodePath.I @@ -43,10 +43,10 @@ WorkingNodePath(const WorkingNodePath ©) : * 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); } diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index b721486c72..ba460bc3bf 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -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 } /** diff --git a/panda/src/putil/copyOnWritePointer.I b/panda/src/putil/copyOnWritePointer.I index a44731bcbc..9e996355fa 100644 --- a/panda/src/putil/copyOnWritePointer.I +++ b/panda/src/putil/copyOnWritePointer.I @@ -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 &&from) NOEXCEPT { */ template INLINE CPT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: -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::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 INLINE const TYPENAME CopyOnWritePointerTo::To *CopyOnWritePointerTo:: -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 INLINE PT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: 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::To) to; + PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer(); + to.cheat() = (To *)from.p(); + from.cheat() = nullptr; + return to; } #else // COW_THREADED /** diff --git a/panda/src/putil/copyOnWritePointer.cxx b/panda/src/putil/copyOnWritePointer.cxx index e2396e84a9..03ed76e24b 100644 --- a/panda/src/putil/copyOnWritePointer.cxx +++ b/panda/src/putil/copyOnWritePointer.cxx @@ -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) { diff --git a/panda/src/putil/copyOnWritePointer.h b/panda/src/putil/copyOnWritePointer.h index 1a7f0e099d..2178b6b433 100644 --- a/panda/src/putil/copyOnWritePointer.h +++ b/panda/src/putil/copyOnWritePointer.h @@ -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 diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 4829576407..3c8550a6a5 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -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();