43 const RenderState *RenderState::_empty_state =
nullptr;
44 UpdateSeq RenderState::_last_cycle_detect;
45 size_t RenderState::_garbage_index = 0;
47 PStatCollector RenderState::_cache_update_pcollector(
"*:State Cache:Update");
48 PStatCollector RenderState::_garbage_collect_pcollector(
"*:State Cache:Garbage Collect");
49 PStatCollector RenderState::_state_compose_pcollector(
"*:State Cache:Compose State");
50 PStatCollector RenderState::_state_invert_pcollector(
"*:State Cache:Invert State");
51 PStatCollector RenderState::_node_counter(
"RenderStates:On nodes");
53 PStatCollector RenderState::_state_break_cycles_pcollector(
"*:State Cache:Break Cycles");
54 PStatCollector RenderState::_state_validate_pcollector(
"*:State Cache:Validate");
71 if (_states ==
nullptr) {
76 _cache_stats.add_num_states(1);
77 _read_overrides =
nullptr;
78 _generated_shader =
nullptr;
80 #ifdef DO_MEMORY_USAGE
90 _filled_slots(copy._filled_slots),
95 for (
int i = 0; i < RenderAttribRegistry::_max_slots; ++i) {
96 _attributes[i] = copy._attributes[i];
101 _cache_stats.add_num_states(1);
102 _read_overrides =
nullptr;
103 _generated_shader =
nullptr;
105 #ifdef DO_MEMORY_USAGE
117 nassertv(!is_destructing());
123 nassertv(_saved_entry == -1);
124 nassertv(_composition_cache.
is_empty() && _invert_composition_cache.
is_empty());
142 SlotMask mask = _filled_slots | other._filled_slots;
145 int result = _attributes[slot].compare_to(other._attributes[slot]);
165 if (
this == &other) {
172 for (
int n = 0; n < num_sorted_slots; ++n) {
174 nassertr((_attributes[slot]._attrib !=
nullptr) == _filled_slots.
get_bit(slot), 0);
177 const RenderAttrib *b = other._attributes[slot]._attrib;
179 return a < b ? -1 : 1;
197 const RenderAttrib *b = other._attributes[slot]._attrib;
199 return a < b ? -1 : 1;
218 const Attribute &attrib = _attributes[slot];
219 nassertr(attrib._attrib !=
nullptr,
false);
220 if (!attrib._attrib->cull_callback(trav, data)) {
237 int slot = attrib->get_slot();
238 state->_attributes[slot].set(attrib,
override);
239 state->_filled_slots.
set_bit(slot);
240 return return_new(state);
250 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
251 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
252 state->_filled_slots.
set_bit(attrib1->get_slot());
253 state->_filled_slots.
set_bit(attrib2->get_slot());
254 return return_new(state);
265 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
266 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
267 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
268 state->_filled_slots.
set_bit(attrib1->get_slot());
269 state->_filled_slots.
set_bit(attrib2->get_slot());
270 state->_filled_slots.
set_bit(attrib3->get_slot());
271 return return_new(state);
283 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
284 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
285 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
286 state->_attributes[attrib4->get_slot()].set(attrib4,
override);
287 state->_filled_slots.
set_bit(attrib1->get_slot());
288 state->_filled_slots.
set_bit(attrib2->get_slot());
289 state->_filled_slots.
set_bit(attrib3->get_slot());
290 state->_filled_slots.
set_bit(attrib4->get_slot());
291 return return_new(state);
304 state->_attributes[attrib1->get_slot()].set(attrib1,
override);
305 state->_attributes[attrib2->get_slot()].set(attrib2,
override);
306 state->_attributes[attrib3->get_slot()].set(attrib3,
override);
307 state->_attributes[attrib4->get_slot()].set(attrib4,
override);
308 state->_attributes[attrib5->get_slot()].set(attrib5,
override);
309 state->_filled_slots.
set_bit(attrib1->get_slot());
310 state->_filled_slots.
set_bit(attrib2->get_slot());
311 state->_filled_slots.
set_bit(attrib3->get_slot());
312 state->_filled_slots.
set_bit(attrib4->get_slot());
313 state->_filled_slots.
set_bit(attrib5->get_slot());
314 return return_new(state);
321 make(
const RenderAttrib *
const *attrib,
int num_attribs,
int override) {
322 if (num_attribs == 0) {
326 for (
int i = 0; i < num_attribs; i++) {
327 int slot = attrib[i]->get_slot();
328 state->_attributes[slot].set(attrib[i],
override);
329 state->_filled_slots.
set_bit(slot);
331 return return_new(state);
358 return do_compose(other);
364 int index = _composition_cache.
find(other);
366 Composition &comp = ((
RenderState *)
this)->_composition_cache.modify_data(index);
367 if (comp._result ==
nullptr) {
372 comp._result = result;
397 ((
RenderState *)
this)->_composition_cache[other]._result = result;
402 ((
RenderState *)other)->_composition_cache[
this]._result =
nullptr;
447 return do_invert_compose(other);
453 int index = _invert_composition_cache.
find(other);
455 Composition &comp = ((
RenderState *)
this)->_invert_composition_cache.modify_data(index);
456 if (comp._result ==
nullptr) {
460 CPT(
RenderState) result = do_invert_compose(other);
461 comp._result = result;
481 CPT(
RenderState) result = do_invert_compose(other);
485 ((
RenderState *)
this)->_invert_composition_cache[other]._result = result;
490 ((
RenderState *)other)->_invert_composition_cache[
this]._result =
nullptr;
513 add_attrib(
const RenderAttrib *attrib,
int override)
const {
514 int slot = attrib->get_slot();
515 if (_filled_slots.
get_bit(slot) &&
516 _attributes[slot]._override >
override) {
523 new_state->_attributes[slot].set(attrib,
override);
524 new_state->_filled_slots.
set_bit(slot);
525 return return_new(new_state);
537 int slot = attrib->get_slot();
538 new_state->_attributes[slot]._attrib = attrib;
539 new_state->_filled_slots.
set_bit(slot);
540 return return_new(new_state);
550 set_attrib(
const RenderAttrib *attrib,
int override)
const {
552 int slot = attrib->get_slot();
553 new_state->_attributes[slot].set(attrib,
override);
554 new_state->_filled_slots.
set_bit(slot);
555 return return_new(new_state);
563 remove_attrib(
int slot)
const {
564 if (_attributes[slot]._attrib ==
nullptr) {
575 new_state->_attributes[slot].set(
nullptr, 0);
576 new_state->_filled_slots.
clear_bit(slot);
577 return return_new(new_state);
587 adjust_all_priorities(
int adjustment)
const {
590 SlotMask mask = _filled_slots;
593 Attribute &attrib = new_state->_attributes[slot];
594 nassertr(attrib._attrib !=
nullptr,
this);
595 attrib._override = std::max(attrib._override + adjustment, 0);
597 mask.clear_bit(slot);
598 slot = mask.get_lowest_on_bit();
601 return return_new(new_state);
612 if (garbage_collect_states || !state_cache) {
628 if (auto_break_cycles && uniquify_states) {
656 output(ostream &out)
const {
663 const char *sep =
"";
665 SlotMask mask = _filled_slots;
668 const Attribute &attrib = _attributes[slot];
669 nassertv(attrib._attrib !=
nullptr);
670 out << sep << attrib._attrib->get_type();
673 mask.clear_bit(slot);
674 slot = mask.get_lowest_on_bit();
684 write(ostream &out,
int indent_level)
const {
690 SlotMask mask = _filled_slots;
693 const Attribute &attrib = _attributes[slot];
694 nassertv(attrib._attrib !=
nullptr);
695 attrib._attrib->write(out, indent_level);
697 mask.clear_bit(slot);
698 slot = mask.get_lowest_on_bit();
719 if (_states ==
nullptr) {
741 if (_states ==
nullptr) {
749 StateCount state_count;
752 for (
size_t si = 0; si < size; ++si) {
757 for (i = 0; i < cache_size; ++i) {
759 if (result !=
nullptr && result != state) {
761 std::pair<StateCount::iterator, bool> ir =
762 state_count.insert(StateCount::value_type(result, 1));
766 (*(ir.first)).second++;
771 for (i = 0; i < cache_size; ++i) {
773 if (result !=
nullptr && result != state) {
774 std::pair<StateCount::iterator, bool> ir =
775 state_count.insert(StateCount::value_type(result, 1));
777 (*(ir.first)).second++;
788 StateCount::iterator sci;
789 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
791 int count = (*sci).second;
797 if (pgraph_cat.is_debug()) {
799 <<
"Unused state: " << (
void *)state <<
":"
801 state->write(pgraph_cat.debug(
false), 2);
824 if (_states ==
nullptr) {
838 TempStates temp_states;
839 temp_states.reserve(orig_size);
842 for (
size_t si = 0; si < size; ++si) {
844 temp_states.push_back(state);
849 TempStates::iterator ti;
850 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
855 for (i = 0; i < cache_size; ++i) {
857 if (result !=
nullptr && result != state) {
858 result->cache_unref();
863 state->_composition_cache.
clear();
866 for (i = 0; i < cache_size; ++i) {
868 if (result !=
nullptr && result != state) {
869 result->cache_unref();
874 state->_invert_composition_cache.
clear();
883 return orig_size - new_size;
898 if (_states ==
nullptr || !garbage_collect_states) {
904 PStatTimer timer(_garbage_collect_pcollector);
908 size_t size = orig_size;
909 size_t num_this_pass = std::max(0,
int(size * garbage_collect_states_rate));
910 if (num_this_pass <= 0) {
914 bool break_and_uniquify = (auto_break_cycles && uniquify_transforms);
916 size_t si = _garbage_index;
921 num_this_pass = std::min(num_this_pass, size);
922 size_t stop_at_element = (si + num_this_pass) % size;
926 if (break_and_uniquify) {
933 state->detect_and_break_cycles();
943 state->release_new();
944 state->remove_cache_pointers();
945 state->cache_unref();
953 if (stop_at_element > 0) {
958 si = (si + 1) % size;
959 }
while (si != stop_at_element);
972 return (
int)orig_size - (int)size + num_attribs;
984 for (
size_t si = 0; si < size; ++si) {
986 state->_mungers.
clear();
987 state->_munged_states.
clear();
988 state->_last_mi = -1;
1007 if (_states ==
nullptr) {
1013 VisitedStates visited;
1017 for (
size_t si = 0; si < size; ++si) {
1020 bool inserted = visited.insert(state).second;
1022 ++_last_cycle_detect;
1023 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1025 CompositionCycleDesc::reverse_iterator csi;
1027 out <<
"\nCycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1028 <<
"state " << (
void *)state <<
":" << state->
get_ref_count()
1030 state->write(out, 2);
1031 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
1032 const CompositionCycleDescEntry &entry = (*csi);
1033 if (entry._inverted) {
1034 out <<
"invert composed with ";
1036 out <<
"composed with ";
1038 out << (
const void *)entry._obj <<
":" << entry._obj->get_ref_count()
1039 <<
" " << *entry._obj <<
"\n"
1040 <<
"produces " << (
const void *)entry._result <<
":"
1041 << entry._result->get_ref_count() <<
" =\n";
1042 entry._result->write(out, 2);
1043 visited.insert(entry._result);
1048 ++_last_cycle_detect;
1049 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1051 CompositionCycleDesc::iterator csi;
1053 out <<
"\nReverse cycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1055 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
1056 const CompositionCycleDescEntry &entry = (*csi);
1057 out << (
const void *)entry._result <<
":"
1058 << entry._result->get_ref_count() <<
" =\n";
1059 entry._result->write(out, 2);
1060 out << (
const void *)entry._obj <<
":"
1061 << entry._obj->get_ref_count() <<
" =\n";
1062 entry._obj->write(out, 2);
1063 visited.insert(entry._result);
1065 out << (
void *)state <<
":"
1067 state->write(out, 2);
1084 if (_states ==
nullptr) {
1085 out <<
"0 states:\n";
1091 out << size <<
" states:\n";
1092 for (
size_t si = 0; si < size; ++si) {
1094 state->write(out, 2);
1106 if (_states ==
nullptr) {
1110 PStatTimer timer(_state_validate_pcollector);
1119 <<
"RenderState::_states cache is invalid!\n";
1125 nassertr(si < size,
false);
1126 nassertr(_states->
get_key(si)->get_ref_count() >= 0,
false);
1129 while (snext < size) {
1130 nassertr(_states->
get_key(snext)->get_ref_count() >= 0,
false);
1135 if ((ci < 0) != (c > 0) ||
1136 (ci > 0) != (c < 0) ||
1137 (ci == 0) != (c == 0)) {
1139 <<
"RenderState::compare_to() not defined properly!\n";
1140 pgraph_cat.error(
false)
1141 <<
"(a, b): " << c <<
"\n";
1142 pgraph_cat.error(
false)
1143 <<
"(b, a): " << ci <<
"\n";
1144 ssi->write(pgraph_cat.error(
false), 2);
1145 ssnext->write(pgraph_cat.error(
false), 2);
1166 if (get_attrib(render_mode)) {
1169 if (get_attrib(tex_gen)) {
1172 if (get_attrib(tex_matrix)) {
1176 return geom_rendering;
1195 validate_filled_slots()
const {
1199 int max_slots = reg->get_max_slots();
1200 for (
int slot = 1; slot < max_slots; ++slot) {
1201 const Attribute &attribute = _attributes[slot];
1202 if (attribute._attrib !=
nullptr) {
1207 return (mask == _filled_slots);
1217 SlotMask mask = _filled_slots;
1220 const Attribute &attrib = _attributes[slot];
1221 nassertv(attrib._attrib !=
nullptr);
1225 mask.clear_bit(slot);
1226 slot = mask.get_lowest_on_bit();
1229 _flags |= F_hash_known;
1241 nassertr(state !=
nullptr, state);
1246 if (state->_attributes[0]._attrib !=
nullptr) {
1247 const RenderAttrib *attrib = state->_attributes[0]._attrib;
1248 if (attrib->get_type() == TypeHandle::none()) {
1251 <<
"Uninitialized RenderAttrib type: " << attrib->get_type()
1256 if (already_reported.insert(attrib->get_type()).second) {
1258 << attrib->get_type() <<
" did not initialize its slot number.\n";
1263 state->_attributes[0]._attrib =
nullptr;
1267 nassertr(state->validate_filled_slots(), state);
1270 if (!uniquify_states && !state->
is_empty()) {
1274 return return_unique(state);
1287 nassertr(state !=
nullptr,
nullptr);
1294 if (paranoid_const) {
1301 if (state->_saved_entry != -1) {
1309 if (!uniquify_attribs && !state->
is_empty()) {
1310 SlotMask mask = state->_filled_slots;
1313 Attribute &attrib = state->_attributes[slot];
1314 nassertd(attrib._attrib !=
nullptr) continue;
1315 attrib._attrib = attrib._attrib->get_unique();
1316 mask.clear_bit(slot);
1321 int si = _states->find(state);
1326 if (state->get_ref_count() == 0) {
1333 if (garbage_collect_states) {
1339 si = _states->
store(state,
nullptr);
1342 state->_saved_entry = si;
1356 SlotMask mask = _filled_slots | other->_filled_slots;
1357 new_state->_filled_slots = mask;
1361 const Attribute &a = _attributes[slot];
1362 const Attribute &b = other->_attributes[slot];
1363 Attribute &result = new_state->_attributes[slot];
1365 if (a._attrib ==
nullptr) {
1366 nassertr(b._attrib !=
nullptr,
this);
1370 }
else if (b._attrib ==
nullptr) {
1374 }
else if (b._override < a._override) {
1378 }
else if (a._override < b._override &&
1379 a._attrib->lower_attrib_can_override()) {
1391 result.set(a._attrib->compose(b._attrib), b._override);
1394 mask.clear_bit(slot);
1395 slot = mask.get_lowest_on_bit();
1398 return return_new(new_state);
1405 do_invert_compose(
const RenderState *other)
const {
1410 SlotMask mask = _filled_slots | other->_filled_slots;
1411 new_state->_filled_slots = mask;
1415 const Attribute &a = _attributes[slot];
1416 const Attribute &b = other->_attributes[slot];
1417 Attribute &result = new_state->_attributes[slot];
1419 if (a._attrib ==
nullptr) {
1420 nassertr(b._attrib !=
nullptr,
this);
1424 }
else if (b._attrib ==
nullptr) {
1431 result.set(a._attrib->invert_compose(b._attrib), 0);
1434 mask.clear_bit(slot);
1435 slot = mask.get_lowest_on_bit();
1437 return return_new(new_state);
1445 detect_and_break_cycles() {
1446 PStatTimer timer(_state_break_cycles_pcollector);
1448 ++_last_cycle_detect;
1449 if (r_detect_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1452 if (pgraph_cat.is_debug()) {
1454 <<
"Breaking cycle involving " << (*this) <<
"\n";
1459 ++_last_cycle_detect;
1460 if (r_detect_reverse_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1461 if (pgraph_cat.is_debug()) {
1463 <<
"Breaking cycle involving " << (*this) <<
"\n";
1483 if (current_state->_cycle_detect == this_seq) {
1489 return (current_state == start_state && length > 2);
1491 ((
RenderState *)current_state)->_cycle_detect = this_seq;
1494 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1495 for (i = 0; i < cache_size; ++i) {
1497 if (result !=
nullptr) {
1498 if (r_detect_cycles(start_state, result, length + 1,
1499 this_seq, cycle_desc)) {
1501 if (cycle_desc !=
nullptr) {
1503 CompositionCycleDescEntry entry(other, result,
false);
1504 cycle_desc->push_back(entry);
1511 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1512 for (i = 0; i < cache_size; ++i) {
1514 if (result !=
nullptr) {
1515 if (r_detect_cycles(start_state, result, length + 1,
1516 this_seq, cycle_desc)) {
1518 if (cycle_desc !=
nullptr) {
1520 CompositionCycleDescEntry entry(other, result,
true);
1521 cycle_desc->push_back(entry);
1538 r_detect_reverse_cycles(
const RenderState *start_state,
1542 if (current_state->_cycle_detect == this_seq) {
1548 return (current_state == start_state && length > 2);
1550 ((
RenderState *)current_state)->_cycle_detect = this_seq;
1553 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1554 for (i = 0; i < cache_size; ++i) {
1556 if (other != current_state) {
1557 int oi = other->_composition_cache.
find(current_state);
1558 nassertr(oi != -1,
false);
1561 if (result !=
nullptr) {
1562 if (r_detect_reverse_cycles(start_state, result, length + 1,
1563 this_seq, cycle_desc)) {
1565 if (cycle_desc !=
nullptr) {
1567 CompositionCycleDescEntry entry(other, result,
false);
1568 cycle_desc->push_back(entry);
1576 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1577 for (i = 0; i < cache_size; ++i) {
1579 if (other != current_state) {
1580 int oi = other->_invert_composition_cache.
find(current_state);
1581 nassertr(oi != -1,
false);
1584 if (result !=
nullptr) {
1585 if (r_detect_reverse_cycles(start_state, result, length + 1,
1586 this_seq, cycle_desc)) {
1588 if (cycle_desc !=
nullptr) {
1590 CompositionCycleDescEntry entry(other, result,
false);
1591 cycle_desc->push_back(entry);
1613 if (_saved_entry != -1) {
1615 nassertv_always(_states->
remove(
this));
1627 remove_cache_pointers() {
1645 if (_composition_cache.
is_empty() && _invert_composition_cache.
is_empty()) {
1654 while (!_composition_cache.
is_empty()) {
1665 Composition comp = _composition_cache.
get_data(i);
1674 if (other !=
this) {
1675 int oi = other->_composition_cache.
find(
this);
1681 Composition ocomp = other->_composition_cache.
get_data(oi);
1690 if (ocomp._result !=
nullptr && ocomp._result != other) {
1698 if (comp._result !=
nullptr && comp._result !=
this) {
1705 while (!_invert_composition_cache.
is_empty()) {
1707 nassertv(other !=
this);
1708 Composition comp = _invert_composition_cache.
get_data(i);
1712 if (other !=
this) {
1713 int oi = other->_invert_composition_cache.
find(
this);
1715 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
1719 if (ocomp._result !=
nullptr && ocomp._result != other) {
1724 if (comp._result !=
nullptr && comp._result !=
this) {
1734 determine_bin_index() {
1736 if ((_flags & F_checked_bin_index) != 0) {
1741 std::string bin_name;
1745 if (get_attrib(bin)) {
1750 if (bin_name.empty()) {
1753 bin_name =
"opaque";
1756 if (get_attrib(transparency)) {
1757 switch (transparency->
get_mode()) {
1758 case TransparencyAttrib::M_alpha:
1759 case TransparencyAttrib::M_premultiplied_alpha:
1760 case TransparencyAttrib::M_dual:
1762 bin_name =
"transparent";
1772 _bin_index = bin_manager->
find_bin(bin_name);
1773 if (_bin_index == -1) {
1774 pgraph_cat.warning()
1775 <<
"No bin named " << bin_name <<
"; creating default bin.\n";
1776 _bin_index = bin_manager->
add_bin(bin_name, CullBinManager::BT_unsorted, 0);
1778 _flags |= F_checked_bin_index;
1785 determine_cull_callback() {
1787 if ((_flags & F_checked_cull_callback) != 0) {
1792 SlotMask mask = _filled_slots;
1795 const Attribute &attrib = _attributes[slot];
1796 nassertv(attrib._attrib !=
nullptr);
1797 if (attrib._attrib->has_cull_callback()) {
1798 _flags |= F_has_cull_callback;
1802 mask.clear_bit(slot);
1803 slot = mask.get_lowest_on_bit();
1806 _flags |= F_checked_cull_callback;
1816 for (
int slot = 1; slot < num_slots; ++slot) {
1828 update_pstats(
int old_referenced_bits,
int new_referenced_bits) {
1830 if ((old_referenced_bits & R_node) != 0) {
1831 _node_counter.sub_level(1);
1832 }
else if ((old_referenced_bits & R_cache) != 0) {
1833 _cache_counter.sub_level(1);
1835 if ((new_referenced_bits & R_node) != 0) {
1836 _node_counter.add_level(1);
1837 }
else if ((new_referenced_bits & R_cache) != 0) {
1838 _cache_counter.add_level(1);
1858 _states_lock =
new LightReMutex(
"RenderState::_states_lock");
1859 _cache_stats.
init();
1866 state->_saved_entry = _states->
store(state,
nullptr);
1867 _empty_state = state;
1887 nassertv(num_attribs == (
int)(uint16_t)num_attribs);
1895 const Attribute &attrib = _attributes[slot];
1896 nassertv(attrib._attrib !=
nullptr);
1913 int num_attribs = 0;
1916 for (
size_t i = 0; i < (*_read_overrides).size(); ++i) {
1917 int override = (*_read_overrides)[i];
1920 if (attrib !=
nullptr) {
1921 int slot = attrib->get_slot();
1922 if (slot > 0 && slot < reg->get_max_slots()) {
1923 _attributes[slot].set(attrib,
override);
1930 delete _read_overrides;
1931 _read_overrides =
nullptr;
1954 if (pointer == state) {
1994 state->fillin(scan, manager);
2009 _read_overrides =
new vector_int;
2010 (*_read_overrides).reserve(num_attribs);
2012 for (
int i = 0; i < num_attribs; ++i) {
2015 (*_read_overrides).push_back(
override);