15 #include "renderState.h"
16 #include "transparencyAttrib.h"
17 #include "cullBinAttrib.h"
18 #include "cullBinManager.h"
19 #include "fogAttrib.h"
20 #include "clipPlaneAttrib.h"
21 #include "scissorAttrib.h"
22 #include "transparencyAttrib.h"
23 #include "colorAttrib.h"
24 #include "colorScaleAttrib.h"
25 #include "textureAttrib.h"
26 #include "texGenAttrib.h"
27 #include "shaderAttrib.h"
28 #include "pStatTimer.h"
29 #include "config_pgraph.h"
30 #include "bamReader.h"
31 #include "bamWriter.h"
32 #include "datagramIterator.h"
34 #include "compareTo.h"
35 #include "lightReMutexHolder.h"
36 #include "lightMutexHolder.h"
38 #include "renderAttribRegistry.h"
72 _auto_shader_state(NULL),
81 new(&_attributes[i]) Attribute();
84 if (_states == (States *)NULL) {
88 _last_mi = _mungers.end();
89 _cache_stats.add_num_states(1);
90 _read_overrides = NULL;
91 _generated_shader = NULL;
100 RenderState(
const RenderState ©) :
101 _filled_slots(copy._filled_slots),
103 _auto_shader_state(NULL),
112 new(&_attributes[i]) Attribute(copy._attributes[i]);
116 _last_mi = _mungers.end();
117 _cache_stats.add_num_states(1);
118 _read_overrides = NULL;
119 _generated_shader = NULL;
128 operator = (
const RenderState &) {
141 nassertv(!is_destructing());
147 nassertv(_saved_entry == -1);
148 nassertv(_composition_cache.
is_empty() && _invert_composition_cache.
is_empty());
151 if (_auto_shader_state != (
const RenderState *)NULL) {
152 if (_auto_shader_state !=
this) {
153 cache_unref_delete(_auto_shader_state);
155 _auto_shader_state = NULL;
161 _cache_stats.add_num_states(-1);
166 _attributes[i].~Attribute();
186 SlotMask mask = _filled_slots | other._filled_slots;
189 int result = _attributes[slot].compare_to(other._attributes[slot]);
212 if (
this == &other) {
219 for (
int n = 0; n < num_sorted_slots; ++n) {
221 nassertr((_attributes[slot]._attrib != NULL) == _filled_slots.
get_bit(slot), 0);
224 const RenderAttrib *b = other._attributes[slot]._attrib;
226 return a < b ? -1 : 1;
243 SlotMask mask = (_filled_slots | other._filled_slots) & compare_mask;
247 const RenderAttrib *b = other._attributes[slot]._attrib;
249 return a < b ? -1 : 1;
271 const Attribute &attrib = _attributes[slot];
272 nassertr(attrib._attrib != NULL,
false);
273 if (!attrib._attrib->cull_callback(trav, data)) {
289 CPT(RenderState) RenderState::
291 RenderState *state =
new RenderState;
292 int slot = attrib->get_slot();
293 state->_attributes[slot].set(attrib,
override);
294 state->_filled_slots.
set_bit(slot);
295 return return_new(state);
303 CPT(RenderState) RenderState::
306 RenderState *state =
new RenderState;
307 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
308 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
309 state->_filled_slots.
set_bit(attrib1->get_slot());
310 state->_filled_slots.
set_bit(attrib2->get_slot());
311 return return_new(state);
319 CPT(RenderState) RenderState::
323 RenderState *state =
new RenderState;
324 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
325 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
326 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
327 state->_filled_slots.
set_bit(attrib1->get_slot());
328 state->_filled_slots.
set_bit(attrib2->get_slot());
329 state->_filled_slots.
set_bit(attrib3->get_slot());
330 return return_new(state);
338 CPT(RenderState) RenderState::
343 RenderState *state =
new RenderState;
344 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
345 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
346 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
347 state->_attributes[attrib4->get_slot()].set(attrib4,
override);
348 state->_filled_slots.
set_bit(attrib1->get_slot());
349 state->_filled_slots.
set_bit(attrib2->get_slot());
350 state->_filled_slots.
set_bit(attrib3->get_slot());
351 state->_filled_slots.
set_bit(attrib4->get_slot());
352 return return_new(state);
360 CPT(RenderState) RenderState::
366 RenderState *state =
new RenderState;
367 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
368 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
369 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
370 state->_attributes[attrib4->get_slot()].set(attrib4,
override);
371 state->_attributes[attrib5->get_slot()].set(attrib5,
override);
372 state->_filled_slots.
set_bit(attrib1->get_slot());
373 state->_filled_slots.
set_bit(attrib2->get_slot());
374 state->_filled_slots.
set_bit(attrib3->get_slot());
375 state->_filled_slots.
set_bit(attrib4->get_slot());
376 state->_filled_slots.
set_bit(attrib5->get_slot());
377 return return_new(state);
385 CPT(RenderState) RenderState::
386 make(const
RenderAttrib * const *attrib,
int num_attribs,
int override) {
387 if (num_attribs == 0) {
390 RenderState *state =
new RenderState;
391 for (
int i = 0; i < num_attribs; i++) {
392 int slot = attrib[i]->get_slot();
393 state->_attributes[slot].set(attrib[i],
override);
394 state->_filled_slots.
set_bit(slot);
396 return return_new(state);
412 CPT(RenderState) RenderState::
413 compose(const RenderState *other)
const {
422 if (other->is_empty()) {
427 return do_compose(other);
433 int index = _composition_cache.find(other);
435 Composition &comp = ((RenderState *)
this)->_composition_cache.modify_data(index);
436 if (comp._result == (
const RenderState *)NULL) {
440 CPT(RenderState) result = do_compose(other);
441 comp._result = result;
443 if (result != (const RenderState *)this) {
450 _cache_stats.inc_hits();
453 _cache_stats.inc_misses();
462 CPT(RenderState) result = do_compose(other);
464 _cache_stats.add_total_size(1);
465 _cache_stats.inc_adds(_composition_cache.get_size() == 0);
467 ((RenderState *)this)->_composition_cache[other]._result = result;
470 _cache_stats.add_total_size(1);
471 _cache_stats.inc_adds(other->_composition_cache.get_size() == 0);
472 ((RenderState *)other)->_composition_cache[
this]._result = NULL;
475 if (result != (
const RenderState *)
this) {
487 _cache_stats.maybe_report(
"RenderState");
503 CPT(RenderState) RenderState::
504 invert_compose(const RenderState *other)
const {
522 return do_invert_compose(other);
528 int index = _invert_composition_cache.find(other);
530 Composition &comp = ((RenderState *)
this)->_invert_composition_cache.modify_data(index);
531 if (comp._result == (
const RenderState *)NULL) {
535 CPT(RenderState) result = do_invert_compose(other);
536 comp._result = result;
538 if (result != (const RenderState *)this) {
545 _cache_stats.inc_hits();
548 _cache_stats.inc_misses();
557 CPT(RenderState) result = do_invert_compose(other);
559 _cache_stats.add_total_size(1);
560 _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0);
561 ((RenderState *)this)->_invert_composition_cache[other]._result = result;
564 _cache_stats.add_total_size(1);
565 _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0);
566 ((RenderState *)other)->_invert_composition_cache[
this]._result = NULL;
569 if (result != (
const RenderState *)
this) {
593 CPT(RenderState) RenderState::
594 add_attrib(const
RenderAttrib *attrib,
int override)
const {
595 int slot = attrib->get_slot();
596 if (_filled_slots.get_bit(slot) &&
597 _attributes[slot]._override >
override) {
603 RenderState *new_state =
new RenderState(*
this);
604 new_state->_attributes[slot].set(attrib,
override);
605 new_state->_filled_slots.
set_bit(slot);
606 return return_new(new_state);
618 CPT(RenderState) RenderState::
620 RenderState *new_state =
new RenderState(*
this);
621 int slot = attrib->get_slot();
622 new_state->_attributes[slot]._attrib = attrib;
623 new_state->_filled_slots.
set_bit(slot);
624 return return_new(new_state);
636 CPT(RenderState) RenderState::
637 set_attrib(const
RenderAttrib *attrib,
int override)
const {
638 RenderState *new_state =
new RenderState(*
this);
639 int slot = attrib->get_slot();
640 new_state->_attributes[slot].set(attrib,
override);
641 new_state->_filled_slots.
set_bit(slot);
642 return return_new(new_state);
652 CPT(RenderState) RenderState::
653 remove_attrib(
int slot)
const {
654 if (_attributes[slot]._attrib == NULL) {
660 if (_filled_slots.get_num_on_bits() == 1) {
664 RenderState *new_state =
new RenderState(*
this);
665 new_state->_attributes[slot].set(NULL, 0);
666 new_state->_filled_slots.
clear_bit(slot);
667 return return_new(new_state);
679 CPT(RenderState) RenderState::
680 adjust_all_priorities(
int adjustment)
const {
681 RenderState *new_state =
new RenderState(*
this);
683 SlotMask mask = _filled_slots;
684 int slot = mask.get_lowest_on_bit();
686 Attribute &attrib = new_state->_attributes[slot];
688 attrib._override = max(attrib._override + adjustment, 0);
690 mask.clear_bit(slot);
691 slot = mask.get_lowest_on_bit();
694 return return_new(new_state);
709 if (!state_cache || garbage_collect_states) {
725 if (auto_break_cycles && uniquify_states) {
732 ((RenderState *)
this)->detect_and_break_cycles();
744 ((RenderState *)
this)->release_new();
745 ((RenderState *)
this)->remove_cache_pointers();
767 if (_auto_shader_state == (
const RenderState *)NULL) {
768 ((RenderState *)
this)->assign_auto_shader_state();
770 return _auto_shader_state;
779 output(ostream &out)
const {
786 const char *sep =
"";
788 SlotMask mask = _filled_slots;
791 const Attribute &attrib = _attributes[slot];
793 out << sep << attrib._attrib->get_type();
796 mask.clear_bit(slot);
797 slot = mask.get_lowest_on_bit();
809 write(ostream &out,
int indent_level)
const {
811 indent(out, indent_level)
815 SlotMask mask = _filled_slots;
818 const Attribute &attrib = _attributes[slot];
820 attrib._attrib->write(out, indent_level);
822 mask.clear_bit(slot);
823 slot = mask.get_lowest_on_bit();
851 if (_states == (
States *)NULL) {
878 if (_states == (
States *)NULL) {
886 StateCount state_count;
889 for (
int si = 0; si < size; ++si) {
893 const RenderState *state = _states->
get_key(si);
896 int cache_size = state->_composition_cache.
get_size();
897 for (i = 0; i < cache_size; ++i) {
899 const RenderState *result = state->_composition_cache.
get_data(i)._result;
900 if (result != (
const RenderState *)NULL && result != state) {
903 pair<StateCount::iterator, bool> ir =
904 state_count.insert(StateCount::value_type(result, 1));
908 (*(ir.first)).second++;
913 cache_size = state->_invert_composition_cache.
get_size();
914 for (i = 0; i < cache_size; ++i) {
915 if (state->_invert_composition_cache.
has_element(i)) {
916 const RenderState *result = state->_invert_composition_cache.
get_data(i)._result;
917 if (result != (
const RenderState *)NULL && result != state) {
918 pair<StateCount::iterator, bool> ir =
919 state_count.insert(StateCount::value_type(result, 1));
921 (*(ir.first)).second++;
933 StateCount::iterator sci;
934 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
935 const RenderState *state = (*sci).first;
936 int count = (*sci).second;
942 if (pgraph_cat.is_debug()) {
944 <<
"Unused state: " << (
void *)state <<
":"
946 state->write(pgraph_cat.debug(
false), 2);
976 if (_states == (
States *)NULL) {
990 TempStates temp_states;
991 temp_states.reserve(orig_size);
994 for (
int si = 0; si < size; ++si) {
998 const RenderState *state = _states->
get_key(si);
999 temp_states.push_back(state);
1005 TempStates::iterator ti;
1006 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
1007 RenderState *state = (RenderState *)(*ti).p();
1010 int cache_size = state->_composition_cache.
get_size();
1011 for (i = 0; i < cache_size; ++i) {
1013 const RenderState *result = state->_composition_cache.
get_data(i)._result;
1014 if (result != (
const RenderState *)NULL && result != state) {
1020 _cache_stats.add_total_size(-state->_composition_cache.
get_num_entries());
1021 state->_composition_cache.
clear();
1023 cache_size = state->_invert_composition_cache.
get_size();
1024 for (i = 0; i < cache_size; ++i) {
1025 if (state->_invert_composition_cache.
has_element(i)) {
1026 const RenderState *result = state->_invert_composition_cache.
get_data(i)._result;
1027 if (result != (
const RenderState *)NULL && result != state) {
1033 _cache_stats.add_total_size(-state->_invert_composition_cache.
get_num_entries());
1034 state->_invert_composition_cache.
clear();
1043 return orig_size - new_size;
1063 if (_states == (
States *)NULL || !garbage_collect_states) {
1068 PStatTimer timer(_garbage_collect_pcollector);
1073 int num_this_pass = int(size * garbage_collect_states_rate);
1074 if (num_this_pass <= 0) {
1077 num_this_pass = min(num_this_pass, size);
1078 int stop_at_element = (_garbage_index + num_this_pass) % size;
1080 int num_elements = 0;
1081 int si = _garbage_index;
1085 RenderState *state = (RenderState *)_states->
get_key(si);
1086 if (auto_break_cycles && uniquify_states) {
1093 state->detect_and_break_cycles();
1104 state->release_new();
1105 state->remove_cache_pointers();
1111 si = (si + 1) % size;
1112 }
while (si != stop_at_element);
1113 _garbage_index = si;
1117 return orig_size - new_size + num_attribs;
1132 for (
int si = 0; si < size; ++si) {
1136 RenderState *state = (RenderState *)(_states->
get_key(si));
1137 state->_mungers.clear();
1138 state->_last_mi = state->_mungers.end();
1162 if (_states == (
States *)NULL) {
1168 VisitedStates visited;
1172 for (
int si = 0; si < size; ++si) {
1176 const RenderState *state = _states->
get_key(si);
1178 bool inserted = visited.insert(state).second;
1180 ++_last_cycle_detect;
1181 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1183 CompositionCycleDesc::reverse_iterator csi;
1185 out <<
"\nCycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1186 <<
"state " << (
void *)state <<
":" << state->
get_ref_count()
1188 state->write(out, 2);
1189 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
1190 const CompositionCycleDescEntry &entry = (*csi);
1191 if (entry._inverted) {
1192 out <<
"invert composed with ";
1194 out <<
"composed with ";
1196 out << (
const void *)entry._obj <<
":" << entry._obj->get_ref_count()
1197 <<
" " << *entry._obj <<
"\n"
1198 <<
"produces " << (
const void *)entry._result <<
":"
1199 << entry._result->get_ref_count() <<
" =\n";
1200 entry._result->write(out, 2);
1201 visited.insert(entry._result);
1206 ++_last_cycle_detect;
1207 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1209 CompositionCycleDesc::iterator csi;
1211 out <<
"\nReverse cycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1213 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
1214 const CompositionCycleDescEntry &entry = (*csi);
1215 out << (
const void *)entry._result <<
":"
1216 << entry._result->get_ref_count() <<
" =\n";
1217 entry._result->write(out, 2);
1218 out << (
const void *)entry._obj <<
":"
1219 << entry._obj->get_ref_count() <<
" =\n";
1220 entry._obj->write(out, 2);
1221 visited.insert(entry._result);
1223 out << (
void *)state <<
":"
1225 state->write(out, 2);
1244 if (_states == (
States *)NULL) {
1245 out <<
"0 states:\n";
1253 for (
int si = 0; si < size; ++si) {
1257 const RenderState *state = _states->
get_key(si);
1258 state->write(out, 2);
1274 if (_states == (
States *)NULL) {
1278 PStatTimer timer(_state_validate_pcollector);
1287 <<
"RenderState::_states cache is invalid!\n";
1293 while (si < size && !_states->has_element(si)) {
1296 nassertr(si < size,
false);
1297 nassertr(_states->
get_key(si)->get_ref_count() >= 0,
false);
1300 while (snext < size && !_states->has_element(snext)) {
1303 while (snext < size) {
1304 nassertr(_states->
get_key(snext)->get_ref_count() >= 0,
false);
1305 const RenderState *ssi = _states->
get_key(si);
1306 const RenderState *ssnext = _states->
get_key(snext);
1307 int c = ssi->compare_to(*ssnext);
1309 if ((ci < 0) != (c > 0) ||
1310 (ci > 0) != (c < 0) ||
1311 (ci == 0) != (c == 0)) {
1313 <<
"RenderState::compare_to() not defined properly!\n";
1314 pgraph_cat.error(
false)
1315 <<
"(a, b): " << c <<
"\n";
1316 pgraph_cat.error(
false)
1317 <<
"(b, a): " << ci <<
"\n";
1318 ssi->write(pgraph_cat.error(
false), 2);
1319 ssnext->write(pgraph_cat.error(
false), 2);
1324 while (snext < size && !_states->has_element(snext)) {
1356 return geom_rendering;
1381 validate_filled_slots()
const {
1386 for (
int slot = 1; slot < max_slots; ++slot) {
1387 const Attribute &attribute = _attributes[slot];
1393 return (mask == _filled_slots);
1405 SlotMask mask = _filled_slots;
1408 const Attribute &attrib = _attributes[slot];
1413 mask.clear_bit(slot);
1414 slot = mask.get_lowest_on_bit();
1417 _flags |= F_hash_known;
1428 assign_auto_shader_state() {
1429 CPT(RenderState) state = do_calc_auto_shader_state();
1433 if (_auto_shader_state == (
const RenderState *)NULL) {
1434 _auto_shader_state = state;
1435 if (_auto_shader_state !=
this) {
1436 _auto_shader_state->cache_ref();
1449 CPT(RenderState) RenderState::
1450 do_calc_auto_shader_state() {
1451 RenderState *state =
new RenderState;
1453 SlotMask mask = _filled_slots;
1454 int slot = mask.get_lowest_on_bit();
1456 const Attribute &attrib = _attributes[slot];
1457 nassertr(attrib._attrib != (
RenderAttrib *)NULL,
this);
1458 CPT(
RenderAttrib) new_attrib = attrib._attrib->get_auto_shader_attrib(this);
1459 if (new_attrib != NULL) {
1460 nassertr(new_attrib->get_slot() == slot,
this);
1461 state->_attributes[slot].set(new_attrib, 0);
1462 state->_filled_slots.
set_bit(slot);
1465 mask.clear_bit(slot);
1466 slot = mask.get_lowest_on_bit();
1469 return return_new(state);
1483 CPT(RenderState) RenderState::
1484 return_new(RenderState *state) {
1485 nassertr(state != (RenderState *)NULL, state);
1490 if (state->_attributes[0]._attrib != (
RenderAttrib *)NULL) {
1491 const RenderAttrib *attrib = state->_attributes[0]._attrib;
1495 <<
"Uninitialized RenderAttrib type: " << attrib->get_type()
1500 if (already_reported.insert(attrib->get_type()).second) {
1502 << attrib->get_type() <<
" did not initialize its slot number.\n";
1507 state->_attributes[0]._attrib = NULL;
1508 state->_filled_slots.clear_bit(0);
1511 nassertr(state->validate_filled_slots(), state);
1514 if (!uniquify_states && !state->is_empty()) {
1518 return return_unique(state);
1533 CPT(RenderState) RenderState::
1534 return_unique(RenderState *state) {
1535 nassertr(state != (RenderState *)NULL, state);
1542 if (paranoid_const) {
1543 nassertr(validate_states(), state);
1549 if (state->_saved_entry != -1) {
1557 CPT(RenderState) pt_state = state;
1561 if (!uniquify_attribs && !state->is_empty()) {
1562 SlotMask mask = state->_filled_slots;
1563 int slot = mask.get_lowest_on_bit();
1565 Attribute &attrib = state->_attributes[slot];
1566 nassertr(attrib._attrib != (
RenderAttrib *)NULL, state);
1567 attrib._attrib = attrib._attrib->get_unique();
1568 mask.clear_bit(slot);
1569 slot = mask.get_lowest_on_bit();
1573 int si = _states->find(state);
1576 return _states->get_key(si);
1580 if (garbage_collect_states) {
1586 si = _states->store(state, Empty());
1589 state->_saved_entry = si;
1600 CPT(RenderState) RenderState::
1601 do_compose(const RenderState *other)
const {
1604 RenderState *new_state =
new RenderState;
1606 SlotMask mask = _filled_slots | other->_filled_slots;
1607 new_state->_filled_slots = mask;
1611 const Attribute &a = _attributes[slot];
1612 const Attribute &b = other->_attributes[slot];
1613 Attribute &result = new_state->_attributes[slot];
1615 if (a._attrib == NULL) {
1616 nassertr(b._attrib != NULL,
this);
1620 }
else if (b._attrib == NULL) {
1624 }
else if (b._override < a._override) {
1628 }
else if (a._override < b._override &&
1629 a._attrib->lower_attrib_can_override()) {
1642 result.set(a._attrib->compose(b._attrib), b._override);
1645 mask.clear_bit(slot);
1646 slot = mask.get_lowest_on_bit();
1654 if (sattrib->auto_shader()) {
1655 sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs());
1658 return return_new(new_state);
1666 CPT(RenderState) RenderState::
1667 do_invert_compose(const RenderState *other)
const {
1670 RenderState *new_state =
new RenderState;
1672 SlotMask mask = _filled_slots | other->_filled_slots;
1673 new_state->_filled_slots = mask;
1677 const Attribute &a = _attributes[slot];
1678 const Attribute &b = other->_attributes[slot];
1679 Attribute &result = new_state->_attributes[slot];
1681 if (a._attrib == NULL) {
1682 nassertr(b._attrib != NULL,
this);
1686 }
else if (b._attrib == NULL) {
1688 CPT(RenderState) full_default = make_full_default();
1689 CPT(
RenderAttrib) default_attrib = full_default->get_attrib(slot);
1690 result.set(a._attrib->invert_compose(default_attrib), 0);
1695 result.set(a._attrib->invert_compose(b._attrib), 0);
1698 mask.clear_bit(slot);
1699 slot = mask.get_lowest_on_bit();
1701 return return_new(new_state);
1712 detect_and_break_cycles() {
1713 PStatTimer timer(_state_break_cycles_pcollector);
1715 ++_last_cycle_detect;
1716 if (r_detect_cycles(
this,
this, 1, _last_cycle_detect, NULL)) {
1719 if (pgraph_cat.is_debug()) {
1721 <<
"Breaking cycle involving " << (*this) <<
"\n";
1724 ((RenderState *)
this)->remove_cache_pointers();
1726 ++_last_cycle_detect;
1727 if (r_detect_reverse_cycles(
this,
this, 1, _last_cycle_detect, NULL)) {
1728 if (pgraph_cat.is_debug()) {
1730 <<
"Breaking cycle involving " << (*this) <<
"\n";
1733 ((RenderState *)
this)->remove_cache_pointers();
1750 r_detect_cycles(
const RenderState *start_state,
1751 const RenderState *current_state,
1754 if (current_state->_cycle_detect == this_seq) {
1761 return (current_state == start_state && length > 2);
1763 ((RenderState *)current_state)->_cycle_detect = this_seq;
1766 int cache_size = current_state->_composition_cache.
get_size();
1767 for (i = 0; i < cache_size; ++i) {
1768 if (current_state->_composition_cache.
has_element(i)) {
1769 const RenderState *result = current_state->_composition_cache.
get_data(i)._result;
1770 if (result != (
const RenderState *)NULL) {
1771 if (r_detect_cycles(start_state, result, length + 1,
1772 this_seq, cycle_desc)) {
1774 if (cycle_desc != (CompositionCycleDesc *)NULL) {
1775 const RenderState *other = current_state->_composition_cache.
get_key(i);
1776 CompositionCycleDescEntry entry(other, result,
false);
1777 cycle_desc->push_back(entry);
1785 cache_size = current_state->_invert_composition_cache.
get_size();
1786 for (i = 0; i < cache_size; ++i) {
1787 if (current_state->_invert_composition_cache.
has_element(i)) {
1788 const RenderState *result = current_state->_invert_composition_cache.
get_data(i)._result;
1789 if (result != (
const RenderState *)NULL) {
1790 if (r_detect_cycles(start_state, result, length + 1,
1791 this_seq, cycle_desc)) {
1793 if (cycle_desc != (CompositionCycleDesc *)NULL) {
1794 const RenderState *other = current_state->_invert_composition_cache.
get_key(i);
1795 CompositionCycleDescEntry entry(other, result,
true);
1796 cycle_desc->push_back(entry);
1817 r_detect_reverse_cycles(
const RenderState *start_state,
1818 const RenderState *current_state,
1821 if (current_state->_cycle_detect == this_seq) {
1828 return (current_state == start_state && length > 2);
1830 ((RenderState *)current_state)->_cycle_detect = this_seq;
1833 int cache_size = current_state->_composition_cache.
get_size();
1834 for (i = 0; i < cache_size; ++i) {
1835 if (current_state->_composition_cache.
has_element(i)) {
1836 const RenderState *other = current_state->_composition_cache.
get_key(i);
1837 if (other != current_state) {
1838 int oi = other->_composition_cache.
find(current_state);
1839 nassertr(oi != -1,
false);
1841 const RenderState *result = other->_composition_cache.
get_data(oi)._result;
1842 if (result != (
const RenderState *)NULL) {
1843 if (r_detect_reverse_cycles(start_state, result, length + 1,
1844 this_seq, cycle_desc)) {
1846 if (cycle_desc != (CompositionCycleDesc *)NULL) {
1847 const RenderState *other = current_state->_composition_cache.
get_key(i);
1848 CompositionCycleDescEntry entry(other, result,
false);
1849 cycle_desc->push_back(entry);
1858 cache_size = current_state->_invert_composition_cache.
get_size();
1859 for (i = 0; i < cache_size; ++i) {
1860 if (current_state->_invert_composition_cache.
has_element(i)) {
1861 const RenderState *other = current_state->_invert_composition_cache.
get_key(i);
1862 if (other != current_state) {
1863 int oi = other->_invert_composition_cache.
find(current_state);
1864 nassertr(oi != -1,
false);
1866 const RenderState *result = other->_invert_composition_cache.
get_data(oi)._result;
1867 if (result != (
const RenderState *)NULL) {
1868 if (r_detect_reverse_cycles(start_state, result, length + 1,
1869 this_seq, cycle_desc)) {
1871 if (cycle_desc != (CompositionCycleDesc *)NULL) {
1872 const RenderState *other = current_state->_invert_composition_cache.
get_key(i);
1873 CompositionCycleDescEntry entry(other, result,
false);
1874 cycle_desc->push_back(entry);
1900 if (_saved_entry != -1) {
1902 _saved_entry = _states->
find(
this);
1920 remove_cache_pointers() {
1924 if (_auto_shader_state != (
const RenderState *)NULL) {
1925 if (_auto_shader_state !=
this) {
1926 cache_unref_delete(_auto_shader_state);
1928 _auto_shader_state = NULL;
1947 if (_composition_cache.
is_empty() && _invert_composition_cache.
is_empty()) {
1956 while (!_composition_cache.
is_empty()) {
1969 RenderState *other = (RenderState *)_composition_cache.
get_key(i);
1973 Composition comp = _composition_cache.
get_data(i);
1980 _cache_stats.add_total_size(-1);
1981 _cache_stats.inc_dels();
1983 if (other !=
this) {
1984 int oi = other->_composition_cache.
find(
this);
1991 Composition ocomp = other->_composition_cache.
get_data(oi);
1994 _cache_stats.add_total_size(-1);
1995 _cache_stats.inc_dels();
2001 if (ocomp._result != (
const RenderState *)NULL && ocomp._result != other) {
2002 cache_unref_delete(ocomp._result);
2009 if (comp._result != (
const RenderState *)NULL && comp._result !=
this) {
2010 cache_unref_delete(comp._result);
2016 while (!_invert_composition_cache.
is_empty()) {
2017 while (!_invert_composition_cache.
has_element(i)) {
2021 RenderState *other = (RenderState *)_invert_composition_cache.
get_key(i);
2022 nassertv(other !=
this);
2023 Composition comp = _invert_composition_cache.
get_data(i);
2025 _cache_stats.add_total_size(-1);
2026 _cache_stats.inc_dels();
2027 if (other !=
this) {
2028 int oi = other->_invert_composition_cache.
find(
this);
2030 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
2032 _cache_stats.add_total_size(-1);
2033 _cache_stats.inc_dels();
2034 if (ocomp._result != (
const RenderState *)NULL && ocomp._result != other) {
2035 cache_unref_delete(ocomp._result);
2039 if (comp._result != (
const RenderState *)NULL && comp._result !=
this) {
2040 cache_unref_delete(comp._result);
2052 determine_bin_index() {
2054 if ((_flags & F_checked_bin_index) != 0) {
2068 if (bin_name.empty()) {
2072 bin_name =
"opaque";
2076 switch (transparency->
get_mode()) {
2077 case TransparencyAttrib::M_alpha:
2078 case TransparencyAttrib::M_dual:
2080 bin_name =
"transparent";
2090 _bin_index = bin_manager->
find_bin(bin_name);
2091 if (_bin_index == -1) {
2092 pgraph_cat.warning()
2093 <<
"No bin named " << bin_name <<
"; creating default bin.\n";
2094 _bin_index = bin_manager->
add_bin(bin_name, CullBinManager::BT_unsorted, 0);
2096 _flags |= F_checked_bin_index;
2105 determine_cull_callback() {
2107 if ((_flags & F_checked_cull_callback) != 0) {
2112 SlotMask mask = _filled_slots;
2115 const Attribute &attrib = _attributes[slot];
2117 if (attrib._attrib->has_cull_callback()) {
2118 _flags |= F_has_cull_callback;
2122 mask.clear_bit(slot);
2123 slot = mask.get_lowest_on_bit();
2126 _flags |= F_checked_cull_callback;
2138 for (
int slot = 1; slot < num_slots; ++slot) {
2139 _attributes[slot].set(reg->get_slot_default(slot), 0);
2153 update_pstats(
int old_referenced_bits,
int new_referenced_bits) {
2155 if ((old_referenced_bits & R_node) != 0) {
2156 _node_counter.sub_level(1);
2157 }
else if ((old_referenced_bits & R_cache) != 0) {
2158 _cache_counter.sub_level(1);
2160 if ((new_referenced_bits & R_node) != 0) {
2161 _node_counter.add_level(1);
2162 }
else if ((new_referenced_bits & R_cache) != 0) {
2163 _cache_counter.add_level(1);
2187 _states_lock =
new LightReMutex(
"RenderState::_states_lock");
2188 _cache_stats.init();
2215 nassertv(num_attribs == (
int)(PN_uint16)num_attribs);
2223 const Attribute &attrib = _attributes[slot];
2244 int num_attribs = 0;
2247 for (
size_t i = 0; i < (*_read_overrides).size(); ++i) {
2248 int override = (*_read_overrides)[i];
2252 int slot = attrib->get_slot();
2253 if (slot > 0 && slot < reg->get_max_slots()) {
2254 _attributes[slot].set(attrib,
override);
2261 delete _read_overrides;
2262 _read_overrides = NULL;
2281 RenderState *state = DCAST(RenderState, old_ptr);
2282 CPT(RenderState) pointer = return_unique(state);
2289 if (pointer == state) {
2296 return (RenderState *)pointer.p();
2329 RenderState *state =
new RenderState;
2333 parse_params(params, scan, manager);
2334 state->fillin(scan, manager);
2352 _read_overrides =
new vector_int;
2353 (*_read_overrides).reserve(num_attribs);
2355 for (
int i = 0; i < num_attribs; ++i) {
2358 (*_read_overrides).push_back(
override);
void clear_bit(int index)
Sets the nth bit off.
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
int find(const Key &key) const
Searches for the indicated key in the table.
This is our own Panda specialization on the default STL map.
static int get_num_states()
Returns the total number of unique RenderState objects allocated in the world.
int get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this TexMatrixAttrib is ...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
int get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this RenderState is appl...
static TypeHandle none()
Returns a special zero-valued TypeHandle that is used to indicate no type.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static int get_max_priority()
Returns the maximum priority number (sometimes called override) that may be set on any node...
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
This controls the enabling of transparency.
int get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this RenderModeAttrib is...
int get_num_entries() const
Returns the number of active entries in the table.
Base class for objects that can be written to and read from Bam files.
const string & get_bin_name() const
Returns the name of the bin this attribute specifies.
static void clear_munger_cache()
Completely empties the cache of state + gsg -> munger, for all states and all gsg's.
A lightweight reentrant mutex.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
int get_num_sorted_slots() const
Returns the number of entries in the sorted_slots list.
const RenderState * get_auto_shader_state() const
Returns the base RenderState that should have the generated_shader stored within it, for generated shader states.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This template class implements an unordered map of keys to data, implemented as a hashtable...
static void register_with_read_factory()
Tells the BamReader how to create objects of type RenderState.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
int get_cache_ref_count() const
Returns the current reference count.
void clear()
Completely empties the table.
DeletedBufferChain * get_array_chain() const
Returns the DeletedBufferChain object that may be used to allocated appropriately-sized arrays of Ren...
PN_int32 get_int32()
Extracts a signed 32-bit integer.
void * allocate(size_t size, TypeHandle type_handle)
Allocates the memory for a new buffer of the indicated size (which must be no greater than the fixed ...
static int garbage_collect()
Performs a garbage-collection cycle.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
void register_change_this(ChangeThisFunc func, TypedWritable *whom)
Called by an object reading itself from the bam file to indicate that the object pointer that will be...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
int find_bin(const string &name) const
Returns the bin_index associated with the bin of the given name, or -1 if no bin has that name...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
int get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this TexGenAttrib is app...
static CullBinManager * get_global_ptr()
Returns the pointer to the global CullBinManager object.
bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
Calls cull_callback() on each attrib.
int compare_sort(const RenderState &other) const
Returns -1, 0, or 1 according to the relative sorting of these two RenderStates, with regards to rend...
This is our own Panda specialization on the default STL vector.
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
static Thread * get_main_thread()
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process...
virtual ~RenderState()
The destructor is responsible for removing the RenderState from the global set if it is there...
A lightweight class that represents a single element that may be timed and/or counted via stats...
bool is_empty() const
Returns true if the table is empty; i.e.
int get_size() const
Returns the total number of slots in the table.
static void list_cycles(ostream &out)
Detects all of the reference-count cycles in the cache and reports them to standard output...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
virtual bool unref() const
Explicitly decrements the reference count.
static int garbage_collect()
Performs a garbage-collection cycle.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
static bool validate_states()
Ensures that the cache is still stored in sorted order, and that none of the cache elements have been...
int get_lowest_on_bit() const
Returns the index of the lowest 1 bit in the mask.
This class is used to associate each RenderAttrib with a different slot index at runtime, so we can store a list of RenderAttribs in the RenderState object, and very quickly look them up by type.
Similar to MutexHolder, but for a light mutex.
void deallocate(void *ptr, TypeHandle type_handle)
Frees the memory for a buffer previously allocated via allocate().
static int get_num_unused_states()
Returns the total number of RenderState objects that have been allocated but have no references outsi...
virtual bool unref() const
This method overrides ReferenceCount::unref() to check whether the remaining reference count is entir...
int get_num_slots() const
Returns the number of RenderAttrib slots that have been allocated.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
bool is_empty() const
Returns true if the state is empty, false otherwise.
bool cache_unref() const
Overrides this method to update PStats appropriately.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
const RenderAttrib * get_attrib(TypeHandle type) const
Looks for a RenderAttrib of the indicated type in the state, and returns it if it is found...
void set_bit(int index)
Sets the nth bit on.
Similar to MutexHolder, but for a light reentrant mutex.
int get_sorted_slot(int n) const
Returns the nth slot in sorted order.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Assigns geometry to a particular bin by name.
Applies a transform matrix to UV's before they are rendered.
Mode get_mode() const
Returns the transparency mode.
int add_bin(const string &name, BinType type, int sort)
Defines a new bin with the indicated name, and returns the new bin_index.
int get_draw_order() const
Returns the draw order this attribute specifies.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is used to track the utilization of the TransformState and RenderState caches, for low-level performance tuning information.
Specifies how polygons are to be drawn.
int compare_mask(const RenderState &other, SlotMask compare_mask) const
This version of compare_to takes a slot mask that indicates which attributes to include in the compar...
This is our own Panda specialization on the default STL set.
bool validate() const
Returns true if the internal table appears to be consistent, false if there are some internal errors...
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
A class to retrieve the individual data elements previously stored in a Datagram. ...
static TypedWritable * change_this(TypedWritable *old_ptr, BamReader *manager)
Called immediately after complete_pointers(), this gives the object a chance to adjust its own pointe...
int compare_to(const RenderState &other) const
Provides an arbitrary ordering among all unique RenderStates, so we can store the essentially differe...
const Value & get_data(int n) const
Returns the data in the nth slot of the table.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
TypeHandle is the identifier used to differentiate C++ class types.
static int clear_cache()
Empties the cache of composed RenderStates.
This is a sequence number that increments monotonically.
This is a global object that maintains the collection of named CullBins in the world.
int get_ref_count() const
Returns the current reference count.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Computes texture coordinates for geometry automatically based on vertex position and/or normal...
static void list_states(ostream &out)
Lists all of the RenderStates in the cache to the output stream, one per line.
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
void remove_element(int n)
Removes the nth slot from the table.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
static RenderAttribRegistry * quick_get_global_ptr()
Returns the global_ptr without first ensuring it has been initialized.
const Key & get_key(int n) const
Returns the key in the nth slot of the table.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
bool has_element(int n) const
Returns true if there is an element stored in the nth slot, false otherwise.
int get_num_on_bits() const
Returns the number of bits that are set to 1 in the mask.
int get_max_slots() const
Returns the maximum number that any slot number is allowed to grow.
static void init_states()
Make sure the global _states map is allocated.
static void bin_removed(int bin_index)
Intended to be called by CullBinManager::remove_bin(), this informs all the RenderStates in the world...