// Filename: renderState.h // Created by: drose (21Feb02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #ifndef RENDERSTATE_H #define RENDERSTATE_H #include "pandabase.h" #include "renderAttrib.h" #include "nodeCachedReferenceCount.h" #include "pointerTo.h" #include "ordered_vector.h" #include "updateSeq.h" #include "pStatCollector.h" #include "renderModeAttrib.h" #include "texMatrixAttrib.h" #include "geomMunger.h" #include "weakPointerTo.h" #include "shaderExpansion.h" #include "reMutex.h" #include "pmutex.h" #include "deletedChain.h" class GraphicsStateGuardianBase; class FogAttrib; class CullBinAttrib; class TransparencyAttrib; class ColorAttrib; class ColorScaleAttrib; class TextureAttrib; class TexGenAttrib; class ClipPlaneAttrib; class ShaderAttrib; class FactoryParams; //////////////////////////////////////////////////////////////////// // 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 RenderState : public NodeCachedReferenceCount { protected: RenderState(); private: RenderState(const RenderState ©); void operator = (const RenderState ©); public: virtual ~RenderState(); ALLOC_DELETED_CHAIN(RenderState); PUBLISHED: bool operator < (const RenderState &other) const; size_t get_hash() const; INLINE bool is_empty() const; INLINE int get_num_attribs() const; INLINE const RenderAttrib *get_attrib(int n) const; INLINE int get_override(int n) const; INLINE bool has_cull_callback() const; bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; int find_attrib(TypeHandle type) const; static CPT(RenderState) make_empty(); 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); static CPT(RenderState) make(const AttribSlots *slots, 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) remove_attrib(TypeHandle type) const; CPT(RenderState) adjust_all_priorities(int adjustment) const; const RenderAttrib *get_attrib(TypeHandle type) const; int get_override(TypeHandle type) const; bool unref() const; INLINE void cache_ref() const; INLINE bool cache_unref() const; INLINE void node_ref() const; INLINE bool node_unref() 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 list_cycles(ostream &out); static void list_states(ostream &out); static bool validate_states(); 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 const FogAttrib *get_fog() const; INLINE const CullBinAttrib *get_bin() const; INLINE const TransparencyAttrib *get_transparency() const; INLINE int get_bin_index() const; INLINE const ColorAttrib *get_color() const; INLINE const ColorScaleAttrib *get_color_scale() const; INLINE const TextureAttrib *get_texture() const; INLINE const TexGenAttrib *get_tex_gen() const; INLINE const TexMatrixAttrib *get_tex_matrix() const; INLINE const RenderModeAttrib *get_render_mode() const; INLINE const ClipPlaneAttrib *get_clip_plane() const; INLINE const ShaderAttrib *get_shader() const; int get_geom_rendering(int geom_rendering) const; public: void store_into_slots(AttribSlots *slots) const; static void bin_removed(int bin_index); INLINE ShaderExpansion *get_shader_expansion() const; INLINE void set_shader_expansion(ShaderExpansion *exp); INLINE static void flush_level(); private: 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); CPT(RenderState) do_compose(const RenderState *other) const; CPT(RenderState) do_invert_compose(const RenderState *other) const; static bool r_detect_cycles(const RenderState *start_state, const RenderState *current_state, int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); void remove_cache_pointers(); void determine_bin_index(); void determine_fog(); INLINE void determine_bin(); void do_determine_bin(); INLINE void determine_transparency(); void do_determine_transparency(); void determine_color(); void determine_color_scale(); void determine_texture(); void determine_tex_gen(); void determine_tex_matrix(); void determine_render_mode(); void determine_clip_plane(); void determine_shader(); void determine_cull_callback(); 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(); private: // This mutex protects _states. It also protects any modification // to the cache, which is encoded in _composition_cache and // _invert_composition_cache. static ReMutex *_states_lock; typedef phash_set > States; static States *_states; static CPT(RenderState) _empty_state; // This iterator records the entry corresponding to this RenderState // object in the above global set. We keep the iterator around so // we can remove it when the RenderState destructs. States::iterator _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 phash_map 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; static PStatCollector _cache_update_pcollector; static PStatCollector _state_compose_pcollector; static PStatCollector _state_invert_pcollector; static PStatCollector _node_counter; static PStatCollector _cache_counter; private: // This is the actual data within the RenderState: a set of // RenderAttribs. class Attribute { public: INLINE Attribute(const RenderAttrib *attrib, int override); INLINE Attribute(int override); INLINE Attribute(TypeHandle type); INLINE Attribute(const Attribute ©); INLINE void operator = (const Attribute ©); INLINE bool operator < (const Attribute &other) const; INLINE int compare_to(const Attribute &other) const; TypeHandle _type; CPT(RenderAttrib) _attrib; int _override; }; typedef ov_set Attributes; Attributes _attributes; // We cache the index to the associated CullBin, if there happens to // be a CullBinAttrib in the state. int _bin_index; int _draw_order; // If this renderstate contains a Shader, then the macroexpansion // of the shader needs to be cached (to avoid having to regenerate // it each time this RenderState is applied). PT(ShaderExpansion) _shader_expansion; // We also cache the pointer to some critical attribs stored in the // state, if they exist. const FogAttrib *_fog; const CullBinAttrib *_bin; const TransparencyAttrib *_transparency; const ColorAttrib *_color; const ColorScaleAttrib *_color_scale; const TextureAttrib *_texture; const TexGenAttrib *_tex_gen; const TexMatrixAttrib *_tex_matrix; const RenderModeAttrib *_render_mode; const ClipPlaneAttrib *_clip_plane; const ShaderAttrib *_shader; enum Flags { F_checked_bin_index = 0x0001, F_checked_fog = 0x0002, F_checked_bin = 0x0004, F_checked_transparency = 0x0008, F_checked_color = 0x0010, F_checked_color_scale = 0x0020, F_checked_texture = 0x0040, F_checked_tex_gen = 0x0080, F_checked_tex_matrix = 0x0100, F_checked_render_mode = 0x0200, F_checked_clip_plane = 0x0400, F_checked_shader = 0x0800, F_checked_cull_callback = 0x1000, F_has_cull_callback = 0x2000, F_is_destructing = 0x8000, }; unsigned short _flags; // This mutex protects _flags, and all of the above computed values. Mutex _lock; 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; }; INLINE ostream &operator << (ostream &out, const RenderState &state) { state.output(out); return out; } #include "renderState.I" #endif