cull: Use more efficient arena allocation for CullableObject

This commit is contained in:
rdb 2024-11-03 16:23:31 +01:00
parent 55fa0e9912
commit 6823634f60
35 changed files with 182 additions and 255 deletions

View File

@ -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);
}
/**

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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.
*/

View File

@ -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,

View File

@ -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.
*/

View File

@ -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,

View File

@ -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.
*/

View File

@ -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,

View File

@ -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.
*/

View File

@ -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,

View File

@ -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.
*/

View File

@ -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,

View File

@ -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;
}

View File

@ -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:

View File

@ -42,8 +42,8 @@ get_occlusion_mask() const {
*
*/
INLINE PipeOcclusionCullTraverser::PendingObject::
PendingObject(CullableObject *object) :
_object(object)
PendingObject(CullableObject &&object) :
_object(std::move(object))
{
}

View File

@ -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);
}

View File

@ -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 &copy) = 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<PendingObject> PendingObjects;

View File

@ -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;

View File

@ -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);
}
/**

View File

@ -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);
}
/**

View File

@ -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";
}
/**

View File

@ -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();

View File

@ -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.

View File

@ -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.
*/

View File

@ -45,6 +45,7 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount {
public:
CullResult(GraphicsStateGuardianBase *gsg,
const PStatCollector &draw_region_pcollector);
CullResult(const CullResult &copy) = 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;

View File

@ -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);

View File

@ -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 &copy);
INLINE CullableObject(CullableObject &&from) noexcept = default;
INLINE void operator = (const CullableObject &copy);
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:

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
/**

View File

@ -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);
}
}