// Filename: renderState.h // Created by: drose (21Feb02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #ifndef RENDERSTATE_H #define RENDERSTATE_H #include "pandabase.h" #include "renderAttrib.h" #include "nodeCachedReferenceCount.h" #include "pointerTo.h" #include "pvector.h" #include "updateSeq.h" #include "pStatCollector.h" #include "renderModeAttrib.h" #include "texMatrixAttrib.h" #include "geomMunger.h" #include "weakPointerTo.h" #include "lightReMutex.h" #include "lightMutex.h" #include "deletedChain.h" #include "simpleHashMap.h" #include "cacheStats.h" #include "renderAttribRegistry.h" class GraphicsStateGuardianBase; class FactoryParams; class ShaderAttrib; //////////////////////////////////////////////////////////////////// // Class : RenderState // Description : This represents a unique collection of RenderAttrib // objects that correspond to a particular renderable // state. // // You should not attempt to create or modify a // RenderState object directly. Instead, call one of // the make() functions to create one for you. And // instead of modifying a RenderState object, create a // new one. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_PGRAPH RenderState : public NodeCachedReferenceCount { protected: RenderState(); private: RenderState(const RenderState ©); void operator = (const RenderState ©); public: virtual ~RenderState(); ALLOC_DELETED_CHAIN(RenderState); typedef RenderAttribRegistry::SlotMask SlotMask; PUBLISHED: int compare_to(const RenderState &other) const; int compare_sort(const RenderState &other) const; INLINE size_t get_hash() const; INLINE bool is_empty() const; INLINE bool has_cull_callback() const; bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; static CPT(RenderState) make_empty(); static CPT(RenderState) make_full_default(); static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0); static CPT(RenderState) make(const RenderAttrib *attrib1, const RenderAttrib *attrib2, int override = 0); static CPT(RenderState) make(const RenderAttrib *attrib1, const RenderAttrib *attrib2, const RenderAttrib *attrib3, int override = 0); static CPT(RenderState) make(const RenderAttrib *attrib1, const RenderAttrib *attrib2, const RenderAttrib *attrib3, const RenderAttrib *attrib4, int override = 0); static CPT(RenderState) make(const RenderAttrib * const *attrib, int num_attribs, int override = 0); CPT(RenderState) compose(const RenderState *other) const; CPT(RenderState) invert_compose(const RenderState *other) const; CPT(RenderState) add_attrib(const RenderAttrib *attrib, int override = 0) const; CPT(RenderState) set_attrib(const RenderAttrib *attrib) const; CPT(RenderState) set_attrib(const RenderAttrib *attrib, int override) const; INLINE CPT(RenderState) remove_attrib(TypeHandle type) const; CPT(RenderState) remove_attrib(int slot) const; CPT(RenderState) adjust_all_priorities(int adjustment) const; INLINE bool has_attrib(TypeHandle type) const; INLINE bool has_attrib(int slot) const; INLINE const RenderAttrib *get_attrib(TypeHandle type) const; INLINE const RenderAttrib *get_attrib(int slot) const; INLINE const RenderAttrib *get_attrib_def(int slot) const; INLINE int get_override(TypeHandle type) const; INLINE int get_override(int slot) const; INLINE CPT(RenderState) get_unique() const; virtual bool unref() const; INLINE void cache_ref() const; INLINE bool cache_unref() const; INLINE void node_ref() const; INLINE bool node_unref() const; INLINE int get_composition_cache_num_entries() const; INLINE int get_invert_composition_cache_num_entries() const; INLINE int get_composition_cache_size() const; INLINE const RenderState *get_composition_cache_source(int n) const; INLINE const RenderState *get_composition_cache_result(int n) const; INLINE int get_invert_composition_cache_size() const; INLINE const RenderState *get_invert_composition_cache_source(int n) const; INLINE const RenderState *get_invert_composition_cache_result(int n) const; #ifdef HAVE_PYTHON PyObject *get_composition_cache() const; PyObject *get_invert_composition_cache() const; #endif // HAVE_PYTHON const RenderState *get_auto_shader_state() const; void output(ostream &out) const; void write(ostream &out, int indent_level) const; static int get_max_priority(); static int get_num_states(); static int get_num_unused_states(); static int clear_cache(); static void clear_munger_cache(); static int garbage_collect(); static void list_cycles(ostream &out); static void list_states(ostream &out); static bool validate_states(); #ifdef HAVE_PYTHON static PyObject *get_states(); #endif // HAVE_PYTHON PUBLISHED: // These methods are intended for use by low-level code, but they're // also handy enough to expose to high-level users. INLINE int get_draw_order() const; INLINE int get_bin_index() const; int get_geom_rendering(int geom_rendering) const; public: static void bin_removed(int bin_index); INLINE static void flush_level(); private: INLINE void check_hash() const; bool validate_filled_slots() const; INLINE bool do_cache_unref() const; INLINE bool do_node_unref() const; INLINE void calc_hash(); void do_calc_hash(); void assign_auto_shader_state(); CPT(RenderState) do_calc_auto_shader_state(); class CompositionCycleDescEntry { public: INLINE CompositionCycleDescEntry(const RenderState *obj, const RenderState *result, bool inverted); const RenderState *_obj; const RenderState *_result; bool _inverted; }; typedef pvector CompositionCycleDesc; static CPT(RenderState) return_new(RenderState *state); static CPT(RenderState) return_unique(RenderState *state); CPT(RenderState) do_compose(const RenderState *other) const; CPT(RenderState) do_invert_compose(const RenderState *other) const; void detect_and_break_cycles(); static bool r_detect_cycles(const RenderState *start_state, const RenderState *current_state, int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); static bool r_detect_reverse_cycles(const RenderState *start_state, const RenderState *current_state, int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); void release_new(); void remove_cache_pointers(); void determine_bin_index(); void determine_cull_callback(); void fill_default(); INLINE void set_destructing(); INLINE bool is_destructing() const; INLINE void consider_update_pstats(int old_referenced_bits) const; static void update_pstats(int old_referenced_bits, int new_referenced_bits); public: static void init_states(); // If this state contains an "auto" ShaderAttrib, then an explicit // ShaderAttrib will be synthesized by the runtime and stored here. // I can't declare this as a ShaderAttrib because that would create // a circular include-file dependency problem. Aaargh. CPT(RenderAttrib) _generated_shader; private: // This mutex protects _states. It also protects any modification // to the cache, which is encoded in _composition_cache and // _invert_composition_cache. static LightReMutex *_states_lock; class Empty { }; typedef SimpleHashMap > States; static States *_states; static CPT(RenderState) _empty_state; static CPT(RenderState) _full_default_state; // This iterator records the entry corresponding to this // RenderState object in the above global set. We keep the index // around so we can remove it when the RenderState destructs. int _saved_entry; // This data structure manages the job of caching the composition of // two RenderStates. It's complicated because we have to be sure to // remove the entry if *either* of the input RenderStates destructs. // To implement this, we always record Composition entries in pairs, // one in each of the two involved RenderState objects. class Composition { public: INLINE Composition(); INLINE Composition(const Composition ©); // _result is reference counted if and only if it is not the same // pointer as this. const RenderState *_result; }; // The first element of the map is the object we compose with. This // is not reference counted within this map; instead we store a // companion pointer in the other object, and remove the references // explicitly when either object destructs. typedef SimpleHashMap CompositionCache; CompositionCache _composition_cache; CompositionCache _invert_composition_cache; // This is here to provide a quick cache of GSG + RenderState -> // GeomMunger for the cull phase. It is here because it is faster // to look up the GSG in the RenderState pointer than vice-versa, // since there are likely to be far fewer GSG's than RenderStates. // The code to manage this map lives in // GraphicsStateGuardian::get_geom_munger(). typedef pmap Mungers; Mungers _mungers; Mungers::const_iterator _last_mi; // This is used to mark nodes as we visit them to detect cycles. UpdateSeq _cycle_detect; static UpdateSeq _last_cycle_detect; // This keeps track of our current position through the garbage // collection cycle. static int _garbage_index; static PStatCollector _cache_update_pcollector; static PStatCollector _garbage_collect_pcollector; static PStatCollector _state_compose_pcollector; static PStatCollector _state_invert_pcollector; static PStatCollector _state_break_cycles_pcollector; static PStatCollector _state_validate_pcollector; static PStatCollector _node_counter; static PStatCollector _cache_counter; private: // This is the actual data within the RenderState: a set of // max_slots RenderAttribs. class Attribute { public: INLINE Attribute(const RenderAttrib *attrib, int override); INLINE Attribute(int override = 0); INLINE Attribute(const Attribute ©); INLINE void operator = (const Attribute ©); INLINE void set(const RenderAttrib *attrib, int override); INLINE int compare_to(const Attribute &other) const; CPT(RenderAttrib) _attrib; int _override; }; Attribute *_attributes; // We also store a bitmask of the non-NULL attributes in the above // array. This is redundant, but it is a useful cache. SlotMask _filled_slots; // We cache the index to the associated CullBin, if there happens to // be a CullBinAttrib in the state. int _bin_index; int _draw_order; size_t _hash; const RenderState *_auto_shader_state; enum Flags { F_checked_bin_index = 0x000001, F_checked_cull_callback = 0x000002, F_has_cull_callback = 0x000004, F_is_destructing = 0x000008, F_hash_known = 0x000010, }; unsigned int _flags; vector_int *_read_overrides; // Only used during bam reading. // This mutex protects _flags, and all of the above computed values. LightMutex _lock; static CacheStats _cache_stats; public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(BamReader *manager); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { NodeCachedReferenceCount::init_type(); register_type(_type_handle, "RenderState", NodeCachedReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} private: static TypeHandle _type_handle; friend class GraphicsStateGuardian; friend class RenderAttribRegistry; }; INLINE ostream &operator << (ostream &out, const RenderState &state) { state.output(out); return out; } #include "renderState.I" #endif