Skip to content

Commit 9a40feb

Browse files
committed
shadows: fix light buffer not being destructed after light removal
Fixes LP 1672089
1 parent 1fd8af5 commit 9a40feb

File tree

7 files changed

+124
-23
lines changed

7 files changed

+124
-23
lines changed

panda/src/pgraph/light.cxx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,20 @@ get_attenuation() const {
157157
return no_atten;
158158
}
159159

160+
/**
161+
* This is called when the light is added to a LightAttrib.
162+
*/
163+
void Light::
164+
attrib_ref() {
165+
}
166+
167+
/**
168+
* This is called when the light is removed from a LightAttrib.
169+
*/
170+
void Light::
171+
attrib_unref() {
172+
}
173+
160174
/**
161175
* Computes the vector from a particular vertex to this light. The exact
162176
* vector depends on the type of light (e.g. point lights return a different

panda/src/pgraph/light.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class EXPCL_PANDA_PGRAPH Light {
6464
MAKE_PROPERTY(priority, get_priority, set_priority);
6565

6666
public:
67+
virtual void attrib_ref();
68+
virtual void attrib_unref();
69+
6770
virtual void output(ostream &out) const=0;
6871
virtual void write(ostream &out, int indent_level) const=0;
6972
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,

panda/src/pgraph/lightAttrib.I

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,6 @@ INLINE LightAttrib::
1818
LightAttrib() : _off_all_lights(false), _num_non_ambient_lights(0) {
1919
}
2020

21-
/**
22-
* Use LightAttrib::make() to construct a new LightAttrib object. The copy
23-
* constructor is only defined to facilitate methods like add_on_light().
24-
*/
25-
INLINE LightAttrib::
26-
LightAttrib(const LightAttrib &copy) :
27-
_on_lights(copy._on_lights),
28-
_off_lights(copy._off_lights),
29-
_off_all_lights(copy._off_all_lights),
30-
_sort_seq(UpdateSeq::old())
31-
{
32-
}
33-
3421
/**
3522
* Returns the number of lights that are turned on by the attribute.
3623
*/

panda/src/pgraph/lightAttrib.cxx

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,44 @@ class CompareLightPriorities {
4747
}
4848
};
4949

50+
/**
51+
* Use LightAttrib::make() to construct a new LightAttrib object. The copy
52+
* constructor is only defined to facilitate methods like add_on_light().
53+
*/
54+
LightAttrib::
55+
LightAttrib(const LightAttrib &copy) :
56+
_on_lights(copy._on_lights),
57+
_off_lights(copy._off_lights),
58+
_off_all_lights(copy._off_all_lights),
59+
_sort_seq(UpdateSeq::old())
60+
{
61+
// Increase the attrib_ref of all the lights in this attribute.
62+
Lights::const_iterator it;
63+
for (it = _on_lights.begin(); it != _on_lights.end(); ++it) {
64+
Light *lobj = (*it).node()->as_light();
65+
nassertd(lobj != nullptr) continue;
66+
lobj->attrib_ref();
67+
}
68+
}
69+
70+
/**
71+
* Destructor.
72+
*/
73+
LightAttrib::
74+
~LightAttrib() {
75+
// Call attrib_unref() on all on lights.
76+
Lights::const_iterator it;
77+
for (it = _on_lights.begin(); it != _on_lights.end(); ++it) {
78+
const NodePath &np = *it;
79+
if (!np.is_empty()) {
80+
Light *lobj = np.node()->as_light();
81+
if (lobj != nullptr) {
82+
lobj->attrib_unref();
83+
}
84+
}
85+
}
86+
}
87+
5088
/**
5189
* Constructs a new LightAttrib object that turns on (or off, according to op)
5290
* the indicated light(s).
@@ -376,14 +414,17 @@ make_all_off() {
376414
*/
377415
CPT(RenderAttrib) LightAttrib::
378416
add_on_light(const NodePath &light) const {
379-
nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
417+
nassertr(!light.is_empty(), this);
418+
Light *lobj = light.node()->as_light();
419+
nassertr(lobj != nullptr, this);
420+
380421
LightAttrib *attrib = new LightAttrib(*this);
381-
attrib->_on_lights.insert(light);
382-
attrib->_off_lights.erase(light);
383422

384423
pair<Lights::iterator, bool> insert_result =
385424
attrib->_on_lights.insert(Lights::value_type(light));
386425
if (insert_result.second) {
426+
lobj->attrib_ref();
427+
387428
// Also ensure it is removed from the off_lights list.
388429
attrib->_off_lights.erase(light);
389430
}
@@ -397,9 +438,14 @@ add_on_light(const NodePath &light) const {
397438
*/
398439
CPT(RenderAttrib) LightAttrib::
399440
remove_on_light(const NodePath &light) const {
400-
nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
441+
nassertr(!light.is_empty(), this);
442+
Light *lobj = light.node()->as_light();
443+
nassertr(lobj != nullptr, this);
444+
401445
LightAttrib *attrib = new LightAttrib(*this);
402-
attrib->_on_lights.erase(light);
446+
if (attrib->_on_lights.erase(light)) {
447+
lobj->attrib_unref();
448+
}
403449
return return_new(attrib);
404450
}
405451

@@ -409,12 +455,17 @@ remove_on_light(const NodePath &light) const {
409455
*/
410456
CPT(RenderAttrib) LightAttrib::
411457
add_off_light(const NodePath &light) const {
412-
nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
458+
nassertr(!light.is_empty(), this);
459+
Light *lobj = light.node()->as_light();
460+
nassertr(lobj != nullptr, this);
461+
413462
LightAttrib *attrib = new LightAttrib(*this);
414463
if (!_off_all_lights) {
415464
attrib->_off_lights.insert(light);
416465
}
417-
attrib->_on_lights.erase(light);
466+
if (attrib->_on_lights.erase(light)) {
467+
lobj->attrib_unref();
468+
}
418469
return return_new(attrib);
419470
}
420471

@@ -960,6 +1011,10 @@ finalize(BamReader *manager) {
9601011
// If it's in the registry, replace it.
9611012
_on_lights[i] = areg->get_node(n);
9621013
}
1014+
1015+
Light *lobj = _on_lights[i].node()->as_light();
1016+
nassertd(lobj != nullptr) continue;
1017+
lobj->attrib_ref();
9631018
}
9641019

9651020
} else {
@@ -992,10 +1047,15 @@ finalize(BamReader *manager) {
9921047
if (n != -1) {
9931048
// If it's in the registry, add that NodePath.
9941049
_on_lights.push_back(areg->get_node(n));
1050+
node = _on_lights.back().node();
9951051
} else {
9961052
// Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
9971053
_on_lights.push_back(NodePath(node));
9981054
}
1055+
1056+
Light *lobj = node->as_light();
1057+
nassertd(lobj != nullptr) continue;
1058+
lobj->attrib_ref();
9991059
}
10001060
}
10011061

panda/src/pgraph/lightAttrib.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
class EXPCL_PANDA_PGRAPH LightAttrib : public RenderAttrib {
3131
protected:
3232
INLINE LightAttrib();
33-
INLINE LightAttrib(const LightAttrib &copy);
33+
LightAttrib(const LightAttrib &copy);
3434

3535
PUBLISHED:
36+
virtual ~LightAttrib();
3637

3738
// This is the old, deprecated interface to LightAttrib. Do not use any of
3839
// these methods for new code; these methods will be removed soon.

panda/src/pgraphnodes/lightLensNode.cxx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ TypeHandle LightLensNode::_type_handle;
2727
*/
2828
LightLensNode::
2929
LightLensNode(const string &name, Lens *lens) :
30-
Camera(name, lens)
30+
Camera(name, lens),
31+
_attrib_count(0)
3132
{
3233
set_active(false);
3334
_shadow_caster = false;
@@ -46,6 +47,10 @@ LightLensNode::
4647
~LightLensNode() {
4748
set_active(false);
4849
clear_shadow_buffers();
50+
51+
// If this triggers, the number of attrib_ref() didn't match the number of
52+
// attrib_unref() calls, probably indicating a bug in LightAttrib.
53+
nassertv(AtomicAdjust::get(_attrib_count) == 0);
4954
}
5055

5156
/**
@@ -57,7 +62,8 @@ LightLensNode(const LightLensNode &copy) :
5762
Camera(copy),
5863
_shadow_caster(copy._shadow_caster),
5964
_sb_size(copy._sb_size),
60-
_sb_sort(-10)
65+
_sb_sort(-10),
66+
_attrib_count(0)
6167
{
6268
}
6369

@@ -81,6 +87,28 @@ clear_shadow_buffers() {
8187
_sbuffers.clear();
8288
}
8389

90+
91+
/**
92+
* This is called when the light is added to a LightAttrib.
93+
*/
94+
void LightLensNode::
95+
attrib_ref() {
96+
AtomicAdjust::inc(_attrib_count);
97+
}
98+
99+
/**
100+
* This is called when the light is removed from a LightAttrib.
101+
*/
102+
void LightLensNode::
103+
attrib_unref() {
104+
// When it is removed from the last LightAttrib, destroy the shadow buffers.
105+
// This is necessary to break the circular reference that the buffer holds
106+
// on this node, via the display region's camera.
107+
if (!AtomicAdjust::dec(_attrib_count)) {
108+
clear_shadow_buffers();
109+
}
110+
}
111+
84112
/**
85113
* Returns the Light object upcast to a PandaNode.
86114
*/

panda/src/pgraphnodes/lightLensNode.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "camera.h"
2121
#include "graphicsStateGuardianBase.h"
2222
#include "graphicsOutputBase.h"
23+
#include "atomicAdjust.h"
2324

2425
class ShaderGenerator;
2526
class GraphicsStateGuardian;
@@ -59,7 +60,14 @@ class EXPCL_PANDA_PGRAPHNODES LightLensNode : public Light, public Camera {
5960
typedef pmap<PT(GraphicsStateGuardianBase), PT(GraphicsOutputBase) > ShadowBuffers;
6061
ShadowBuffers _sbuffers;
6162

63+
// This counts how many LightAttribs in the world are referencing this
64+
// LightLensNode object.
65+
AtomicAdjust::Integer _attrib_count;
66+
6267
public:
68+
virtual void attrib_ref();
69+
virtual void attrib_unref();
70+
6371
virtual PandaNode *as_node();
6472
virtual Light *as_light();
6573

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy