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" 45 UpdateSeq RenderState::_last_cycle_detect;
46 int RenderState::_garbage_index = 0;
48 PStatCollector RenderState::_cache_update_pcollector(
"*:State Cache:Update");
49 PStatCollector RenderState::_garbage_collect_pcollector(
"*:State Cache:Garbage Collect");
50 PStatCollector RenderState::_state_compose_pcollector(
"*:State Cache:Compose State");
51 PStatCollector RenderState::_state_invert_pcollector(
"*:State Cache:Invert State");
52 PStatCollector RenderState::_node_counter(
"RenderStates:On nodes");
54 PStatCollector RenderState::_state_break_cycles_pcollector(
"*:State Cache:Break Cycles");
55 PStatCollector RenderState::_state_validate_pcollector(
"*:State Cache:Validate");
72 _auto_shader_state(NULL),
81 new(&_attributes[i]) Attribute();
84 if (_states == (States *)NULL) {
88 _last_mi = _mungers.end();
90 _read_overrides = NULL;
91 _generated_shader = NULL;
101 _filled_slots(copy._filled_slots),
103 _auto_shader_state(NULL),
112 new(&_attributes[i]) Attribute(copy._attributes[i]);
116 _last_mi = _mungers.end();
118 _read_overrides = NULL;
119 _generated_shader = NULL;
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;
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)) {
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);
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);
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);
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);
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);
386 make(
const RenderAttrib *
const *attrib,
int num_attribs,
int override) {
387 if (num_attribs == 0) {
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);
427 return do_compose(other);
433 int index = _composition_cache.
find(other);
435 Composition &comp = ((
RenderState *)
this)->_composition_cache.modify_data(index);
441 comp._result = result;
467 ((
RenderState *)
this)->_composition_cache[other]._result = result;
472 ((
RenderState *)other)->_composition_cache[
this]._result = NULL;
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);
535 CPT(
RenderState) result = do_invert_compose(other);
536 comp._result = result;
557 CPT(
RenderState) result = do_invert_compose(other);
561 ((
RenderState *)
this)->_invert_composition_cache[other]._result = result;
566 ((
RenderState *)other)->_invert_composition_cache[
this]._result = NULL;
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) {
604 new_state->_attributes[slot].set(attrib,
override);
605 new_state->_filled_slots.
set_bit(slot);
606 return return_new(new_state);
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);
637 set_attrib(
const RenderAttrib *attrib,
int override)
const {
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);
653 remove_attrib(
int slot)
const {
654 if (_attributes[slot]._attrib == NULL) {
665 new_state->_attributes[slot].set(NULL, 0);
666 new_state->_filled_slots.
clear_bit(slot);
667 return return_new(new_state);
680 adjust_all_priorities(
int adjustment)
const {
686 Attribute &attrib = new_state->_attributes[slot];
688 attrib._override = max(attrib._override + adjustment, 0);
694 return return_new(new_state);
709 if (!state_cache || garbage_collect_states) {
725 if (auto_break_cycles && uniquify_states) {
766 get_auto_shader_state()
const {
767 if (_auto_shader_state == (
const RenderState *)NULL) {
770 return _auto_shader_state;
779 output(ostream &out)
const {
786 const char *sep =
"";
791 const Attribute &attrib = _attributes[slot];
793 out << sep << attrib._attrib->get_type();
809 write(ostream &out,
int indent_level)
const {
811 indent(out, indent_level)
818 const Attribute &attrib = _attributes[slot];
820 attrib._attrib->write(out, indent_level);
851 if (_states == (
States *)NULL) {
878 if (_states == (
States *)NULL) {
886 StateCount state_count;
889 for (
int si = 0; si < size; ++si) {
896 int cache_size = state->_composition_cache.
get_size();
897 for (i = 0; i < cache_size; ++i) {
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)) {
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) {
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) {
999 temp_states.push_back(state);
1005 TempStates::iterator ti;
1006 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
1010 int cache_size = state->_composition_cache.
get_size();
1011 for (i = 0; i < cache_size; ++i) {
1014 if (result != (
const RenderState *)NULL && result != state) {
1015 result->cache_unref();
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)) {
1027 if (result != (
const RenderState *)NULL && result != state) {
1028 result->cache_unref();
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;
1086 if (auto_break_cycles && uniquify_states) {
1093 state->detect_and_break_cycles();
1104 state->release_new();
1105 state->remove_cache_pointers();
1106 state->cache_unref();
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) {
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) {
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) {
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);
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);
1408 const Attribute &attrib = _attributes[slot];
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();
1450 do_calc_auto_shader_state() {
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);
1469 return return_new(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;
1511 nassertr(state->validate_filled_slots(), state);
1514 if (!uniquify_states && !state->
is_empty()) {
1518 return return_unique(state);
1542 if (paranoid_const) {
1549 if (state->_saved_entry != -1) {
1561 if (!uniquify_attribs && !state->
is_empty()) {
1562 SlotMask mask = state->_filled_slots;
1565 Attribute &attrib = state->_attributes[slot];
1566 nassertr(attrib._attrib != (
RenderAttrib *)NULL, state);
1567 attrib._attrib = attrib._attrib->get_unique();
1573 int si = _states->
find(state);
1580 if (garbage_collect_states) {
1586 si = _states->
store(state, Empty());
1589 state->_saved_entry = si;
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);
1654 if (sattrib->auto_shader()) {
1655 sattrib = DCAST(
ShaderAttrib, sattrib->clear_all_shader_inputs());
1658 return return_new(new_state);
1667 do_invert_compose(
const RenderState *other)
const {
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);
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";
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";
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)) {
1771 if (r_detect_cycles(start_state, result, length + 1,
1772 this_seq, cycle_desc)) {
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)) {
1790 if (r_detect_cycles(start_state, result, length + 1,
1791 this_seq, cycle_desc)) {
1795 CompositionCycleDescEntry entry(other, result,
true);
1796 cycle_desc->push_back(entry);
1817 r_detect_reverse_cycles(
const RenderState *start_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)) {
1837 if (other != current_state) {
1838 int oi = other->_composition_cache.
find(current_state);
1839 nassertr(oi != -1,
false);
1843 if (r_detect_reverse_cycles(start_state, result, length + 1,
1844 this_seq, cycle_desc)) {
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)) {
1862 if (other != current_state) {
1863 int oi = other->_invert_composition_cache.
find(current_state);
1864 nassertr(oi != -1,
false);
1868 if (r_detect_reverse_cycles(start_state, result, length + 1,
1869 this_seq, cycle_desc)) {
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()) {
1973 Composition comp = _composition_cache.
get_data(i);
1983 if (other !=
this) {
1984 int oi = other->_composition_cache.
find(
this);
1991 Composition ocomp = other->_composition_cache.
get_data(oi);
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)) {
2022 nassertv(other !=
this);
2023 Composition comp = _invert_composition_cache.
get_data(i);
2027 if (other !=
this) {
2028 int oi = other->_invert_composition_cache.
find(
this);
2030 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
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) {
2115 const Attribute &attrib = _attributes[slot];
2117 if (attrib._attrib->has_cull_callback()) {
2118 _flags |= F_has_cull_callback;
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;
2289 if (pointer == state) {
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.
bool is_empty() const
Returns true if the state is empty, false otherwise.
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
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.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
static TypeHandle none()
Returns a special zero-valued TypeHandle that is used to indicate no type.
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...
void inc_dels()
Increments by 1 the count of elements removed from the cache.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
This controls the enabling of transparency.
Mode get_mode() const
Returns the transparency mode.
Base class for objects that can be written to and read from Bam files.
static void clear_munger_cache()
Completely empties the cache of state + gsg -> munger, for all states and all gsg's.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
A lightweight reentrant mutex.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
int store(const Key &key, const Value &data)
Records the indicated key/data pair in the map.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
int get_draw_order() const
Returns the draw order this attribute specifies.
int get_num_slots() const
Returns the number of RenderAttrib slots that have been allocated.
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 ...
const Key & get_key(int n) const
Returns the key in the nth slot of the table.
void clear()
Completely empties the table.
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.
int get_cache_ref_count() const
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
int get_num_entries() const
Returns the number of active entries in the table.
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...
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.
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 CullBinManager * get_global_ptr()
Returns the pointer to the global CullBinManager object.
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...
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
A lightweight class that represents a single element that may be timed and/or counted via stats...
void maybe_report(const char *name)
Outputs a report if enough time has elapsed.
void inc_hits()
Increments by 1 the count of cache hits.
static void list_cycles(ostream &out)
Detects all of the reference-count cycles in the cache and reports them to standard output...
bool has_element(int n) const
Returns true if there is an element stored in the nth slot, false otherwise.
int get_lowest_on_bit() const
Returns the index of the lowest 1 bit in the mask.
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()...
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...
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.
void inc_misses()
Increments by 1 the count of cache misses.
static bool validate_states()
Ensures that the cache is still stored in sorted order, and that none of the cache elements have been...
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.
int get_sorted_slot(int n) const
Returns the nth slot in sorted order.
Similar to MutexHolder, but for a light mutex.
void init()
Initializes the CacheStats for the first time.
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...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void add_total_size(int count)
Adds the indicated count (positive or negative) to the total number of entries for the cache (net occ...
bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
Calls cull_callback() on each attrib.
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...
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...
bool validate() const
Returns true if the internal table appears to be consistent, false if there are some internal errors...
void set_bit(int index)
Sets the nth bit on.
Similar to MutexHolder, but for a light reentrant mutex.
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.
int get_num_sorted_slots() const
Returns the number of entries in the sorted_slots list.
int get_ref_count() const
Returns the current reference count.
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.
int add_bin(const string &name, BinType type, int sort)
Defines a new bin with the indicated name, and returns the new bin_index.
const Value & get_data(int n) const
Returns the data in the nth slot of the table.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
void add_num_states(int count)
Adds the indicated count (positive or negative) to the total count of individual RenderState or Trans...
This is used to track the utilization of the TransformState and RenderState caches, for low-level performance tuning information.
bool is_empty() const
Returns true if the table is empty; i.e.
DeletedBufferChain * get_array_chain() const
Returns the DeletedBufferChain object that may be used to allocated appropriately-sized arrays of Ren...
const string & get_bin_name() const
Returns the name of the bin this attribute specifies.
Specifies how polygons are to be drawn.
This is our own Panda specialization on the default STL set.
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...
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
int get_num_on_bits() const
Returns the number of bits that are set to 1 in the mask.
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 get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this RenderModeAttrib is...
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.
void inc_adds(bool is_new)
Increments by 1 the count of elements added to the cache.
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...
int compare_to(const RenderState &other) const
Provides an arbitrary ordering among all unique RenderStates, so we can store the essentially differe...
static void list_states(ostream &out)
Lists all of the RenderStates in the cache to the output stream, one per line.
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...
int get_geom_rendering(int geom_rendering) const
Returns the union of the Geom::GeomRendering bits that will be required once this TexMatrixAttrib is ...
static RenderAttribRegistry * quick_get_global_ptr()
Returns the global_ptr without first ensuring it has been initialized.
int get_size() const
Returns the total number of slots in the table.
int get_max_slots() const
Returns the maximum number that any slot number is allowed to grow.
virtual bool unref() const
Explicitly decrements the reference count.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
int find(const Key &key) const
Searches for the indicated key in the table.
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
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...