From 6823634f60a652be80b7ed627d1d11a2cea1e6c0 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Nov 2024 16:23:31 +0100 Subject: [PATCH] cull: Use more efficient arena allocation for CullableObject --- panda/src/bullet/bulletDebugNode.cxx | 12 +- panda/src/collide/collisionVisualizer.cxx | 14 +-- panda/src/cull/binCullHandler.cxx | 4 +- panda/src/cull/binCullHandler.h | 2 +- panda/src/cull/cullBinBackToFront.cxx | 12 -- panda/src/cull/cullBinBackToFront.h | 1 - panda/src/cull/cullBinFixed.cxx | 12 -- panda/src/cull/cullBinFixed.h | 1 - panda/src/cull/cullBinFrontToBack.cxx | 12 -- panda/src/cull/cullBinFrontToBack.h | 1 - panda/src/cull/cullBinStateSorted.cxx | 12 -- panda/src/cull/cullBinStateSorted.h | 1 - panda/src/cull/cullBinUnsorted.cxx | 12 -- panda/src/cull/cullBinUnsorted.h | 1 - panda/src/cull/drawCullHandler.cxx | 9 +- panda/src/cull/drawCullHandler.h | 2 +- panda/src/grutil/pipeOcclusionCullTraverser.I | 4 +- .../src/grutil/pipeOcclusionCullTraverser.cxx | 42 +++---- panda/src/grutil/pipeOcclusionCullTraverser.h | 8 +- panda/src/grutil/shaderTerrainMesh.cxx | 4 +- panda/src/parametrics/ropeNode.cxx | 24 ++-- panda/src/parametrics/sheetNode.cxx | 6 +- panda/src/pgraph/cullHandler.cxx | 7 +- panda/src/pgraph/cullHandler.h | 2 +- panda/src/pgraph/cullResult.I | 14 +++ panda/src/pgraph/cullResult.cxx | 108 +++++++++++------- panda/src/pgraph/cullResult.h | 18 ++- panda/src/pgraph/cullTraverser.cxx | 20 +--- panda/src/pgraph/cullableObject.h | 6 +- panda/src/pgraph/geomNode.cxx | 19 ++- panda/src/pgraph/occluderNode.cxx | 14 +-- panda/src/pgraph/planeNode.cxx | 6 +- panda/src/pgraphnodes/callbackNode.cxx | 9 +- panda/src/pgraphnodes/computeNode.cxx | 9 +- .../src/pgraphnodes/nodeCullCallbackData.cxx | 9 +- 35 files changed, 182 insertions(+), 255 deletions(-) diff --git a/panda/src/bullet/bulletDebugNode.cxx b/panda/src/bullet/bulletDebugNode.cxx index 7bc26ae1c1..b3a5407146 100644 --- a/panda/src/bullet/bulletDebugNode.cxx +++ b/panda/src/bullet/bulletDebugNode.cxx @@ -248,16 +248,8 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // Record them without any state or transform. trav->_geoms_pcollector.add_level(2); - { - CullableObject *object = - new CullableObject(std::move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); - trav->get_cull_handler()->record_object(object, trav); - } - { - CullableObject *object = - new CullableObject(std::move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); - trav->get_cull_handler()->record_object(object, trav); - } + trav->get_cull_handler()->record_object(CullableObject(std::move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()), trav); + trav->get_cull_handler()->record_object(CullableObject(std::move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()), trav); } /** diff --git a/panda/src/collide/collisionVisualizer.cxx b/panda/src/collide/collisionVisualizer.cxx index d8e70d11df..29d713badb 100644 --- a/panda/src/collide/collisionVisualizer.cxx +++ b/panda/src/collide/collisionVisualizer.cxx @@ -207,11 +207,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { PT(Geom) geom = new Geom(point_vdata); geom->add_primitive(points); - CullableObject *object = - new CullableObject(geom, point_state, - xform_data.get_internal_transform(trav)); - - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + geom, point_state, xform_data.get_internal_transform(trav)), trav); } // Draw the normal vector at the surface point. @@ -236,11 +233,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { PT(Geom) geom = new Geom(line_vdata); geom->add_primitive(lines); - CullableObject *object = - new CullableObject(geom, empty_state, - xform_data.get_internal_transform(trav)); - - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + geom, empty_state, xform_data.get_internal_transform(trav)), trav); } } } diff --git a/panda/src/cull/binCullHandler.cxx b/panda/src/cull/binCullHandler.cxx index 53feb15bd4..be944a281d 100644 --- a/panda/src/cull/binCullHandler.cxx +++ b/panda/src/cull/binCullHandler.cxx @@ -19,6 +19,6 @@ * This is called as each Geom is discovered by the CullTraverser. */ void BinCullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { - _cull_result->add_object(object, traverser); +record_object(CullableObject &&object, const CullTraverser *traverser) { + _cull_result->add_object(std::move(object), traverser); } diff --git a/panda/src/cull/binCullHandler.h b/panda/src/cull/binCullHandler.h index afe73103ed..73d88824c3 100644 --- a/panda/src/cull/binCullHandler.h +++ b/panda/src/cull/binCullHandler.h @@ -28,7 +28,7 @@ class EXPCL_PANDA_CULL BinCullHandler : public CullHandler { public: INLINE BinCullHandler(CullResult *cull_result); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index 99f006b405..a8fa169304 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinBackToFront::_type_handle; -/** - * - */ -CullBinBackToFront:: -~CullBinBackToFront() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinBackToFront.h b/panda/src/cull/cullBinBackToFront.h index cfef2f4267..b950bddc28 100644 --- a/panda/src/cull/cullBinBackToFront.h +++ b/panda/src/cull/cullBinBackToFront.h @@ -33,7 +33,6 @@ public: INLINE CullBinBackToFront(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinBackToFront(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinFixed.cxx b/panda/src/cull/cullBinFixed.cxx index 7d4a4150c2..9d8ff46dcb 100644 --- a/panda/src/cull/cullBinFixed.cxx +++ b/panda/src/cull/cullBinFixed.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinFixed::_type_handle; -/** - * - */ -CullBinFixed:: -~CullBinFixed() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinFixed.h b/panda/src/cull/cullBinFixed.h index 337283e2b3..fdaece4591 100644 --- a/panda/src/cull/cullBinFixed.h +++ b/panda/src/cull/cullBinFixed.h @@ -35,7 +35,6 @@ public: INLINE CullBinFixed(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinFixed(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 8ddc16745d..146eaaab58 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinFrontToBack::_type_handle; -/** - * - */ -CullBinFrontToBack:: -~CullBinFrontToBack() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinFrontToBack.h b/panda/src/cull/cullBinFrontToBack.h index b9ba66c043..15c1f80ccf 100644 --- a/panda/src/cull/cullBinFrontToBack.h +++ b/panda/src/cull/cullBinFrontToBack.h @@ -34,7 +34,6 @@ public: INLINE CullBinFrontToBack(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinFrontToBack(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index 55c0607526..3d08802a48 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -22,18 +22,6 @@ TypeHandle CullBinStateSorted::_type_handle; -/** - * - */ -CullBinStateSorted:: -~CullBinStateSorted() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinStateSorted.h b/panda/src/cull/cullBinStateSorted.h index f97e41fa48..2e6486e348 100644 --- a/panda/src/cull/cullBinStateSorted.h +++ b/panda/src/cull/cullBinStateSorted.h @@ -37,7 +37,6 @@ public: INLINE CullBinStateSorted(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinStateSorted(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinUnsorted.cxx b/panda/src/cull/cullBinUnsorted.cxx index c633913a03..768ce35abf 100644 --- a/panda/src/cull/cullBinUnsorted.cxx +++ b/panda/src/cull/cullBinUnsorted.cxx @@ -19,18 +19,6 @@ TypeHandle CullBinUnsorted::_type_handle; -/** - * - */ -CullBinUnsorted:: -~CullBinUnsorted() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi); - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinUnsorted.h b/panda/src/cull/cullBinUnsorted.h index 2dcf60a85f..bd31ea0a38 100644 --- a/panda/src/cull/cullBinUnsorted.h +++ b/panda/src/cull/cullBinUnsorted.h @@ -29,7 +29,6 @@ public: INLINE CullBinUnsorted(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - ~CullBinUnsorted(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/drawCullHandler.cxx b/panda/src/cull/drawCullHandler.cxx index 78e27a0086..ac7ebf947f 100644 --- a/panda/src/cull/drawCullHandler.cxx +++ b/panda/src/cull/drawCullHandler.cxx @@ -25,17 +25,14 @@ * This is called as each Geom is discovered by the CullTraverser. */ void DrawCullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { +record_object(CullableObject &&object, const CullTraverser *traverser) { // Munge vertices as needed for the GSG's requirements, and the object's // current state. bool force = !_gsg->get_effective_incomplete_render(); Thread *current_thread = traverser->get_current_thread(); - if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) { + if (object.munge_geom(_gsg, _gsg->get_geom_munger(object._state, current_thread), traverser, force)) { // Now we can immediately draw the object. - draw(object, _gsg, force, current_thread); + draw(&object, _gsg, force, current_thread); } - - // Dispense with the object. - delete object; } diff --git a/panda/src/cull/drawCullHandler.h b/panda/src/cull/drawCullHandler.h index 5d8b5d3e41..127f1ee849 100644 --- a/panda/src/cull/drawCullHandler.h +++ b/panda/src/cull/drawCullHandler.h @@ -31,7 +31,7 @@ class EXPCL_PANDA_CULL DrawCullHandler : public CullHandler { public: INLINE DrawCullHandler(GraphicsStateGuardianBase *gsg); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.I b/panda/src/grutil/pipeOcclusionCullTraverser.I index d5e8685afd..9d51d18504 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.I +++ b/panda/src/grutil/pipeOcclusionCullTraverser.I @@ -42,8 +42,8 @@ get_occlusion_mask() const { * */ INLINE PipeOcclusionCullTraverser::PendingObject:: -PendingObject(CullableObject *object) : - _object(object) +PendingObject(CullableObject &&object) : + _object(std::move(object)) { } diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.cxx b/panda/src/grutil/pipeOcclusionCullTraverser.cxx index 62828319b3..ab0e859cea 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.cxx +++ b/panda/src/grutil/pipeOcclusionCullTraverser.cxx @@ -217,28 +217,19 @@ end_traverse() { _current_query = nullptr; _next_query = nullptr; - PendingObjects::iterator oi; - for (oi = _pending_objects.begin(); oi != _pending_objects.end(); ++oi) { - PendingObject &pobj = (*oi); + for (PendingObject &pobj : _pending_objects) { if (pobj._query == nullptr) { _occlusion_untested_pcollector.add_level(1); - _true_cull_handler->record_object(pobj._object, this); + _true_cull_handler->record_object(std::move(pobj._object), this); } else { int num_fragments = pobj._query->get_num_fragments(); if (num_fragments != 0) { _occlusion_passed_pcollector.add_level(1); - _true_cull_handler->record_object(pobj._object, this); + _true_cull_handler->record_object(std::move(pobj._object), this); } else { _occlusion_failed_pcollector.add_level(1); - delete pobj._object; } } - - // The CullableObject has by now either been recorded (which will - // eventually delete it) or deleted directly. -#ifndef NDEBUG - pobj._object = nullptr; -#endif // NDEBUG } _pending_objects.clear(); CullTraverser::end_traverse(); @@ -363,9 +354,9 @@ traverse_below(CullTraverserData &data) { * the end of the scene. */ void PipeOcclusionCullTraverser:: -record_object(CullableObject *object, const CullTraverser *traverser) { +record_object(CullableObject &&object, const CullTraverser *traverser) { nassertv(traverser == this); - PendingObject pobj(object); + PendingObject pobj(std::move(object)); Thread *current_thread = get_current_thread(); @@ -379,13 +370,13 @@ record_object(CullableObject *object, const CullTraverser *traverser) { // ancestor. Don't perform another one. pobj._query = _current_query; - } else if (object->_geom->get_nested_vertices(current_thread) < min_occlusion_vertices) { + } else if (pobj._object._geom->get_nested_vertices(current_thread) < min_occlusion_vertices) { // This object is too small to bother testing for occlusions. } else { // Issue an occlusion test for this object. - CPT(BoundingVolume) vol = object->_geom->get_bounds(current_thread); - CPT(TransformState) net_transform = _inv_cs_world_transform->compose(object->_internal_transform); + CPT(BoundingVolume) vol = pobj._object._geom->get_bounds(current_thread); + CPT(TransformState) net_transform = _inv_cs_world_transform->compose(pobj._object._internal_transform); CPT(TransformState) internal_transform; CPT(Geom) geom; if (get_volume_viz(vol, geom, net_transform, internal_transform)) { @@ -394,7 +385,7 @@ record_object(CullableObject *object, const CullTraverser *traverser) { } } - _pending_objects.push_back(pobj); + _pending_objects.push_back(std::move(pobj)); } /** @@ -608,14 +599,13 @@ perform_occlusion_test(const Geom *geom, const TransformState *net_transform, gsg->begin_occlusion_query(); - CullableObject *viz = - new CullableObject(geom, _solid_test_state, internal_transform); + CullableObject viz(geom, _solid_test_state, internal_transform); static ConfigVariableBool test_occlude("test-occlude", false); if (test_occlude) { - _true_cull_handler->record_object(viz, _internal_trav); + _true_cull_handler->record_object(std::move(viz), _internal_trav); } else { - _internal_cull_handler->record_object(viz, _internal_trav); + _internal_cull_handler->record_object(std::move(viz), _internal_trav); } PT(OcclusionQueryContext) query = gsg->end_occlusion_query(); @@ -654,13 +644,9 @@ show_results(int num_fragments, const Geom *geom, TransparencyAttrib::make(TransparencyAttrib::M_alpha), ColorAttrib::make_flat(color)); - CullableObject *internal_viz = - new CullableObject(geom, state, internal_transform); - _internal_cull_handler->record_object(internal_viz, _internal_trav); + _internal_cull_handler->record_object(CullableObject(geom, state, internal_transform), _internal_trav); // Also render the viz in the main scene. internal_transform = get_scene()->get_cs_world_transform()->compose(net_transform); - CullableObject *main_viz = - new CullableObject(geom, state, internal_transform); - _true_cull_handler->record_object(main_viz, this); + _true_cull_handler->record_object(CullableObject(geom, state, internal_transform), this); } diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.h b/panda/src/grutil/pipeOcclusionCullTraverser.h index d41c5acff4..f193b997e6 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.h +++ b/panda/src/grutil/pipeOcclusionCullTraverser.h @@ -39,7 +39,7 @@ class GraphicsStateGuardian; * in grutil instead, for lack of any better ideas. */ class EXPCL_PANDA_GRUTIL PipeOcclusionCullTraverser : public CullTraverser, - public CullHandler { + public CullHandler { PUBLISHED: explicit PipeOcclusionCullTraverser(GraphicsOutput *host); PipeOcclusionCullTraverser(const PipeOcclusionCullTraverser ©) = delete; @@ -59,7 +59,7 @@ protected: virtual bool is_in_view(CullTraverserData &data); virtual void traverse_below(CullTraverserData &data); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: @@ -110,10 +110,10 @@ private: class PendingObject { public: - INLINE PendingObject(CullableObject *object); + INLINE PendingObject(CullableObject &&object); INLINE ~PendingObject(); - CullableObject *_object; + CullableObject _object; PT(OcclusionQueryContext) _query; }; typedef pvector PendingObjects; diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index 339db9c383..4b42a35938 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -544,8 +544,8 @@ 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, std::move(state), std::move(modelview_transform)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + _chunk_geom, std::move(state), std::move(modelview_transform)), trav); // After rendering, increment the view index ++_current_view_index; diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index 5d49c2dda3..21c551aebe 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -329,10 +329,8 @@ render_thread(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -375,10 +373,8 @@ render_tape(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -428,10 +424,8 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -489,10 +483,8 @@ render_tube(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx index 620a35512f..cac8409278 100644 --- a/panda/src/parametrics/sheetNode.cxx +++ b/panda/src/parametrics/sheetNode.cxx @@ -319,10 +319,8 @@ render_sheet(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** diff --git a/panda/src/pgraph/cullHandler.cxx b/panda/src/pgraph/cullHandler.cxx index b8f889706d..3350e0a6d7 100644 --- a/panda/src/pgraph/cullHandler.cxx +++ b/panda/src/pgraph/cullHandler.cxx @@ -40,10 +40,9 @@ CullHandler:: * expected to delete it later. */ void CullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { - nout << *object->_geom << " " << *object->_internal_transform << " " - << *object->_state << "\n"; - delete object; +record_object(CullableObject &&object, const CullTraverser *traverser) { + nout << *object._geom << " " << *object._internal_transform << " " + << *object._state << "\n"; } /** diff --git a/panda/src/pgraph/cullHandler.h b/panda/src/pgraph/cullHandler.h index 9d42d6bad8..a5877d5eb9 100644 --- a/panda/src/pgraph/cullHandler.h +++ b/panda/src/pgraph/cullHandler.h @@ -30,7 +30,7 @@ public: CullHandler(); virtual ~CullHandler(); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); virtual void end_traverse(); diff --git a/panda/src/pgraph/cullResult.I b/panda/src/pgraph/cullResult.I index 303a06dfd8..a0ea58eb3f 100644 --- a/panda/src/pgraph/cullResult.I +++ b/panda/src/pgraph/cullResult.I @@ -16,6 +16,7 @@ */ INLINE CullResult:: ~CullResult() { + delete_page(_page); } /** @@ -32,6 +33,19 @@ get_bin(int bin_index) { return make_new_bin(bin_index); } +/** + * Allocates memory for a new CullableObject that is associated with this + * CullResult. + */ +INLINE CullableObject *CullResult:: +alloc_object(CullableObject &&object) { + AllocationPage *page = _page; + if (page->_size >= page->_capacity) { + page = new_page(); + } + return new (page->_memory + sizeof(CullableObject) * (page->_size++)) CullableObject(std::move(object)); +} + /** * If the user configured flash-bin-binname, then update the object's state to * flash all the geometry in the bin. diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index b6b238f838..d4b1550935 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -61,6 +61,8 @@ CullResult(GraphicsStateGuardianBase *gsg, _gsg(gsg), _draw_region_pcollector(draw_region_pcollector) { + _page = &_first_page; + #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif @@ -100,13 +102,13 @@ make_next() const { * the owner of the object pointer, and will eventually delete it. */ void CullResult:: -add_object(CullableObject *object, const CullTraverser *traverser) { +add_object(CullableObject &&object, const CullTraverser *traverser) { static const LColor flash_alpha_color(0.92, 0.96, 0.10, 1.0f); static const LColor flash_binary_color(0.21f, 0.67f, 0.24, 1.0f); static const LColor flash_multisample_color(0.78f, 0.05f, 0.81f, 1.0f); static const LColor flash_dual_color(0.92, 0.01f, 0.01f, 1.0f); - nassertv(object->_draw_callback != nullptr || object->_geom != nullptr); + nassertv(object._draw_callback != nullptr || object._geom != nullptr); bool force = !traverser->get_effective_incomplete_render(); Thread *current_thread = traverser->get_current_thread(); @@ -114,62 +116,60 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // This is probably a good time to check for an auto rescale setting. const RescaleNormalAttrib *rescale; - object->_state->get_attrib_def(rescale); + object._state->get_attrib_def(rescale); if (rescale->get_mode() == RescaleNormalAttrib::M_auto) { RescaleNormalAttrib::Mode mode; - if (object->_internal_transform->has_identity_scale()) { + if (object._internal_transform->has_identity_scale()) { mode = RescaleNormalAttrib::M_none; - } else if (object->_internal_transform->has_uniform_scale()) { + } else if (object._internal_transform->has_uniform_scale()) { mode = RescaleNormalAttrib::M_rescale; } else { mode = RescaleNormalAttrib::M_normalize; } - object->_state = object->_state->compose(get_rescale_normal_state(mode)); + object._state = object._state->compose(get_rescale_normal_state(mode)); } // Check for a special wireframe setting. const RenderModeAttrib *rmode; - if (object->_state->get_attrib(rmode)) { + if (object._state->get_attrib(rmode)) { if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) { - CullableObject *wireframe_part = new CullableObject(*object); + CullableObject wireframe_part(object); const ShaderAttrib *shader = nullptr; - object->_state->get_attrib(shader); - wireframe_part->_state = get_wireframe_overlay_state(rmode, shader); + object._state->get_attrib(shader); + wireframe_part._state = get_wireframe_overlay_state(rmode, shader); - if (wireframe_part->munge_geom - (_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread), + if (wireframe_part.munge_geom + (_gsg, _gsg->get_geom_munger(wireframe_part._state, current_thread), traverser, force)) { int wireframe_bin_index = bin_manager->find_bin("fixed"); CullBin *bin = get_bin(wireframe_bin_index); nassertv(bin != nullptr); - check_flash_bin(wireframe_part->_state, bin_manager, wireframe_bin_index); - bin->add_object(wireframe_part, current_thread); - } else { - delete wireframe_part; + check_flash_bin(wireframe_part._state, bin_manager, wireframe_bin_index); + bin->add_object(alloc_object(std::move(wireframe_part)), current_thread); } - object->_state = object->_state->compose(get_wireframe_filled_state()); + object._state = object._state->compose(get_wireframe_filled_state()); } } // Check to see if there's a special transparency setting. const TransparencyAttrib *trans; - if (object->_state->get_attrib(trans)) { + if (object._state->get_attrib(trans)) { switch (trans->get_mode()) { case TransparencyAttrib::M_alpha: case TransparencyAttrib::M_premultiplied_alpha: // M_alpha implies an alpha-write test, so we don't waste time writing // 0-valued pixels. - object->_state = object->_state->compose(get_alpha_state()); - check_flash_transparency(object->_state, flash_alpha_color); + object._state = object._state->compose(get_alpha_state()); + check_flash_transparency(object._state, flash_alpha_color); break; case TransparencyAttrib::M_binary: // M_binary is implemented by explicitly setting the alpha test. - object->_state = object->_state->compose(get_binary_state()); - check_flash_transparency(object->_state, flash_binary_color); + object._state = object._state->compose(get_binary_state()); + check_flash_transparency(object._state, flash_binary_color); break; case TransparencyAttrib::M_multisample: @@ -177,14 +177,14 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // The multisample modes are implemented using M_binary if the GSG in // use doesn't support multisample. if (!_gsg->get_supports_multisample()) { - object->_state = object->_state->compose(get_binary_state()); + object._state = object._state->compose(get_binary_state()); } - check_flash_transparency(object->_state, flash_multisample_color); + check_flash_transparency(object._state, flash_multisample_color); break; case TransparencyAttrib::M_dual: #ifndef NDEBUG - check_flash_transparency(object->_state, flash_dual_color); + check_flash_transparency(object._state, flash_dual_color); #endif if (!m_dual) { // If m_dual is configured off, it becomes M_alpha. @@ -198,7 +198,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // falls back to M_alpha. { const CullBinAttrib *bin_attrib; - if (!object->_state->get_attrib(bin_attrib) || + if (!object._state->get_attrib(bin_attrib) || bin_attrib->get_bin_name().empty()) { // We make a copy of the object to draw the transparent part; this // gets placed in the transparent bin. @@ -206,28 +206,25 @@ add_object(CullableObject *object, const CullTraverser *traverser) { if (m_dual_transparent) #endif { - CullableObject *transparent_part = new CullableObject(*object); + CullableObject transparent_part(object); CPT(RenderState) transparent_state = get_dual_transparent_state(); - transparent_part->_state = object->_state->compose(transparent_state); - if (transparent_part->munge_geom - (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread), + transparent_part._state = object._state->compose(transparent_state); + if (transparent_part.munge_geom + (_gsg, _gsg->get_geom_munger(transparent_part._state, current_thread), traverser, force)) { - int transparent_bin_index = transparent_part->_state->get_bin_index(); + int transparent_bin_index = transparent_part._state->get_bin_index(); CullBin *bin = get_bin(transparent_bin_index); nassertv(bin != nullptr); - check_flash_bin(transparent_part->_state, bin_manager, transparent_bin_index); - bin->add_object(transparent_part, current_thread); - } else { - delete transparent_part; + check_flash_bin(transparent_part._state, bin_manager, transparent_bin_index); + bin->add_object(alloc_object(std::move(transparent_part)), current_thread); } } // Now we can draw the opaque part. This will end up in the opaque // bin. - object->_state = object->_state->compose(get_dual_opaque_state()); + object._state = object._state->compose(get_dual_opaque_state()); #ifndef NDEBUG if (!m_dual_opaque) { - delete object; return; } #endif @@ -242,20 +239,18 @@ add_object(CullableObject *object, const CullTraverser *traverser) { } } - int bin_index = object->_state->get_bin_index(); + int bin_index = object._state->get_bin_index(); CullBin *bin = get_bin(bin_index); nassertv(bin != nullptr); - check_flash_bin(object->_state, bin_manager, bin_index); + check_flash_bin(object._state, bin_manager, bin_index); // Munge vertices as needed for the GSG's requirements, and the object's // current state. - if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) { + if (object.munge_geom(_gsg, _gsg->get_geom_munger(object._state, current_thread), traverser, force)) { // The object may or may not now be fully resident, but this may not // matter, since the GSG may have the necessary buffers already loaded. // We'll let the GSG ultimately decide whether to render it. - bin->add_object(object, current_thread); - } else { - delete object; + bin->add_object(alloc_object(std::move(object)), current_thread); } } @@ -371,6 +366,33 @@ make_new_bin(int bin_index) { return bin_ptr; } +/** + * Creates a new AllocationPage replacing the old one. + */ +CullResult::AllocationPage *CullResult:: +new_page() { + AllocationPage *page = new AllocationPage; + page->_next = _page; + _page = page; + return page; +} + +/** + * + */ +void CullResult:: +delete_page(AllocationPage *page) { + size_t size = std::exchange(page->_size, 0); + for (size_t i = 0; i < size; ++i) { + ((CullableObject *)page->_memory)[i].~CullableObject(); + } + AllocationPage *next = page->_next; + if (next != nullptr) { + delete_page(next); + delete page; + } +} + /** * Returns a RenderState containing the given rescale normal attribute. */ diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index 24c0df3d78..ff7cb5fd51 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -45,6 +45,7 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { public: CullResult(GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); + CullResult(const CullResult ©) = delete; INLINE ~CullResult(); PUBLISHED: @@ -52,7 +53,7 @@ PUBLISHED: INLINE CullBin *get_bin(int bin_index); - void add_object(CullableObject *object, const CullTraverser *traverser); + void add_object(CullableObject &&object, const CullTraverser *traverser); void finish_cull(SceneSetup *scene_setup, Thread *current_thread); void draw(Thread *current_thread); @@ -64,6 +65,11 @@ public: private: CullBin *make_new_bin(int bin_index); + struct AllocationPage; + AllocationPage *new_page(); + void delete_page(AllocationPage *page); + INLINE CullableObject *alloc_object(CullableObject &&object); + INLINE void check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index); INLINE void check_flash_transparency(CPT(RenderState) &state, const LColor &color); @@ -88,6 +94,16 @@ private: bool _show_transparency = false; + // Arena allocator for CullableObjects. + struct AllocationPage { + AllocationPage *_next = nullptr; + static const size_t _capacity = 64; + size_t _size = 0; + alignas(CullableObject) unsigned char _memory[sizeof(CullableObject) * _capacity]; + }; + AllocationPage *_page; + AllocationPage _first_page; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index aa1ea8eaa2..1982439e0d 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -259,15 +259,8 @@ draw_bounding_volume(const BoundingVolume *vol, if (bounds_viz != nullptr) { _geoms_pcollector.add_level(2); - CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), - internal_transform); - _cull_handler->record_object(outer_viz, this); - - CullableObject *inner_viz = - new CullableObject(std::move(bounds_viz), get_bounds_inner_viz_state(), - internal_transform); - _cull_handler->record_object(inner_viz, this); + _cull_handler->record_object(CullableObject(bounds_viz, get_bounds_outer_viz_state(), internal_transform), this); + _cull_handler->record_object(CullableObject(std::move(bounds_viz), get_bounds_inner_viz_state(), internal_transform), this); } } @@ -309,11 +302,10 @@ show_bounds(CullTraverserData &data, bool tight) { if (bounds_viz != nullptr) { _geoms_pcollector.add_level(1); - CullableObject *outer_viz = - new CullableObject(std::move(bounds_viz), get_bounds_outer_viz_state(), - internal_transform); - outer_viz->_instances = data._instances; - _cull_handler->record_object(outer_viz, this); + CullableObject outer_viz(std::move(bounds_viz), get_bounds_outer_viz_state(), + internal_transform); + outer_viz._instances = data._instances; + _cull_handler->record_object(std::move(outer_viz), this); } } else if (data._instances == nullptr) { draw_bounding_volume(node->get_bounds(), internal_transform); diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index b11b464657..46fdc228c6 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -24,7 +24,6 @@ #include "geomNode.h" #include "cullTraverserData.h" #include "pStatCollector.h" -#include "deletedChain.h" #include "graphicsStateGuardianBase.h" #include "sceneSetup.h" #include "lightMutex.h" @@ -46,7 +45,10 @@ public: CPT(TransformState) internal_transform); INLINE CullableObject(const CullableObject ©); + INLINE CullableObject(CullableObject &&from) noexcept = default; + INLINE void operator = (const CullableObject ©); + INLINE CullableObject &operator = (CullableObject &&from) noexcept = default; bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force); @@ -64,8 +66,6 @@ public: bool force, Thread *current_thread); public: - ALLOC_DELETED_CHAIN(CullableObject); - void output(std::ostream &out) const; public: diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 2b758c1cea..0443dfc208 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -538,10 +538,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { if (!geom->is_empty()) { CPT(RenderState) state = data._state->compose(geoms.get_geom_state(0)); if (!state->has_cull_callback() || state->cull_callback(trav, data)) { - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), std::move(internal_transform)); - object->_instances = data._instances; - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(std::move(geom), std::move(state), std::move(internal_transform)); + object._instances = data._instances; + trav->get_cull_handler()->record_object(std::move(object), trav); } } } @@ -562,10 +561,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { if (data._instances != nullptr) { // Draw each individual instance. We don't bother culling each // individual Geom for each instance; that is probably way too slow. - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), internal_transform); - object->_instances = data._instances; - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(std::move(geom), std::move(state), internal_transform); + object._instances = data._instances; + trav->get_cull_handler()->record_object(std::move(object), trav); continue; } @@ -588,9 +586,8 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { } } - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), internal_transform); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), internal_transform), trav); } } } diff --git a/panda/src/pgraph/occluderNode.cxx b/panda/src/pgraph/occluderNode.cxx index a1db42c3c3..408f5e28f1 100644 --- a/panda/src/pgraph/occluderNode.cxx +++ b/panda/src/pgraph/occluderNode.cxx @@ -141,17 +141,15 @@ bool OccluderNode:: cull_callback(CullTraverser *trav, CullTraverserData &data) { // Normally, an OccluderNode is invisible. But if someone shows it, we will // draw a visualization, a checkerboard-textured polygon. - CullableObject *occluder_viz = - new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(occluder_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), + data.get_internal_transform(trav)), trav); // Also get the frame. nassertr(_frame_viz != nullptr, false); - CullableObject *frame_viz = - new CullableObject(_frame_viz, get_frame_viz_state(trav, data), - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(frame_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + _frame_viz, get_frame_viz_state(trav, data), + data.get_internal_transform(trav)), trav); // Now carry on to render our child nodes. return true; diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index dbae5ff960..4a290a2454 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -140,10 +140,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // Normally, a PlaneNode is invisible. But if someone shows it, we will // draw a visualization, a nice yellow wireframe. - CullableObject *plane_viz = - new CullableObject(get_viz(trav, data), data._state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(plane_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + get_viz(trav, data), data._state, data.get_internal_transform(trav)), trav); // Now carry on to render our child nodes. return true; diff --git a/panda/src/pgraphnodes/callbackNode.cxx b/panda/src/pgraphnodes/callbackNode.cxx index 2e555dfd1e..8ebb38cd15 100644 --- a/panda/src/pgraphnodes/callbackNode.cxx +++ b/panda/src/pgraphnodes/callbackNode.cxx @@ -121,11 +121,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // Geoms, however. CallbackObject *cbobj = get_draw_callback(); if (cbobj != nullptr) { - CullableObject *object = - new CullableObject(nullptr, data._state, - data.get_internal_transform(trav)); - object->set_draw_callback(cbobj); - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(nullptr, data._state, + data.get_internal_transform(trav)); + object.set_draw_callback(cbobj); + trav->get_cull_handler()->record_object(std::move(object), trav); } } diff --git a/panda/src/pgraphnodes/computeNode.cxx b/panda/src/pgraphnodes/computeNode.cxx index 8c757e2860..505989762d 100644 --- a/panda/src/pgraphnodes/computeNode.cxx +++ b/panda/src/pgraphnodes/computeNode.cxx @@ -82,11 +82,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // OK, render this node. Rendering this node means creating a // CullableObject for the Dispatcher. We don't need to pass any Geoms, // however. - CullableObject *object = - new CullableObject(nullptr, data._state, - data.get_internal_transform(trav)); - object->set_draw_callback(_dispatcher); - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(nullptr, data._state, + data.get_internal_transform(trav)); + object.set_draw_callback(_dispatcher); + trav->get_cull_handler()->record_object(std::move(object), trav); } /** diff --git a/panda/src/pgraphnodes/nodeCullCallbackData.cxx b/panda/src/pgraphnodes/nodeCullCallbackData.cxx index 5a9dbc9e0a..32faac3930 100644 --- a/panda/src/pgraphnodes/nodeCullCallbackData.cxx +++ b/panda/src/pgraphnodes/nodeCullCallbackData.cxx @@ -48,11 +48,10 @@ upcall() { // any Geoms, however. CallbackObject *cbobj = cbnode->get_draw_callback(); if (cbobj != nullptr) { - CullableObject *object = - new CullableObject(nullptr, _data._state, - _data.get_internal_transform(_trav)); - object->set_draw_callback(cbobj); - _trav->get_cull_handler()->record_object(object, _trav); + CullableObject object(nullptr, _data._state, + _data.get_internal_transform(_trav)); + object.set_draw_callback(cbobj); + _trav->get_cull_handler()->record_object(std::move(object), _trav); } }