00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "renderState.h"
00016 #include "transparencyAttrib.h"
00017 #include "cullBinAttrib.h"
00018 #include "cullBinManager.h"
00019 #include "fogAttrib.h"
00020 #include "clipPlaneAttrib.h"
00021 #include "scissorAttrib.h"
00022 #include "transparencyAttrib.h"
00023 #include "colorAttrib.h"
00024 #include "colorScaleAttrib.h"
00025 #include "textureAttrib.h"
00026 #include "texGenAttrib.h"
00027 #include "shaderAttrib.h"
00028 #include "pStatTimer.h"
00029 #include "config_pgraph.h"
00030 #include "bamReader.h"
00031 #include "bamWriter.h"
00032 #include "datagramIterator.h"
00033 #include "indent.h"
00034 #include "compareTo.h"
00035 #include "lightReMutexHolder.h"
00036 #include "lightMutexHolder.h"
00037 #include "thread.h"
00038 #include "renderAttribRegistry.h"
00039 #include "py_panda.h"
00040
00041 LightReMutex *RenderState::_states_lock = NULL;
00042 RenderState::States *RenderState::_states = NULL;
00043 CPT(RenderState) RenderState::_empty_state;
00044 CPT(RenderState) RenderState::_full_default_state;
00045 UpdateSeq RenderState::_last_cycle_detect;
00046 int RenderState::_garbage_index = 0;
00047
00048 PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update");
00049 PStatCollector RenderState::_garbage_collect_pcollector("*:State Cache:Garbage Collect");
00050 PStatCollector RenderState::_state_compose_pcollector("*:State Cache:Compose State");
00051 PStatCollector RenderState::_state_invert_pcollector("*:State Cache:Invert State");
00052 PStatCollector RenderState::_node_counter("RenderStates:On nodes");
00053 PStatCollector RenderState::_cache_counter("RenderStates:Cached");
00054 PStatCollector RenderState::_state_break_cycles_pcollector("*:State Cache:Break Cycles");
00055 PStatCollector RenderState::_state_validate_pcollector("*:State Cache:Validate");
00056
00057 CacheStats RenderState::_cache_stats;
00058
00059 TypeHandle RenderState::_type_handle;
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 RenderState::
00070 RenderState() :
00071 _flags(0),
00072 _auto_shader_state(NULL),
00073 _lock("RenderState")
00074 {
00075
00076 RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
00077 _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type());
00078
00079
00080 for (int i = 0; i < reg->get_max_slots(); ++i) {
00081 new(&_attributes[i]) Attribute();
00082 }
00083
00084 if (_states == (States *)NULL) {
00085 init_states();
00086 }
00087 _saved_entry = -1;
00088 _last_mi = _mungers.end();
00089 _cache_stats.add_num_states(1);
00090 _read_overrides = NULL;
00091 _generated_shader = NULL;
00092 }
00093
00094
00095
00096
00097
00098
00099 RenderState::
00100 RenderState(const RenderState ©) :
00101 _filled_slots(copy._filled_slots),
00102 _flags(0),
00103 _auto_shader_state(NULL),
00104 _lock("RenderState")
00105 {
00106
00107 RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
00108 _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type());
00109
00110
00111 for (int i = 0; i < reg->get_max_slots(); ++i) {
00112 new(&_attributes[i]) Attribute(copy._attributes[i]);
00113 }
00114
00115 _saved_entry = -1;
00116 _last_mi = _mungers.end();
00117 _cache_stats.add_num_states(1);
00118 _read_overrides = NULL;
00119 _generated_shader = NULL;
00120 }
00121
00122
00123
00124
00125
00126
00127 void RenderState::
00128 operator = (const RenderState &) {
00129 nassertv(false);
00130 }
00131
00132
00133
00134
00135
00136
00137
00138 RenderState::
00139 ~RenderState() {
00140
00141 nassertv(!is_destructing());
00142 set_destructing();
00143
00144 LightReMutexHolder holder(*_states_lock);
00145
00146
00147 nassertv(_saved_entry == -1);
00148 nassertv(_composition_cache.is_empty() && _invert_composition_cache.is_empty());
00149
00150
00151 if (_auto_shader_state != (const RenderState *)NULL) {
00152 if (_auto_shader_state != this) {
00153 cache_unref_delete(_auto_shader_state);
00154 }
00155 _auto_shader_state = NULL;
00156 }
00157
00158
00159
00160 nassertv(get_ref_count() == 0);
00161 _cache_stats.add_num_states(-1);
00162
00163
00164 RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
00165 for (int i = 0; i < reg->get_max_slots(); ++i) {
00166 _attributes[i].~Attribute();
00167 }
00168 reg->get_array_chain()->deallocate(_attributes, get_class_type());
00169 _attributes = NULL;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 int RenderState::
00185 compare_to(const RenderState &other) const {
00186 SlotMask mask = _filled_slots | other._filled_slots;
00187 int slot = mask.get_lowest_on_bit();
00188 while (slot >= 0) {
00189 int result = _attributes[slot].compare_to(other._attributes[slot]);
00190 if (result != 0) {
00191 return result;
00192 }
00193 mask.clear_bit(slot);
00194 slot = mask.get_lowest_on_bit();
00195 }
00196
00197 return 0;
00198 }
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 int RenderState::
00211 compare_sort(const RenderState &other) const {
00212 if (this == &other) {
00213
00214 return 0;
00215 }
00216
00217 RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
00218 int num_sorted_slots = reg->get_num_sorted_slots();
00219 for (int n = 0; n < num_sorted_slots; ++n) {
00220 int slot = reg->get_sorted_slot(n);
00221 nassertr((_attributes[slot]._attrib != NULL) == _filled_slots.get_bit(slot), 0);
00222
00223 const RenderAttrib *a = _attributes[slot]._attrib;
00224 const RenderAttrib *b = other._attributes[slot]._attrib;
00225 if (a != b) {
00226 return a < b ? -1 : 1;
00227 }
00228 }
00229
00230 return 0;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 bool RenderState::
00242 cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
00243 SlotMask mask = _filled_slots;
00244 int slot = mask.get_lowest_on_bit();
00245 while (slot >= 0) {
00246 const Attribute &attrib = _attributes[slot];
00247 nassertr(attrib._attrib != NULL, false);
00248 if (!attrib._attrib->cull_callback(trav, data)) {
00249 return false;
00250 }
00251
00252 mask.clear_bit(slot);
00253 slot = mask.get_lowest_on_bit();
00254 }
00255
00256 return true;
00257 }
00258
00259
00260
00261
00262
00263
00264 CPT(RenderState) RenderState::
00265 make_empty() {
00266
00267
00268 if (_empty_state == (RenderState *)NULL) {
00269 RenderState *state = new RenderState;
00270 _empty_state = return_unique(state);
00271 }
00272
00273 return _empty_state;
00274 }
00275
00276
00277
00278
00279
00280
00281
00282 CPT(RenderState) RenderState::
00283 make_full_default() {
00284
00285
00286 if (_full_default_state == (RenderState *)NULL) {
00287 RenderState *state = new RenderState;
00288 state->fill_default();
00289 _full_default_state = return_unique(state);
00290 }
00291
00292 return _full_default_state;
00293 }
00294
00295
00296
00297
00298
00299
00300 CPT(RenderState) RenderState::
00301 make(const RenderAttrib *attrib, int override) {
00302 RenderState *state = new RenderState;
00303 int slot = attrib->get_slot();
00304 state->_attributes[slot].set(attrib, override);
00305 state->_filled_slots.set_bit(slot);
00306 return return_new(state);
00307 }
00308
00309
00310
00311
00312
00313
00314 CPT(RenderState) RenderState::
00315 make(const RenderAttrib *attrib1,
00316 const RenderAttrib *attrib2, int override) {
00317 RenderState *state = new RenderState;
00318 state->_attributes[attrib1->get_slot()].set(attrib1, override);
00319 state->_attributes[attrib2->get_slot()].set(attrib2, override);
00320 state->_filled_slots.set_bit(attrib1->get_slot());
00321 state->_filled_slots.set_bit(attrib2->get_slot());
00322 return return_new(state);
00323 }
00324
00325
00326
00327
00328
00329
00330 CPT(RenderState) RenderState::
00331 make(const RenderAttrib *attrib1,
00332 const RenderAttrib *attrib2,
00333 const RenderAttrib *attrib3, int override) {
00334 RenderState *state = new RenderState;
00335 state->_attributes[attrib1->get_slot()].set(attrib1, override);
00336 state->_attributes[attrib2->get_slot()].set(attrib2, override);
00337 state->_attributes[attrib3->get_slot()].set(attrib3, override);
00338 state->_filled_slots.set_bit(attrib1->get_slot());
00339 state->_filled_slots.set_bit(attrib2->get_slot());
00340 state->_filled_slots.set_bit(attrib3->get_slot());
00341 return return_new(state);
00342 }
00343
00344
00345
00346
00347
00348
00349 CPT(RenderState) RenderState::
00350 make(const RenderAttrib *attrib1,
00351 const RenderAttrib *attrib2,
00352 const RenderAttrib *attrib3,
00353 const RenderAttrib *attrib4, int override) {
00354 RenderState *state = new RenderState;
00355 state->_attributes[attrib1->get_slot()].set(attrib1, override);
00356 state->_attributes[attrib2->get_slot()].set(attrib2, override);
00357 state->_attributes[attrib3->get_slot()].set(attrib3, override);
00358 state->_attributes[attrib4->get_slot()].set(attrib4, override);
00359 state->_filled_slots.set_bit(attrib1->get_slot());
00360 state->_filled_slots.set_bit(attrib2->get_slot());
00361 state->_filled_slots.set_bit(attrib3->get_slot());
00362 state->_filled_slots.set_bit(attrib4->get_slot());
00363 return return_new(state);
00364 }
00365
00366
00367
00368
00369
00370
00371 CPT(RenderState) RenderState::
00372 make(const RenderAttrib * const *attrib, int num_attribs, int override) {
00373 if (num_attribs == 0) {
00374 return make_empty();
00375 }
00376 RenderState *state = new RenderState;
00377 for (int i = 0; i < num_attribs; i++) {
00378 int slot = attrib[i]->get_slot();
00379 state->_attributes[slot].set(attrib[i], override);
00380 state->_filled_slots.set_bit(slot);
00381 }
00382 return return_new(state);
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 CPT(RenderState) RenderState::
00399 compose(const RenderState *other) const {
00400
00401
00402
00403
00404
00405 if (is_empty()) {
00406 return other;
00407 }
00408 if (other->is_empty()) {
00409 return this;
00410 }
00411
00412 if (!state_cache) {
00413 return do_compose(other);
00414 }
00415
00416 LightReMutexHolder holder(*_states_lock);
00417
00418
00419 int index = _composition_cache.find(other);
00420 if (index != -1) {
00421 Composition &comp = ((RenderState *)this)->_composition_cache.modify_data(index);
00422 if (comp._result == (const RenderState *)NULL) {
00423
00424
00425
00426 CPT(RenderState) result = do_compose(other);
00427 comp._result = result;
00428
00429 if (result != (const RenderState *)this) {
00430
00431
00432 result->cache_ref();
00433 }
00434 }
00435
00436 _cache_stats.inc_hits();
00437 return comp._result;
00438 }
00439 _cache_stats.inc_misses();
00440
00441
00442
00443
00444
00445
00446
00447
00448 CPT(RenderState) result = do_compose(other);
00449
00450 _cache_stats.add_total_size(1);
00451 _cache_stats.inc_adds(_composition_cache.get_size() == 0);
00452
00453 ((RenderState *)this)->_composition_cache[other]._result = result;
00454
00455 if (other != this) {
00456 _cache_stats.add_total_size(1);
00457 _cache_stats.inc_adds(other->_composition_cache.get_size() == 0);
00458 ((RenderState *)other)->_composition_cache[this]._result = NULL;
00459 }
00460
00461 if (result != (const RenderState *)this) {
00462
00463
00464
00465
00466 result->cache_ref();
00467
00468
00469
00470
00471 }
00472
00473 _cache_stats.maybe_report("RenderState");
00474
00475 return result;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 CPT(RenderState) RenderState::
00490 invert_compose(const RenderState *other) const {
00491
00492
00493
00494
00495
00496 if (is_empty()) {
00497 return other;
00498 }
00499
00500
00501
00502 if (other == this) {
00503
00504 return make_empty();
00505 }
00506
00507 if (!state_cache) {
00508 return do_invert_compose(other);
00509 }
00510
00511 LightReMutexHolder holder(*_states_lock);
00512
00513
00514 int index = _invert_composition_cache.find(other);
00515 if (index != -1) {
00516 Composition &comp = ((RenderState *)this)->_invert_composition_cache.modify_data(index);
00517 if (comp._result == (const RenderState *)NULL) {
00518
00519
00520
00521 CPT(RenderState) result = do_invert_compose(other);
00522 comp._result = result;
00523
00524 if (result != (const RenderState *)this) {
00525
00526
00527 result->cache_ref();
00528 }
00529 }
00530
00531 _cache_stats.inc_hits();
00532 return comp._result;
00533 }
00534 _cache_stats.inc_misses();
00535
00536
00537
00538
00539
00540
00541
00542
00543 CPT(RenderState) result = do_invert_compose(other);
00544
00545 _cache_stats.add_total_size(1);
00546 _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0);
00547 ((RenderState *)this)->_invert_composition_cache[other]._result = result;
00548
00549 if (other != this) {
00550 _cache_stats.add_total_size(1);
00551 _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0);
00552 ((RenderState *)other)->_invert_composition_cache[this]._result = NULL;
00553 }
00554
00555 if (result != (const RenderState *)this) {
00556
00557
00558
00559
00560 result->cache_ref();
00561
00562
00563
00564
00565 }
00566
00567 return result;
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 CPT(RenderState) RenderState::
00580 add_attrib(const RenderAttrib *attrib, int override) const {
00581 int slot = attrib->get_slot();
00582 if (_filled_slots.get_bit(slot) &&
00583 _attributes[slot]._override > override) {
00584
00585 return this;
00586 }
00587
00588
00589 RenderState *new_state = new RenderState(*this);
00590 new_state->_attributes[slot].set(attrib, override);
00591 new_state->_filled_slots.set_bit(slot);
00592 return return_new(new_state);
00593 }
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 CPT(RenderState) RenderState::
00605 set_attrib(const RenderAttrib *attrib) const {
00606 RenderState *new_state = new RenderState(*this);
00607 int slot = attrib->get_slot();
00608 new_state->_attributes[slot]._attrib = attrib;
00609 new_state->_filled_slots.set_bit(slot);
00610 return return_new(new_state);
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 CPT(RenderState) RenderState::
00623 set_attrib(const RenderAttrib *attrib, int override) const {
00624 RenderState *new_state = new RenderState(*this);
00625 int slot = attrib->get_slot();
00626 new_state->_attributes[slot].set(attrib, override);
00627 new_state->_filled_slots.set_bit(slot);
00628 return return_new(new_state);
00629 }
00630
00631
00632
00633
00634
00635
00636
00637
00638 CPT(RenderState) RenderState::
00639 remove_attrib(int slot) const {
00640 if (_attributes[slot]._attrib == NULL) {
00641
00642 return this;
00643 }
00644
00645
00646 if (_filled_slots.get_num_on_bits() == 1) {
00647 return make_empty();
00648 }
00649
00650 RenderState *new_state = new RenderState(*this);
00651 new_state->_attributes[slot].set(NULL, 0);
00652 new_state->_filled_slots.clear_bit(slot);
00653 return return_new(new_state);
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 CPT(RenderState) RenderState::
00666 adjust_all_priorities(int adjustment) const {
00667 RenderState *new_state = new RenderState(*this);
00668
00669 SlotMask mask = _filled_slots;
00670 int slot = mask.get_lowest_on_bit();
00671 while (slot >= 0) {
00672 Attribute &attrib = new_state->_attributes[slot];
00673 nassertr(attrib._attrib != (RenderAttrib *)NULL, this);
00674 attrib._override = max(attrib._override + adjustment, 0);
00675
00676 mask.clear_bit(slot);
00677 slot = mask.get_lowest_on_bit();
00678 }
00679
00680 return return_new(new_state);
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 bool RenderState::
00694 unref() const {
00695 if (!state_cache || garbage_collect_states) {
00696
00697
00698 return ReferenceCount::unref();
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 LightReMutexHolder holder(*_states_lock);
00710
00711 if (auto_break_cycles && uniquify_states) {
00712 if (get_cache_ref_count() > 0 &&
00713 get_ref_count() == get_cache_ref_count() + 1) {
00714
00715
00716
00717
00718 ((RenderState *)this)->detect_and_break_cycles();
00719 }
00720 }
00721
00722 if (ReferenceCount::unref()) {
00723
00724 return true;
00725 }
00726
00727
00728
00729
00730 ((RenderState *)this)->release_new();
00731 ((RenderState *)this)->remove_cache_pointers();
00732
00733 return false;
00734 }
00735
00736 #ifdef HAVE_PYTHON
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751 PyObject *RenderState::
00752 get_composition_cache() const {
00753 IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState;
00754 LightReMutexHolder holder(*_states_lock);
00755 size_t cache_size = _composition_cache.get_size();
00756 PyObject *list = PyList_New(cache_size);
00757
00758 for (size_t i = 0; i < cache_size; ++i) {
00759 PyObject *tuple = PyTuple_New(2);
00760 PyObject *a, *b;
00761 if (!_composition_cache.has_element(i)) {
00762 a = Py_None;
00763 Py_INCREF(a);
00764 b = Py_None;
00765 Py_INCREF(b);
00766 } else {
00767 const RenderState *source = _composition_cache.get_key(i);
00768 if (source == (RenderState *)NULL) {
00769 a = Py_None;
00770 Py_INCREF(a);
00771 } else {
00772 source->ref();
00773 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState,
00774 true, true, source->get_type_index());
00775 }
00776 const RenderState *result = _composition_cache.get_data(i)._result;
00777 if (result == (RenderState *)NULL) {
00778 b = Py_None;
00779 Py_INCREF(b);
00780 } else {
00781 result->ref();
00782 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState,
00783 true, true, result->get_type_index());
00784 }
00785 }
00786 PyTuple_SET_ITEM(tuple, 0, a);
00787 PyTuple_SET_ITEM(tuple, 1, b);
00788
00789 PyList_SET_ITEM(list, i, tuple);
00790 }
00791
00792 return list;
00793 }
00794 #endif // HAVE_PYTHON
00795
00796 #ifdef HAVE_PYTHON
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 PyObject *RenderState::
00812 get_invert_composition_cache() const {
00813 IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState;
00814 LightReMutexHolder holder(*_states_lock);
00815 size_t cache_size = _invert_composition_cache.get_size();
00816 PyObject *list = PyList_New(cache_size);
00817
00818 for (size_t i = 0; i < cache_size; ++i) {
00819 PyObject *tuple = PyTuple_New(2);
00820 PyObject *a, *b;
00821 if (!_invert_composition_cache.has_element(i)) {
00822 a = Py_None;
00823 Py_INCREF(a);
00824 b = Py_None;
00825 Py_INCREF(b);
00826 } else {
00827 const RenderState *source = _invert_composition_cache.get_key(i);
00828 if (source == (RenderState *)NULL) {
00829 a = Py_None;
00830 Py_INCREF(a);
00831 } else {
00832 source->ref();
00833 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState,
00834 true, true, source->get_type_index());
00835 }
00836 const RenderState *result = _invert_composition_cache.get_data(i)._result;
00837 if (result == (RenderState *)NULL) {
00838 b = Py_None;
00839 Py_INCREF(b);
00840 } else {
00841 result->ref();
00842 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState,
00843 true, true, result->get_type_index());
00844 }
00845 }
00846 PyTuple_SET_ITEM(tuple, 0, a);
00847 PyTuple_SET_ITEM(tuple, 1, b);
00848
00849 PyList_SET_ITEM(list, i, tuple);
00850 }
00851
00852 return list;
00853 }
00854 #endif // HAVE_PYTHON
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 const RenderState *RenderState::
00872 get_auto_shader_state() const {
00873 if (_auto_shader_state == (const RenderState *)NULL) {
00874 ((RenderState *)this)->assign_auto_shader_state();
00875 }
00876 return _auto_shader_state;
00877 }
00878
00879
00880
00881
00882
00883
00884 void RenderState::
00885 output(ostream &out) const {
00886 out << "S:";
00887 if (is_empty()) {
00888 out << "(empty)";
00889
00890 } else {
00891 out << "(";
00892 const char *sep = "";
00893
00894 SlotMask mask = _filled_slots;
00895 int slot = mask.get_lowest_on_bit();
00896 while (slot >= 0) {
00897 const Attribute &attrib = _attributes[slot];
00898 nassertv(attrib._attrib != (RenderAttrib *)NULL);
00899 out << sep << attrib._attrib->get_type();
00900 sep = " ";
00901
00902 mask.clear_bit(slot);
00903 slot = mask.get_lowest_on_bit();
00904 }
00905 out << ")";
00906 }
00907 }
00908
00909
00910
00911
00912
00913
00914 void RenderState::
00915 write(ostream &out, int indent_level) const {
00916 if (is_empty()) {
00917 indent(out, indent_level)
00918 << "(empty)\n";
00919 }
00920
00921 SlotMask mask = _filled_slots;
00922 int slot = mask.get_lowest_on_bit();
00923 while (slot >= 0) {
00924 const Attribute &attrib = _attributes[slot];
00925 nassertv(attrib._attrib != (RenderAttrib *)NULL);
00926 attrib._attrib->write(out, indent_level);
00927
00928 mask.clear_bit(slot);
00929 slot = mask.get_lowest_on_bit();
00930 }
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943 int RenderState::
00944 get_max_priority() {
00945 return 1000000000;
00946 }
00947
00948
00949
00950
00951
00952
00953
00954
00955 int RenderState::
00956 get_num_states() {
00957 if (_states == (States *)NULL) {
00958 return 0;
00959 }
00960 LightReMutexHolder holder(*_states_lock);
00961 return _states->get_num_entries();
00962 }
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 int RenderState::
00983 get_num_unused_states() {
00984 if (_states == (States *)NULL) {
00985 return 0;
00986 }
00987 LightReMutexHolder holder(*_states_lock);
00988
00989
00990
00991 typedef pmap<const RenderState *, int> StateCount;
00992 StateCount state_count;
00993
00994 int size = _states->get_size();
00995 for (int si = 0; si < size; ++si) {
00996 if (!_states->has_element(si)) {
00997 continue;
00998 }
00999 const RenderState *state = _states->get_key(si);
01000
01001 int i;
01002 int cache_size = state->_composition_cache.get_size();
01003 for (i = 0; i < cache_size; ++i) {
01004 if (state->_composition_cache.has_element(i)) {
01005 const RenderState *result = state->_composition_cache.get_data(i)._result;
01006 if (result != (const RenderState *)NULL && result != state) {
01007
01008
01009 pair<StateCount::iterator, bool> ir =
01010 state_count.insert(StateCount::value_type(result, 1));
01011 if (!ir.second) {
01012
01013
01014 (*(ir.first)).second++;
01015 }
01016 }
01017 }
01018 }
01019 cache_size = state->_invert_composition_cache.get_size();
01020 for (i = 0; i < cache_size; ++i) {
01021 if (state->_invert_composition_cache.has_element(i)) {
01022 const RenderState *result = state->_invert_composition_cache.get_data(i)._result;
01023 if (result != (const RenderState *)NULL && result != state) {
01024 pair<StateCount::iterator, bool> ir =
01025 state_count.insert(StateCount::value_type(result, 1));
01026 if (!ir.second) {
01027 (*(ir.first)).second++;
01028 }
01029 }
01030 }
01031 }
01032 }
01033
01034
01035
01036
01037 int num_unused = 0;
01038
01039 StateCount::iterator sci;
01040 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
01041 const RenderState *state = (*sci).first;
01042 int count = (*sci).second;
01043 nassertr(count == state->get_cache_ref_count(), num_unused);
01044 nassertr(count <= state->get_ref_count(), num_unused);
01045 if (count == state->get_ref_count()) {
01046 num_unused++;
01047
01048 if (pgraph_cat.is_debug()) {
01049 pgraph_cat.debug()
01050 << "Unused state: " << (void *)state << ":"
01051 << state->get_ref_count() << " =\n";
01052 state->write(pgraph_cat.debug(false), 2);
01053 }
01054 }
01055 }
01056
01057 return num_unused;
01058 }
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080 int RenderState::
01081 clear_cache() {
01082 if (_states == (States *)NULL) {
01083 return 0;
01084 }
01085 LightReMutexHolder holder(*_states_lock);
01086
01087 PStatTimer timer(_cache_update_pcollector);
01088 int orig_size = _states->get_num_entries();
01089
01090
01091
01092
01093
01094 {
01095 typedef pvector< CPT(RenderState) > TempStates;
01096 TempStates temp_states;
01097 temp_states.reserve(orig_size);
01098
01099 int size = _states->get_size();
01100 for (int si = 0; si < size; ++si) {
01101 if (!_states->has_element(si)) {
01102 continue;
01103 }
01104 const RenderState *state = _states->get_key(si);
01105 temp_states.push_back(state);
01106 }
01107
01108
01109
01110
01111 TempStates::iterator ti;
01112 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
01113 RenderState *state = (RenderState *)(*ti).p();
01114
01115 int i;
01116 int cache_size = state->_composition_cache.get_size();
01117 for (i = 0; i < cache_size; ++i) {
01118 if (state->_composition_cache.has_element(i)) {
01119 const RenderState *result = state->_composition_cache.get_data(i)._result;
01120 if (result != (const RenderState *)NULL && result != state) {
01121 result->cache_unref();
01122 nassertr(result->get_ref_count() > 0, 0);
01123 }
01124 }
01125 }
01126 _cache_stats.add_total_size(-state->_composition_cache.get_num_entries());
01127 state->_composition_cache.clear();
01128
01129 cache_size = state->_invert_composition_cache.get_size();
01130 for (i = 0; i < cache_size; ++i) {
01131 if (state->_invert_composition_cache.has_element(i)) {
01132 const RenderState *result = state->_invert_composition_cache.get_data(i)._result;
01133 if (result != (const RenderState *)NULL && result != state) {
01134 result->cache_unref();
01135 nassertr(result->get_ref_count() > 0, 0);
01136 }
01137 }
01138 }
01139 _cache_stats.add_total_size(-state->_invert_composition_cache.get_num_entries());
01140 state->_invert_composition_cache.clear();
01141 }
01142
01143
01144
01145
01146 }
01147
01148 int new_size = _states->get_num_entries();
01149 return orig_size - new_size;
01150 }
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165 int RenderState::
01166 garbage_collect() {
01167 int num_attribs = RenderAttrib::garbage_collect();
01168
01169 if (_states == (States *)NULL || !garbage_collect_states) {
01170 return num_attribs;
01171 }
01172 LightReMutexHolder holder(*_states_lock);
01173
01174 PStatTimer timer(_garbage_collect_pcollector);
01175 int orig_size = _states->get_num_entries();
01176
01177
01178 int size = _states->get_size();
01179 int num_this_pass = int(size * garbage_collect_states_rate);
01180 if (num_this_pass <= 0) {
01181 return num_attribs;
01182 }
01183 num_this_pass = min(num_this_pass, size);
01184 int stop_at_element = (_garbage_index + num_this_pass) % size;
01185
01186 int num_elements = 0;
01187 int si = _garbage_index;
01188 do {
01189 if (_states->has_element(si)) {
01190 ++num_elements;
01191 RenderState *state = (RenderState *)_states->get_key(si);
01192 if (auto_break_cycles && uniquify_states) {
01193 if (state->get_cache_ref_count() > 0 &&
01194 state->get_ref_count() == state->get_cache_ref_count()) {
01195
01196
01197
01198
01199 state->detect_and_break_cycles();
01200 }
01201 }
01202
01203 if (state->get_ref_count() == 1) {
01204
01205
01206
01207
01208
01209
01210 state->release_new();
01211 state->remove_cache_pointers();
01212 state->cache_unref();
01213 delete state;
01214 }
01215 }
01216
01217 si = (si + 1) % size;
01218 } while (si != stop_at_element);
01219 _garbage_index = si;
01220 nassertr(_states->validate(), 0);
01221
01222 int new_size = _states->get_num_entries();
01223 return orig_size - new_size + num_attribs;
01224 }
01225
01226
01227
01228
01229
01230
01231
01232
01233 void RenderState::
01234 clear_munger_cache() {
01235 LightReMutexHolder holder(*_states_lock);
01236
01237 int size = _states->get_size();
01238 for (int si = 0; si < size; ++si) {
01239 if (!_states->has_element(si)) {
01240 continue;
01241 }
01242 RenderState *state = (RenderState *)(_states->get_key(si));
01243 state->_mungers.clear();
01244 state->_last_mi = state->_mungers.end();
01245 }
01246 }
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 void RenderState::
01267 list_cycles(ostream &out) {
01268 if (_states == (States *)NULL) {
01269 return;
01270 }
01271 LightReMutexHolder holder(*_states_lock);
01272
01273 typedef pset<const RenderState *> VisitedStates;
01274 VisitedStates visited;
01275 CompositionCycleDesc cycle_desc;
01276
01277 int size = _states->get_size();
01278 for (int si = 0; si < size; ++si) {
01279 if (!_states->has_element(si)) {
01280 continue;
01281 }
01282 const RenderState *state = _states->get_key(si);
01283
01284 bool inserted = visited.insert(state).second;
01285 if (inserted) {
01286 ++_last_cycle_detect;
01287 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
01288
01289 CompositionCycleDesc::reverse_iterator csi;
01290
01291 out << "\nCycle detected of length " << cycle_desc.size() + 1 << ":\n"
01292 << "state " << (void *)state << ":" << state->get_ref_count()
01293 << " =\n";
01294 state->write(out, 2);
01295 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
01296 const CompositionCycleDescEntry &entry = (*csi);
01297 if (entry._inverted) {
01298 out << "invert composed with ";
01299 } else {
01300 out << "composed with ";
01301 }
01302 out << (const void *)entry._obj << ":" << entry._obj->get_ref_count()
01303 << " " << *entry._obj << "\n"
01304 << "produces " << (const void *)entry._result << ":"
01305 << entry._result->get_ref_count() << " =\n";
01306 entry._result->write(out, 2);
01307 visited.insert(entry._result);
01308 }
01309
01310 cycle_desc.clear();
01311 } else {
01312 ++_last_cycle_detect;
01313 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
01314
01315 CompositionCycleDesc::iterator csi;
01316
01317 out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n"
01318 << "state ";
01319 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
01320 const CompositionCycleDescEntry &entry = (*csi);
01321 out << (const void *)entry._result << ":"
01322 << entry._result->get_ref_count() << " =\n";
01323 entry._result->write(out, 2);
01324 out << (const void *)entry._obj << ":"
01325 << entry._obj->get_ref_count() << " =\n";
01326 entry._obj->write(out, 2);
01327 visited.insert(entry._result);
01328 }
01329 out << (void *)state << ":"
01330 << state->get_ref_count() << " =\n";
01331 state->write(out, 2);
01332
01333 cycle_desc.clear();
01334 }
01335 }
01336 }
01337 }
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348 void RenderState::
01349 list_states(ostream &out) {
01350 if (_states == (States *)NULL) {
01351 out << "0 states:\n";
01352 return;
01353 }
01354 LightReMutexHolder holder(*_states_lock);
01355
01356 out << _states->get_num_entries() << " states:\n";
01357
01358 int size = _states->get_size();
01359 for (int si = 0; si < size; ++si) {
01360 if (!_states->has_element(si)) {
01361 continue;
01362 }
01363 const RenderState *state = _states->get_key(si);
01364 state->write(out, 2);
01365 }
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378 bool RenderState::
01379 validate_states() {
01380 if (_states == (States *)NULL) {
01381 return true;
01382 }
01383
01384 PStatTimer timer(_state_validate_pcollector);
01385
01386 LightReMutexHolder holder(*_states_lock);
01387 if (_states->is_empty()) {
01388 return true;
01389 }
01390
01391 if (!_states->validate()) {
01392 pgraph_cat.error()
01393 << "RenderState::_states cache is invalid!\n";
01394 return false;
01395 }
01396
01397 int size = _states->get_size();
01398 int si = 0;
01399 while (si < size && !_states->has_element(si)) {
01400 ++si;
01401 }
01402 nassertr(si < size, false);
01403 nassertr(_states->get_key(si)->get_ref_count() >= 0, false);
01404 int snext = si;
01405 ++snext;
01406 while (snext < size && !_states->has_element(snext)) {
01407 ++snext;
01408 }
01409 while (snext < size) {
01410 nassertr(_states->get_key(snext)->get_ref_count() >= 0, false);
01411 const RenderState *ssi = _states->get_key(si);
01412 const RenderState *ssnext = _states->get_key(snext);
01413 int c = ssi->compare_to(*ssnext);
01414 int ci = ssnext->compare_to(*ssi);
01415 if ((ci < 0) != (c > 0) ||
01416 (ci > 0) != (c < 0) ||
01417 (ci == 0) != (c == 0)) {
01418 pgraph_cat.error()
01419 << "RenderState::compare_to() not defined properly!\n";
01420 pgraph_cat.error(false)
01421 << "(a, b): " << c << "\n";
01422 pgraph_cat.error(false)
01423 << "(b, a): " << ci << "\n";
01424 ssi->write(pgraph_cat.error(false), 2);
01425 ssnext->write(pgraph_cat.error(false), 2);
01426 return false;
01427 }
01428 si = snext;
01429 ++snext;
01430 while (snext < size && !_states->has_element(snext)) {
01431 ++snext;
01432 }
01433 }
01434
01435 return true;
01436 }
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446 int RenderState::
01447 get_geom_rendering(int geom_rendering) const {
01448 const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, get_attrib(RenderModeAttrib::get_class_slot()));
01449 const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, get_attrib(TexGenAttrib::get_class_slot()));
01450 const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, get_attrib(TexMatrixAttrib::get_class_slot()));
01451
01452 if (render_mode != (const RenderModeAttrib *)NULL) {
01453 geom_rendering = render_mode->get_geom_rendering(geom_rendering);
01454 }
01455 if (tex_gen != (const TexGenAttrib *)NULL) {
01456 geom_rendering = tex_gen->get_geom_rendering(geom_rendering);
01457 }
01458 if (tex_matrix != (const TexMatrixAttrib *)NULL) {
01459 geom_rendering = tex_matrix->get_geom_rendering(geom_rendering);
01460 }
01461
01462 return geom_rendering;
01463 }
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473 void RenderState::
01474 bin_removed(int bin_index) {
01475
01476 nassertv(false);
01477 }
01478
01479
01480
01481
01482
01483
01484
01485
01486 bool RenderState::
01487 validate_filled_slots() const {
01488 SlotMask mask;
01489
01490 RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
01491 int max_slots = reg->get_max_slots();
01492 for (int slot = 1; slot < max_slots; ++slot) {
01493 const Attribute &attribute = _attributes[slot];
01494 if (attribute._attrib != (RenderAttrib *)NULL) {
01495 mask.set_bit(slot);
01496 }
01497 }
01498
01499 return (mask == _filled_slots);
01500 }
01501
01502
01503
01504
01505
01506
01507 void RenderState::
01508 do_calc_hash() {
01509 _hash = 0;
01510
01511 SlotMask mask = _filled_slots;
01512 int slot = mask.get_lowest_on_bit();
01513 while (slot >= 0) {
01514 const Attribute &attrib = _attributes[slot];
01515 nassertv(attrib._attrib != (RenderAttrib *)NULL);
01516 _hash = pointer_hash::add_hash(_hash, attrib._attrib);
01517 _hash = int_hash::add_hash(_hash, attrib._override);
01518
01519 mask.clear_bit(slot);
01520 slot = mask.get_lowest_on_bit();
01521 }
01522
01523 _flags |= F_hash_known;
01524 }
01525
01526
01527
01528
01529
01530
01531
01532
01533 void RenderState::
01534 assign_auto_shader_state() {
01535 CPT(RenderState) state = do_calc_auto_shader_state();
01536
01537 {
01538 LightReMutexHolder holder(*_states_lock);
01539 if (_auto_shader_state == (const RenderState *)NULL) {
01540 _auto_shader_state = state;
01541 if (_auto_shader_state != this) {
01542 _auto_shader_state->cache_ref();
01543 }
01544 }
01545 }
01546 }
01547
01548
01549
01550
01551
01552
01553
01554
01555 CPT(RenderState) RenderState::
01556 do_calc_auto_shader_state() {
01557 RenderState *state = new RenderState;
01558
01559 SlotMask mask = _filled_slots;
01560 int slot = mask.get_lowest_on_bit();
01561 while (slot >= 0) {
01562 const Attribute &attrib = _attributes[slot];
01563 nassertr(attrib._attrib != (RenderAttrib *)NULL, this);
01564 CPT(RenderAttrib) new_attrib = attrib._attrib->get_auto_shader_attrib(this);
01565 if (new_attrib != NULL) {
01566 nassertr(new_attrib->get_slot() == slot, this);
01567 state->_attributes[slot].set(new_attrib, 0);
01568 state->_filled_slots.set_bit(slot);
01569 }
01570
01571 mask.clear_bit(slot);
01572 slot = mask.get_lowest_on_bit();
01573 }
01574
01575 return return_new(state);
01576 }
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589 CPT(RenderState) RenderState::
01590 return_new(RenderState *state) {
01591 nassertr(state != (RenderState *)NULL, state);
01592
01593
01594
01595 #ifndef NDEBUG
01596 if (state->_attributes[0]._attrib != (RenderAttrib *)NULL) {
01597 const RenderAttrib *attrib = state->_attributes[0]._attrib;
01598 if (attrib->get_type() == TypeHandle::none()) {
01599 ((RenderAttrib *)attrib)->force_init_type();
01600 pgraph_cat->error()
01601 << "Uninitialized RenderAttrib type: " << attrib->get_type()
01602 << "\n";
01603
01604 } else {
01605 static pset<TypeHandle> already_reported;
01606 if (already_reported.insert(attrib->get_type()).second) {
01607 pgraph_cat->error()
01608 << attrib->get_type() << " did not initialize its slot number.\n";
01609 }
01610 }
01611 }
01612 #endif
01613 state->_attributes[0]._attrib = NULL;
01614 state->_filled_slots.clear_bit(0);
01615
01616 #ifndef NDEBUG
01617 nassertr(state->validate_filled_slots(), state);
01618 #endif
01619
01620 if (!uniquify_states && !state->is_empty()) {
01621 return state;
01622 }
01623
01624 return return_unique(state);
01625 }
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639 CPT(RenderState) RenderState::
01640 return_unique(RenderState *state) {
01641 nassertr(state != (RenderState *)NULL, state);
01642
01643 if (!state_cache) {
01644 return state;
01645 }
01646
01647 #ifndef NDEBUG
01648 if (paranoid_const) {
01649 nassertr(validate_states(), state);
01650 }
01651 #endif
01652
01653 LightReMutexHolder holder(*_states_lock);
01654
01655 if (state->_saved_entry != -1) {
01656
01657
01658 return state;
01659 }
01660
01661
01662
01663 CPT(RenderState) pt_state = state;
01664
01665
01666
01667 if (!uniquify_attribs && !state->is_empty()) {
01668 SlotMask mask = state->_filled_slots;
01669 int slot = mask.get_lowest_on_bit();
01670 while (slot >= 0) {
01671 Attribute &attrib = state->_attributes[slot];
01672 nassertr(attrib._attrib != (RenderAttrib *)NULL, state);
01673 attrib._attrib = attrib._attrib->get_unique();
01674 mask.clear_bit(slot);
01675 slot = mask.get_lowest_on_bit();
01676 }
01677 }
01678
01679 int si = _states->find(state);
01680 if (si != -1) {
01681
01682 return _states->get_key(si);
01683 }
01684
01685
01686 if (garbage_collect_states) {
01687
01688
01689
01690 state->cache_ref();
01691 }
01692 si = _states->store(state, Empty());
01693
01694
01695 state->_saved_entry = si;
01696 return pt_state;
01697 }
01698
01699
01700
01701
01702
01703
01704
01705
01706 CPT(RenderState) RenderState::
01707 do_compose(const RenderState *other) const {
01708 PStatTimer timer(_state_compose_pcollector);
01709
01710 RenderState *new_state = new RenderState;
01711
01712 SlotMask mask = _filled_slots | other->_filled_slots;
01713 new_state->_filled_slots = mask;
01714
01715 int slot = mask.get_lowest_on_bit();
01716 while (slot >= 0) {
01717 const Attribute &a = _attributes[slot];
01718 const Attribute &b = other->_attributes[slot];
01719 Attribute &result = new_state->_attributes[slot];
01720
01721 if (a._attrib == NULL) {
01722 nassertr(b._attrib != NULL, this);
01723
01724 result = b;
01725
01726 } else if (b._attrib == NULL) {
01727
01728 result = a;
01729
01730 } else if (b._override < a._override) {
01731
01732 result = a;
01733
01734 } else if (a._override < b._override &&
01735 a._attrib->lower_attrib_can_override()) {
01736
01737
01738
01739
01740
01741
01742 result = b;
01743
01744 } else {
01745
01746
01747
01748 result.set(a._attrib->compose(b._attrib), b._override);
01749 }
01750
01751 mask.clear_bit(slot);
01752 slot = mask.get_lowest_on_bit();
01753 }
01754
01755
01756
01757
01758
01759 CPT(ShaderAttrib) sattrib = DCAST(ShaderAttrib, new_state->get_attrib_def(ShaderAttrib::get_class_slot()));
01760 if (sattrib->auto_shader()) {
01761 sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs());
01762 }
01763
01764 return return_new(new_state);
01765 }
01766
01767
01768
01769
01770
01771
01772 CPT(RenderState) RenderState::
01773 do_invert_compose(const RenderState *other) const {
01774 PStatTimer timer(_state_invert_pcollector);
01775
01776 RenderState *new_state = new RenderState;
01777
01778 SlotMask mask = _filled_slots | other->_filled_slots;
01779 new_state->_filled_slots = mask;
01780
01781 int slot = mask.get_lowest_on_bit();
01782 while (slot >= 0) {
01783 const Attribute &a = _attributes[slot];
01784 const Attribute &b = other->_attributes[slot];
01785 Attribute &result = new_state->_attributes[slot];
01786
01787 if (a._attrib == NULL) {
01788 nassertr(b._attrib != NULL, this);
01789
01790 result = b;
01791
01792 } else if (b._attrib == NULL) {
01793
01794 CPT(RenderState) full_default = make_full_default();
01795 CPT(RenderAttrib) default_attrib = full_default->get_attrib(slot);
01796 result.set(a._attrib->invert_compose(default_attrib), 0);
01797
01798 } else {
01799
01800
01801 result.set(a._attrib->invert_compose(b._attrib), 0);
01802 }
01803
01804 mask.clear_bit(slot);
01805 slot = mask.get_lowest_on_bit();
01806 }
01807 return return_new(new_state);
01808 }
01809
01810
01811
01812
01813
01814
01815
01816
01817 void RenderState::
01818 detect_and_break_cycles() {
01819 PStatTimer timer(_state_break_cycles_pcollector);
01820
01821 ++_last_cycle_detect;
01822 if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
01823
01824
01825 if (pgraph_cat.is_debug()) {
01826 pgraph_cat.debug()
01827 << "Breaking cycle involving " << (*this) << "\n";
01828 }
01829
01830 ((RenderState *)this)->remove_cache_pointers();
01831 } else {
01832 ++_last_cycle_detect;
01833 if (r_detect_reverse_cycles(this, this, 1, _last_cycle_detect, NULL)) {
01834 if (pgraph_cat.is_debug()) {
01835 pgraph_cat.debug()
01836 << "Breaking cycle involving " << (*this) << "\n";
01837 }
01838
01839 ((RenderState *)this)->remove_cache_pointers();
01840 }
01841 }
01842 }
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855 bool RenderState::
01856 r_detect_cycles(const RenderState *start_state,
01857 const RenderState *current_state,
01858 int length, UpdateSeq this_seq,
01859 RenderState::CompositionCycleDesc *cycle_desc) {
01860 if (current_state->_cycle_detect == this_seq) {
01861
01862
01863
01864
01865
01866
01867 return (current_state == start_state && length > 2);
01868 }
01869 ((RenderState *)current_state)->_cycle_detect = this_seq;
01870
01871 int i;
01872 int cache_size = current_state->_composition_cache.get_size();
01873 for (i = 0; i < cache_size; ++i) {
01874 if (current_state->_composition_cache.has_element(i)) {
01875 const RenderState *result = current_state->_composition_cache.get_data(i)._result;
01876 if (result != (const RenderState *)NULL) {
01877 if (r_detect_cycles(start_state, result, length + 1,
01878 this_seq, cycle_desc)) {
01879
01880 if (cycle_desc != (CompositionCycleDesc *)NULL) {
01881 const RenderState *other = current_state->_composition_cache.get_key(i);
01882 CompositionCycleDescEntry entry(other, result, false);
01883 cycle_desc->push_back(entry);
01884 }
01885 return true;
01886 }
01887 }
01888 }
01889 }
01890
01891 cache_size = current_state->_invert_composition_cache.get_size();
01892 for (i = 0; i < cache_size; ++i) {
01893 if (current_state->_invert_composition_cache.has_element(i)) {
01894 const RenderState *result = current_state->_invert_composition_cache.get_data(i)._result;
01895 if (result != (const RenderState *)NULL) {
01896 if (r_detect_cycles(start_state, result, length + 1,
01897 this_seq, cycle_desc)) {
01898
01899 if (cycle_desc != (CompositionCycleDesc *)NULL) {
01900 const RenderState *other = current_state->_invert_composition_cache.get_key(i);
01901 CompositionCycleDescEntry entry(other, result, true);
01902 cycle_desc->push_back(entry);
01903 }
01904 return true;
01905 }
01906 }
01907 }
01908 }
01909
01910
01911 return false;
01912 }
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922 bool RenderState::
01923 r_detect_reverse_cycles(const RenderState *start_state,
01924 const RenderState *current_state,
01925 int length, UpdateSeq this_seq,
01926 RenderState::CompositionCycleDesc *cycle_desc) {
01927 if (current_state->_cycle_detect == this_seq) {
01928
01929
01930
01931
01932
01933
01934 return (current_state == start_state && length > 2);
01935 }
01936 ((RenderState *)current_state)->_cycle_detect = this_seq;
01937
01938 int i;
01939 int cache_size = current_state->_composition_cache.get_size();
01940 for (i = 0; i < cache_size; ++i) {
01941 if (current_state->_composition_cache.has_element(i)) {
01942 const RenderState *other = current_state->_composition_cache.get_key(i);
01943 if (other != current_state) {
01944 int oi = other->_composition_cache.find(current_state);
01945 nassertr(oi != -1, false);
01946
01947 const RenderState *result = other->_composition_cache.get_data(oi)._result;
01948 if (result != (const RenderState *)NULL) {
01949 if (r_detect_reverse_cycles(start_state, result, length + 1,
01950 this_seq, cycle_desc)) {
01951
01952 if (cycle_desc != (CompositionCycleDesc *)NULL) {
01953 const RenderState *other = current_state->_composition_cache.get_key(i);
01954 CompositionCycleDescEntry entry(other, result, false);
01955 cycle_desc->push_back(entry);
01956 }
01957 return true;
01958 }
01959 }
01960 }
01961 }
01962 }
01963
01964 cache_size = current_state->_invert_composition_cache.get_size();
01965 for (i = 0; i < cache_size; ++i) {
01966 if (current_state->_invert_composition_cache.has_element(i)) {
01967 const RenderState *other = current_state->_invert_composition_cache.get_key(i);
01968 if (other != current_state) {
01969 int oi = other->_invert_composition_cache.find(current_state);
01970 nassertr(oi != -1, false);
01971
01972 const RenderState *result = other->_invert_composition_cache.get_data(oi)._result;
01973 if (result != (const RenderState *)NULL) {
01974 if (r_detect_reverse_cycles(start_state, result, length + 1,
01975 this_seq, cycle_desc)) {
01976
01977 if (cycle_desc != (CompositionCycleDesc *)NULL) {
01978 const RenderState *other = current_state->_invert_composition_cache.get_key(i);
01979 CompositionCycleDescEntry entry(other, result, false);
01980 cycle_desc->push_back(entry);
01981 }
01982 return true;
01983 }
01984 }
01985 }
01986 }
01987 }
01988
01989
01990 return false;
01991 }
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002 void RenderState::
02003 release_new() {
02004 nassertv(_states_lock->debug_is_locked());
02005
02006 if (_saved_entry != -1) {
02007
02008 _saved_entry = _states->find(this);
02009 _states->remove_element(_saved_entry);
02010 _saved_entry = -1;
02011 }
02012 }
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025 void RenderState::
02026 remove_cache_pointers() {
02027 nassertv(_states_lock->debug_is_locked());
02028
02029
02030 if (_auto_shader_state != (const RenderState *)NULL) {
02031 if (_auto_shader_state != this) {
02032 cache_unref_delete(_auto_shader_state);
02033 }
02034 _auto_shader_state = NULL;
02035 }
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052 #ifdef DO_PSTATS
02053 if (_composition_cache.is_empty() && _invert_composition_cache.is_empty()) {
02054 return;
02055 }
02056 PStatTimer timer(_cache_update_pcollector);
02057 #endif // DO_PSTATS
02058
02059
02060
02061 int i = 0;
02062 while (!_composition_cache.is_empty()) {
02063
02064 while (!_composition_cache.has_element(i)) {
02065 ++i;
02066 }
02067
02068
02069
02070
02071
02072
02073
02074
02075 RenderState *other = (RenderState *)_composition_cache.get_key(i);
02076
02077
02078
02079 Composition comp = _composition_cache.get_data(i);
02080
02081
02082
02083
02084
02085 _composition_cache.remove_element(i);
02086 _cache_stats.add_total_size(-1);
02087 _cache_stats.inc_dels();
02088
02089 if (other != this) {
02090 int oi = other->_composition_cache.find(this);
02091
02092
02093
02094
02095 if (oi != -1) {
02096
02097 Composition ocomp = other->_composition_cache.get_data(oi);
02098
02099 other->_composition_cache.remove_element(oi);
02100 _cache_stats.add_total_size(-1);
02101 _cache_stats.inc_dels();
02102
02103
02104
02105
02106
02107 if (ocomp._result != (const RenderState *)NULL && ocomp._result != other) {
02108 cache_unref_delete(ocomp._result);
02109 }
02110 }
02111 }
02112
02113
02114
02115 if (comp._result != (const RenderState *)NULL && comp._result != this) {
02116 cache_unref_delete(comp._result);
02117 }
02118 }
02119
02120
02121 i = 0;
02122 while (!_invert_composition_cache.is_empty()) {
02123 while (!_invert_composition_cache.has_element(i)) {
02124 ++i;
02125 }
02126
02127 RenderState *other = (RenderState *)_invert_composition_cache.get_key(i);
02128 nassertv(other != this);
02129 Composition comp = _invert_composition_cache.get_data(i);
02130 _invert_composition_cache.remove_element(i);
02131 _cache_stats.add_total_size(-1);
02132 _cache_stats.inc_dels();
02133 if (other != this) {
02134 int oi = other->_invert_composition_cache.find(this);
02135 if (oi != -1) {
02136 Composition ocomp = other->_invert_composition_cache.get_data(oi);
02137 other->_invert_composition_cache.remove_element(oi);
02138 _cache_stats.add_total_size(-1);
02139 _cache_stats.inc_dels();
02140 if (ocomp._result != (const RenderState *)NULL && ocomp._result != other) {
02141 cache_unref_delete(ocomp._result);
02142 }
02143 }
02144 }
02145 if (comp._result != (const RenderState *)NULL && comp._result != this) {
02146 cache_unref_delete(comp._result);
02147 }
02148 }
02149 }
02150
02151
02152
02153
02154
02155
02156
02157 void RenderState::
02158 determine_bin_index() {
02159 LightMutexHolder holder(_lock);
02160 if ((_flags & F_checked_bin_index) != 0) {
02161
02162 return;
02163 }
02164
02165 string bin_name;
02166 _draw_order = 0;
02167
02168 const CullBinAttrib *bin = DCAST(CullBinAttrib, get_attrib(CullBinAttrib::get_class_slot()));
02169 if (bin != (const CullBinAttrib *)NULL) {
02170 bin_name = bin->get_bin_name();
02171 _draw_order = bin->get_draw_order();
02172 }
02173
02174 if (bin_name.empty()) {
02175
02176
02177
02178 bin_name = "opaque";
02179
02180 const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, get_attrib(TransparencyAttrib::get_class_slot()));
02181 if (transparency != (const TransparencyAttrib *)NULL) {
02182 switch (transparency->get_mode()) {
02183 case TransparencyAttrib::M_alpha:
02184 case TransparencyAttrib::M_dual:
02185
02186 bin_name = "transparent";
02187 break;
02188
02189 default:
02190 break;
02191 }
02192 }
02193 }
02194
02195 CullBinManager *bin_manager = CullBinManager::get_global_ptr();
02196 _bin_index = bin_manager->find_bin(bin_name);
02197 if (_bin_index == -1) {
02198 pgraph_cat.warning()
02199 << "No bin named " << bin_name << "; creating default bin.\n";
02200 _bin_index = bin_manager->add_bin(bin_name, CullBinManager::BT_unsorted, 0);
02201 }
02202 _flags |= F_checked_bin_index;
02203 }
02204
02205
02206
02207
02208
02209
02210 void RenderState::
02211 determine_cull_callback() {
02212 LightMutexHolder holder(_lock);
02213 if ((_flags & F_checked_cull_callback) != 0) {
02214
02215 return;
02216 }
02217
02218 SlotMask mask = _filled_slots;
02219 int slot = mask.get_lowest_on_bit();
02220 while (slot >= 0) {
02221 const Attribute &attrib = _attributes[slot];
02222 nassertv(attrib._attrib != (RenderAttrib *)NULL);
02223 if (attrib._attrib->has_cull_callback()) {
02224 _flags |= F_has_cull_callback;
02225 break;
02226 }
02227
02228 mask.clear_bit(slot);
02229 slot = mask.get_lowest_on_bit();
02230 }
02231
02232 _flags |= F_checked_cull_callback;
02233 }
02234
02235
02236
02237
02238
02239
02240 void RenderState::
02241 fill_default() {
02242 RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
02243 int num_slots = reg->get_num_slots();
02244 for (int slot = 1; slot < num_slots; ++slot) {
02245 _attributes[slot].set(reg->get_slot_default(slot), 0);
02246 _filled_slots.set_bit(slot);
02247 }
02248 }
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258 void RenderState::
02259 update_pstats(int old_referenced_bits, int new_referenced_bits) {
02260 #ifdef DO_PSTATS
02261 if ((old_referenced_bits & R_node) != 0) {
02262 _node_counter.sub_level(1);
02263 } else if ((old_referenced_bits & R_cache) != 0) {
02264 _cache_counter.sub_level(1);
02265 }
02266 if ((new_referenced_bits & R_node) != 0) {
02267 _node_counter.add_level(1);
02268 } else if ((new_referenced_bits & R_cache) != 0) {
02269 _cache_counter.add_level(1);
02270 }
02271 #endif // DO_PSTATS
02272 }
02273
02274 #ifdef HAVE_PYTHON
02275
02276
02277
02278
02279
02280
02281
02282 PyObject *RenderState::
02283 get_states() {
02284 IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState;
02285 if (_states == (States *)NULL) {
02286 return PyList_New(0);
02287 }
02288 LightReMutexHolder holder(*_states_lock);
02289
02290 size_t num_states = _states->get_num_entries();
02291 PyObject *list = PyList_New(num_states);
02292 size_t i = 0;
02293
02294 int size = _states->get_size();
02295 for (int si = 0; si < size; ++si) {
02296 if (!_states->has_element(si)) {
02297 continue;
02298 }
02299 const RenderState *state = _states->get_key(si);
02300 state->ref();
02301 PyObject *a =
02302 DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState,
02303 true, true, state->get_type_index());
02304 nassertr(i < num_states, list);
02305 PyList_SET_ITEM(list, i, a);
02306 ++i;
02307 }
02308 nassertr(i == num_states, list);
02309 return list;
02310 }
02311 #endif // HAVE_PYTHON
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323 void RenderState::
02324 init_states() {
02325 _states = new States;
02326
02327
02328
02329
02330
02331
02332 _states_lock = new LightReMutex("RenderState::_states_lock");
02333 _cache_stats.init();
02334 nassertv(Thread::get_current_thread() == Thread::get_main_thread());
02335 }
02336
02337
02338
02339
02340
02341
02342
02343
02344 void RenderState::
02345 register_with_read_factory() {
02346 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
02347 }
02348
02349
02350
02351
02352
02353
02354
02355 void RenderState::
02356 write_datagram(BamWriter *manager, Datagram &dg) {
02357 TypedWritable::write_datagram(manager, dg);
02358
02359 int num_attribs = _filled_slots.get_num_on_bits();
02360 nassertv(num_attribs == (int)(PN_uint16)num_attribs);
02361 dg.add_uint16(num_attribs);
02362
02363
02364
02365 SlotMask mask = _filled_slots;
02366 int slot = mask.get_lowest_on_bit();
02367 while (slot >= 0) {
02368 const Attribute &attrib = _attributes[slot];
02369 nassertv(attrib._attrib != (RenderAttrib *)NULL);
02370 manager->write_pointer(dg, attrib._attrib);
02371 dg.add_int32(attrib._override);
02372
02373 mask.clear_bit(slot);
02374 slot = mask.get_lowest_on_bit();
02375 }
02376 }
02377
02378
02379
02380
02381
02382
02383
02384
02385 int RenderState::
02386 complete_pointers(TypedWritable **p_list, BamReader *manager) {
02387 int pi = TypedWritable::complete_pointers(p_list, manager);
02388
02389 int num_attribs = 0;
02390
02391 RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
02392 for (size_t i = 0; i < (*_read_overrides).size(); ++i) {
02393 int override = (*_read_overrides)[i];
02394
02395 RenderAttrib *attrib = DCAST(RenderAttrib, p_list[pi++]);
02396 if (attrib != (RenderAttrib *)NULL) {
02397 int slot = attrib->get_slot();
02398 if (slot > 0 && slot < reg->get_max_slots()) {
02399 _attributes[slot].set(attrib, override);
02400 _filled_slots.set_bit(slot);
02401 ++num_attribs;
02402 }
02403 }
02404 }
02405
02406 delete _read_overrides;
02407 _read_overrides = NULL;
02408
02409 return pi;
02410 }
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423 TypedWritable *RenderState::
02424 change_this(TypedWritable *old_ptr, BamReader *manager) {
02425
02426 RenderState *state = DCAST(RenderState, old_ptr);
02427 CPT(RenderState) pointer = return_unique(state);
02428
02429
02430
02431
02432
02433
02434 if (pointer == state) {
02435 pointer->ref();
02436 manager->register_finalize(state);
02437 }
02438
02439
02440
02441 return (RenderState *)pointer.p();
02442 }
02443
02444
02445
02446
02447
02448
02449
02450
02451 void RenderState::
02452 finalize(BamReader *) {
02453
02454 unref();
02455
02456
02457
02458
02459
02460
02461 nassertv(get_ref_count() != 0);
02462 }
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472 TypedWritable *RenderState::
02473 make_from_bam(const FactoryParams ¶ms) {
02474 RenderState *state = new RenderState;
02475 DatagramIterator scan;
02476 BamReader *manager;
02477
02478 parse_params(params, scan, manager);
02479 state->fillin(scan, manager);
02480 manager->register_change_this(change_this, state);
02481
02482 return state;
02483 }
02484
02485
02486
02487
02488
02489
02490
02491
02492 void RenderState::
02493 fillin(DatagramIterator &scan, BamReader *manager) {
02494 TypedWritable::fillin(scan, manager);
02495
02496 int num_attribs = scan.get_uint16();
02497 _read_overrides = new vector_int;
02498 (*_read_overrides).reserve(num_attribs);
02499
02500 for (int i = 0; i < num_attribs; ++i) {
02501 manager->read_pointer(scan);
02502 int override = scan.get_int32();
02503 (*_read_overrides).push_back(override);
02504 }
02505 }
02506