/** * 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." * * @file shader.h * @author jyelon * @date 2005-09-01 * @author fperazzi, PandaSE * @date 2010-04-29 */ #ifndef SHADER_H #define SHADER_H #include "pandabase.h" #include "config_gobj.h" #include "typedWritableReferenceCount.h" #include "namable.h" #include "graphicsStateGuardianBase.h" #include "internalName.h" #include "pta_int.h" #include "pta_float.h" #include "pta_double.h" #include "pta_stdfloat.h" #include "pta_LMatrix4.h" #include "pta_LMatrix3.h" #include "pta_LVecBase4.h" #include "pta_LVecBase3.h" #include "pta_LVecBase2.h" #include "epvector.h" #include "asyncFuture.h" #include "bamCacheRecord.h" #ifdef HAVE_CG // I don't want to include the Cg header file into panda as a whole. Instead, // I'll just excerpt some opaque declarations. typedef struct _CGcontext *CGcontext; typedef struct _CGprogram *CGprogram; typedef struct _CGparameter *CGparameter; #endif /** */ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { PUBLISHED: enum ShaderLanguage { SL_none, SL_Cg, SL_GLSL, SL_HLSL, SL_SPIR_V, }; enum ShaderType { ST_none = 0, ST_vertex, ST_fragment, ST_geometry, ST_tess_control, ST_tess_evaluation, ST_compute, ST_COUNT }; enum AutoShaderSwitch { AS_normal = 0x01, AS_glow = 0x02, AS_gloss = 0x04, AS_ramp = 0x08, AS_shadow = 0x10, }; enum AutoShaderBit { bit_AutoShaderNormal = 0, // bit for AS_normal bit_AutoShaderGlow = 1, // bit for AS_glow bit_AutoShaderGloss = 2, // bit for AS_gloss bit_AutoShaderRamp = 3, // bit for AS_ramp bit_AutoShaderShadow = 4, // bit for AS_shadow }; static PT(Shader) load(const Filename &file, ShaderLanguage lang = SL_none); static PT(Shader) make(std::string body, ShaderLanguage lang = SL_none); static PT(Shader) load(ShaderLanguage lang, const Filename &vertex, const Filename &fragment, const Filename &geometry = "", const Filename &tess_control = "", const Filename &tess_evaluation = ""); static PT(Shader) load_compute(ShaderLanguage lang, const Filename &fn); static PT(Shader) make(ShaderLanguage lang, std::string vertex, std::string fragment, std::string geometry = "", std::string tess_control = "", std::string tess_evaluation = ""); static PT(Shader) make_compute(ShaderLanguage lang, std::string body); INLINE Filename get_filename(ShaderType type = ST_none) const; INLINE void set_filename(ShaderType type, const Filename &filename); INLINE const std::string &get_text(ShaderType type = ST_none) const; INLINE bool get_error_flag() const; INLINE ShaderLanguage get_language() const; INLINE bool has_fullpath() const; INLINE const Filename &get_fullpath() const; INLINE bool get_cache_compiled_shader() const; INLINE void set_cache_compiled_shader(bool flag); PT(AsyncFuture) prepare(PreparedGraphicsObjects *prepared_objects); bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg); public: enum ShaderMatInput { SMO_identity, SMO_window_size, SMO_pixel_size, SMO_texpad_x, SMO_texpix_x, SMO_attr_material, SMO_attr_color, SMO_attr_colorscale, SMO_alight_x, SMO_dlight_x, SMO_plight_x, SMO_slight_x, SMO_satten_x, SMO_texmat_i, SMO_plane_x, SMO_clipplane_x, SMO_mat_constant_x, SMO_vec_constant_x, SMO_world_to_view, SMO_view_to_world, SMO_model_to_view, SMO_view_to_model, SMO_apiview_to_view, SMO_view_to_apiview, SMO_clip_to_view, SMO_view_to_clip, SMO_apiclip_to_view, SMO_view_to_apiclip, SMO_view_x_to_view, SMO_view_to_view_x, SMO_apiview_x_to_view, SMO_view_to_apiview_x, SMO_clip_x_to_view, SMO_view_to_clip_x, SMO_apiclip_x_to_view, SMO_view_to_apiclip_x, SMO_attr_fog, SMO_attr_fogcolor, SMO_frame_number, SMO_frame_time, SMO_frame_delta, SMO_mat_constant_x_attrib, SMO_vec_constant_x_attrib, SMO_light_ambient, SMO_light_source_i_attrib, SMO_light_product_i_ambient, SMO_light_product_i_diffuse, SMO_light_product_i_specular, // SMO_clipplane_x is world coords, GLSL needs eye coords SMO_apiview_clipplane_i, SMO_model_to_apiview, SMO_apiview_to_model, SMO_apiview_to_apiclip, SMO_apiclip_to_apiview, SMO_inv_texmat_i, // Additional properties for PBR materials SMO_attr_material2, // Hack for text rendering. Don't use in user shaders. SMO_tex_is_alpha_i, SMO_transform_i, SMO_slider_i, SMO_light_source_i_packed, // Texture scale component of texture matrix. SMO_texscale_i, // Color of an M_blend texture stage. SMO_texcolor_i, SMO_INVALID }; enum ShaderTexInput { STO_INVALID, STO_named_input, STO_named_stage, STO_stage_i, STO_light_i_shadow_map, }; enum ShaderArgClass { SAC_scalar, SAC_vector, SAC_matrix, SAC_sampler, SAC_array, SAC_unknown, }; enum ShaderArgType { SAT_scalar, SAT_vec1, SAT_vec2, SAT_vec3, SAT_vec4, SAT_mat1x1, SAT_mat1x2, SAT_mat1x3, SAT_mat1x4, SAT_mat2x1, SAT_mat2x2, SAT_mat2x3, SAT_mat2x4, SAT_mat3x1, SAT_mat3x2, SAT_mat3x3, SAT_mat3x4, SAT_mat4x1, SAT_mat4x2, SAT_mat4x3, SAT_mat4x4, SAT_sampler1d, SAT_sampler2d, SAT_sampler3d, SAT_sampler2d_array, SAT_sampler_cube, SAT_sampler_buffer, SAT_sampler_cube_array, SAT_unknown }; enum ShaderArgDir { SAD_in, SAD_out, SAD_inout, SAD_unknown, }; enum ShaderMatPiece { SMP_whole, SMP_transpose, SMP_row0, SMP_row1, SMP_row2, SMP_row3, SMP_col0, SMP_col1, SMP_col2, SMP_col3, SMP_row3x1, SMP_row3x2, SMP_row3x3, SMP_upper3x3, SMP_transpose3x3, SMP_cell15, SMP_cell14, SMP_cell13, }; enum ShaderStateDep { SSD_NONE = 0x000, SSD_general = 0x001, SSD_transform = 0x2002, SSD_color = 0x004, SSD_colorscale = 0x008, SSD_material = 0x010, SSD_shaderinputs = 0x020, SSD_fog = 0x040, SSD_light = 0x080, SSD_clip_planes = 0x100, SSD_tex_matrix = 0x200, SSD_frame = 0x400, SSD_projection = 0x800, SSD_texture = 0x1000, SSD_view_transform= 0x2000, }; enum ShaderBug { SBUG_ati_draw_buffers, }; enum ShaderMatFunc { SMF_compose, SMF_transform_dlight, SMF_transform_plight, SMF_transform_slight, SMF_first, }; struct ShaderArgId { std::string _name; ShaderType _type; int _seqno; }; enum ShaderPtrType { SPT_float, SPT_double, SPT_int, SPT_uint, SPT_unknown }; struct ShaderArgInfo { ShaderArgId _id; ShaderArgClass _class; ShaderArgClass _subclass; ShaderArgType _type; ShaderArgDir _direction; bool _varying; ShaderPtrType _numeric_type; NotifyCategory *_cat; }; // Container structure for data of parameters ShaderPtrSpec. struct ShaderPtrData { private: PT(ReferenceCount) _pta; public: void *_ptr; ShaderPtrType _type; bool _updated; size_t _size; //number of elements vec3[4]=12 public: INLINE ShaderPtrData(); INLINE ShaderPtrData(const PTA_float &ptr); INLINE ShaderPtrData(const PTA_LVecBase4f &ptr); INLINE ShaderPtrData(const PTA_LVecBase3f &ptr); INLINE ShaderPtrData(const PTA_LVecBase2f &ptr); INLINE ShaderPtrData(const PTA_LMatrix4f &mat); INLINE ShaderPtrData(const PTA_LMatrix3f &mat); INLINE ShaderPtrData(const LVecBase4f &vec); INLINE ShaderPtrData(const LVecBase3f &vec); INLINE ShaderPtrData(const LVecBase2f &vec); INLINE ShaderPtrData(const LMatrix4f &mat); INLINE ShaderPtrData(const LMatrix3f &mat); INLINE ShaderPtrData(const PTA_double &ptr); INLINE ShaderPtrData(const PTA_LVecBase4d &ptr); INLINE ShaderPtrData(const PTA_LVecBase3d &ptr); INLINE ShaderPtrData(const PTA_LVecBase2d &ptr); INLINE ShaderPtrData(const PTA_LMatrix4d &mat); INLINE ShaderPtrData(const PTA_LMatrix3d &mat); INLINE ShaderPtrData(const LVecBase4d &vec); INLINE ShaderPtrData(const LVecBase3d &vec); INLINE ShaderPtrData(const LVecBase2d &vec); INLINE ShaderPtrData(const LMatrix4d &mat); INLINE ShaderPtrData(const LMatrix3d &mat); INLINE ShaderPtrData(const PTA_int &ptr); INLINE ShaderPtrData(const PTA_LVecBase4i &ptr); INLINE ShaderPtrData(const PTA_LVecBase3i &ptr); INLINE ShaderPtrData(const PTA_LVecBase2i &ptr); INLINE ShaderPtrData(const LVecBase4i &vec); INLINE ShaderPtrData(const LVecBase3i &vec); INLINE ShaderPtrData(const LVecBase2i &vec); INLINE void write_datagram(Datagram &dg) const; INLINE void read_datagram(DatagramIterator &source); }; struct ShaderMatSpec { LMatrix4 _cache[2]; LMatrix4 _value; ShaderArgId _id; ShaderMatFunc _func; ShaderMatInput _part[2]; PT(InternalName) _arg[2]; int _dep[2]; int _index; ShaderMatPiece _piece; }; struct ShaderTexSpec { ShaderArgId _id; PT(InternalName) _name; ShaderTexInput _part; int _stage; int _desired_type; PT(InternalName) _suffix; }; struct ShaderVarSpec { ShaderArgId _id; PT(InternalName) _name; int _append_uv; int _elements; ShaderPtrType _numeric_type; }; struct ShaderPtrSpec { ShaderArgId _id; int _dim[3]; //n_elements,rows,cols int _dep[2]; PT(InternalName) _arg; ShaderArgInfo _info; ShaderPtrType _type; }; class EXPCL_PANDA_GOBJ ShaderCaps { public: void clear(); INLINE bool operator == (const ShaderCaps &other) const; INLINE ShaderCaps(); public: bool _supports_glsl; #ifdef HAVE_CG int _active_vprofile; int _active_fprofile; int _active_gprofile; int _active_tprofile; int _ultimate_vprofile; int _ultimate_fprofile; int _ultimate_gprofile; int _ultimate_tprofile; pset _bug_list; #endif }; class ShaderFile : public ReferenceCount { public: INLINE ShaderFile() {}; INLINE ShaderFile(std::string shared); INLINE ShaderFile(std::string vertex, std::string fragment, std::string geometry, std::string tess_control, std::string tess_evaluation); INLINE void write_datagram(Datagram &dg) const; INLINE void read_datagram(DatagramIterator &source); INLINE bool operator < (const ShaderFile &other) const; public: bool _separate; std::string _shared; std::string _vertex; std::string _fragment; std::string _geometry; std::string _tess_control; std::string _tess_evaluation; std::string _compute; }; public: // These routines help split the shader into sections, for those shader // implementations that need to do so. Don't use them when you use separate // shader programs. void parse_init(); void parse_line(std::string &result, bool rt, bool lt); void parse_upto(std::string &result, std::string pattern, bool include); void parse_rest(std::string &result); bool parse_eof(); void cp_report_error(ShaderArgInfo &arg, const std::string &msg); bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len); bool cp_errchk_parameter_in(ShaderArgInfo &arg); bool cp_errchk_parameter_ptr(ShaderArgInfo &p); bool cp_errchk_parameter_varying(ShaderArgInfo &arg); bool cp_errchk_parameter_uniform(ShaderArgInfo &arg); bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi); bool cp_errchk_parameter_sampler(ShaderArgInfo &arg); bool cp_parse_eol(ShaderArgInfo &arg, vector_string &pieces, int &next); bool cp_parse_delimiter(ShaderArgInfo &arg, vector_string &pieces, int &next); std::string cp_parse_non_delimiter(vector_string &pieces, int &next); bool cp_parse_coord_sys(ShaderArgInfo &arg, vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag); int cp_dependency(ShaderMatInput inp); void cp_optimize_mat_spec(ShaderMatSpec &spec); #ifdef HAVE_CG void cg_recurse_parameters(CGparameter parameter, const ShaderType &type, bool &success); #endif bool compile_parameter(ShaderArgInfo &p, int *arg_dim); void clear_parameters(); void set_compiled(unsigned int format, const char *data, size_t length); bool get_compiled(unsigned int &format, std::string &binary) const; static void set_default_caps(const ShaderCaps &caps); private: #ifdef HAVE_CG ShaderArgClass cg_parameter_class(CGparameter p); ShaderArgType cg_parameter_type(CGparameter p); ShaderArgDir cg_parameter_dir(CGparameter p); CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps, CGcontext context, ShaderType type); bool cg_analyze_entry_point(CGprogram prog, ShaderType type); bool cg_analyze_shader(const ShaderCaps &caps); bool cg_compile_shader(const ShaderCaps &caps, CGcontext context); void cg_release_resources(); void cg_report_errors(); // Determines the appropriate cg profile settings and stores them in the // active shader caps based on any profile settings stored in the shader's // header void cg_get_profile_from_header(ShaderCaps &caps); ShaderCaps _cg_last_caps; static CGcontext _cg_context; CGprogram _cg_vprogram; CGprogram _cg_fprogram; CGprogram _cg_gprogram; int _cg_vprofile; int _cg_fprofile; int _cg_gprofile; CGprogram cg_program_from_shadertype(ShaderType type); public: bool cg_compile_for(const ShaderCaps &caps, CGcontext context, CGprogram &combined_program, pvector &map); #endif public: pvector _ptr_spec; epvector _mat_spec; pvector _tex_spec; pvector _var_spec; int _mat_deps; bool _error_flag; ShaderFile _text; protected: ShaderFile _filename; Filename _fullpath; int _parse; bool _loaded; ShaderLanguage _language; typedef pvector Filenames; Filenames _included_files; // Stores full paths, and includes the fullpaths of the shaders themselves // as well as the includes. Filenames _source_files; time_t _last_modified; PT(BamCacheRecord) _record; bool _cache_compiled_shader; unsigned int _compiled_format; std::string _compiled_binary; static ShaderCaps _default_caps; static int _shaders_generated; typedef pmap ShaderTable; static ShaderTable _load_table; static ShaderTable _make_table; friend class ShaderContext; friend class PreparedGraphicsObjects; typedef pmap Contexts; Contexts _contexts; private: void clear_prepared(PreparedGraphicsObjects *prepared_objects); Shader(ShaderLanguage lang); bool read(const ShaderFile &sfile, BamCacheRecord *record = nullptr); bool load(const ShaderFile &sbody, BamCacheRecord *record = nullptr); bool do_read_source(std::string &into, const Filename &fn, BamCacheRecord *record); bool do_load_source(std::string &into, const std::string &source, BamCacheRecord *record); bool r_preprocess_include(std::ostream &out, const Filename &fn, const Filename &source_dir, std::set &open_files, BamCacheRecord *record, int depth); bool r_preprocess_source(std::ostream &out, std::istream &in, const Filename &fn, const Filename &full_fn, std::set &open_files, BamCacheRecord *record, int fileno = 0, int depth = 0); bool check_modified() const; public: ~Shader(); Filename get_filename_from_index(int index, ShaderType type) const; public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); 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() { TypedWritableReferenceCount::init_type(); register_type(_type_handle, "Shader", TypedWritableReferenceCount::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; }; #include "shader.I" #endif