From 1fdb425b88f24b8678374bd82ceefcf60ddefa4e Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 15 Mar 2007 21:04:31 +0000 Subject: [PATCH] merge shader_overhaul from jyelon --- panda/src/display/graphicsStateGuardian.cxx | 60 +- panda/src/display/graphicsStateGuardian.h | 6 +- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 113 +- panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 6 +- panda/src/dxgsg9/dxShaderContext9.I | 7 +- panda/src/dxgsg9/dxShaderContext9.cxx | 740 +++-------- panda/src/dxgsg9/dxShaderContext9.h | 123 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 14 +- panda/src/glstuff/glShaderContext_src.I | 4 +- panda/src/glstuff/glShaderContext_src.cxx | 460 ++----- panda/src/glstuff/glShaderContext_src.h | 20 +- panda/src/gobj/Sources.pp | 2 +- panda/src/gobj/preparedGraphicsObjects.cxx | 10 +- panda/src/gobj/shaderContext.I | 2 +- panda/src/gobj/shaderContext.cxx | 675 ---------- panda/src/gobj/shaderContext.h | 151 +-- panda/src/gobj/shaderExpansion.I | 66 + panda/src/gobj/shaderExpansion.cxx | 1139 ++++++++++++++++- panda/src/gobj/shaderExpansion.h | 224 +++- panda/src/mesadisplay/mesagsg.h | 3 - panda/src/pgraph/shader.cxx | 8 +- panda/src/pgraph/shader.h | 3 +- 22 files changed, 1843 insertions(+), 1993 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 17529f680f..4c28792a5f 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -783,7 +783,7 @@ clear(DrawableRegion *clearable) { // //////////////////////////////////////////////////////////////////// const LMatrix4f *GraphicsStateGuardian:: -fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered) { +fetch_specified_value(ShaderExpansion::ShaderMatSpec &spec, bool altered) { static LMatrix4f acc; const LMatrix4f *val1; const LMatrix4f *val2; @@ -791,26 +791,26 @@ fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered) { static LMatrix4f t2; switch(spec._func) { - case ShaderContext::SMF_compose: + case ShaderExpansion::SMF_compose: val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1); val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); acc.multiply(*val1, *val2); return &acc; - case ShaderContext::SMF_compose_cache_first: + case ShaderExpansion::SMF_compose_cache_first: if (altered) { spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1); } val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); acc.multiply(spec._cache, *val2); return &acc; - case ShaderContext::SMF_compose_cache_second: + case ShaderExpansion::SMF_compose_cache_second: if (altered) { spec._cache = *fetch_specified_part(spec._part[1], spec._arg[1], t2); } val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1); acc.multiply(*val1, spec._cache); return &acc; - case ShaderContext::SMF_first: + case ShaderExpansion::SMF_first: return fetch_specified_part(spec._part[0], spec._arg[0], t1); default: // should never get here @@ -824,24 +824,24 @@ fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered) { // Description: See fetch_specified_value //////////////////////////////////////////////////////////////////// const LMatrix4f *GraphicsStateGuardian:: -fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMatrix4f &t) { +fetch_specified_part(ShaderExpansion::ShaderMatInput part, InternalName *name, LMatrix4f &t) { switch(part) { - case ShaderContext::SMO_identity: { + case ShaderExpansion::SMO_identity: { return &LMatrix4f::ident_mat(); } - case ShaderContext::SMO_window_size: { + case ShaderExpansion::SMO_window_size: { t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), _current_display_region->get_pixel_height(), 0.0); return &t; } - case ShaderContext::SMO_pixel_size: { + case ShaderExpansion::SMO_pixel_size: { t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), _current_display_region->get_pixel_height(), 0.0); return &t; } - case ShaderContext::SMO_card_center: { + case ShaderExpansion::SMO_card_center: { int px = _current_display_region->get_pixel_width(); int py = _current_display_region->get_pixel_height(); t = LMatrix4f::translate_mat((px*0.5) / Texture::up_to_power_2(px), @@ -849,14 +849,14 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa 0.0); return &t; } - case ShaderContext::SMO_mat_constant_x: { + case ShaderExpansion::SMO_mat_constant_x: { const ShaderInput *input = _target._shader->get_shader_input(name); if (input->get_nodepath().is_empty()) { return &LMatrix4f::ident_mat(); } return &(input->get_nodepath().node()->get_transform()->get_mat()); } - case ShaderContext::SMO_vec_constant_x: { + case ShaderExpansion::SMO_vec_constant_x: { const ShaderInput *input = _target._shader->get_shader_input(name); const float *data = input->get_vector().get_data(); t = LMatrix4f(data[0],data[1],data[2],data[3], @@ -865,28 +865,28 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa data[0],data[1],data[2],data[3]); return &t; } - case ShaderContext::SMO_world_to_view: { + case ShaderExpansion::SMO_world_to_view: { return &(get_scene()->get_world_transform()->get_mat()); break; } - case ShaderContext::SMO_view_to_world: { + case ShaderExpansion::SMO_view_to_world: { return &(get_scene()->get_camera_transform()->get_mat()); } - case ShaderContext::SMO_model_to_view: { + case ShaderExpansion::SMO_model_to_view: { return &(get_external_transform()->get_mat()); } - case ShaderContext::SMO_view_to_model: { + case ShaderExpansion::SMO_view_to_model: { // DANGER: SLOW AND NOT CACHEABLE! t.invert_from(get_external_transform()->get_mat()); return &t; } - case ShaderContext::SMO_apiview_to_view: { + case ShaderExpansion::SMO_apiview_to_view: { return &(_inv_cs_transform->get_mat()); } - case ShaderContext::SMO_view_to_apiview: { + case ShaderExpansion::SMO_view_to_apiview: { return &(_cs_transform->get_mat()); } - case ShaderContext::SMO_clip_to_view: { + case ShaderExpansion::SMO_clip_to_view: { if (_current_lens->get_coordinate_system() == _coordinate_system) { return &(_current_lens->get_projection_mat_inv(_current_stereo_channel)); } else { @@ -895,7 +895,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa return &t; } } - case ShaderContext::SMO_view_to_clip: { + case ShaderExpansion::SMO_view_to_clip: { if (_current_lens->get_coordinate_system() == _coordinate_system) { return &(_current_lens->get_projection_mat(_current_stereo_channel)); } else { @@ -904,15 +904,15 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa return &t; } } - case ShaderContext::SMO_apiclip_to_view: { + case ShaderExpansion::SMO_apiclip_to_view: { t = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat(); return &t; } - case ShaderContext::SMO_view_to_apiclip: { + case ShaderExpansion::SMO_view_to_apiclip: { t = _cs_transform->get_mat() * _projection_mat->get_mat(); return &t; } - case ShaderContext::SMO_view_x_to_view: { + case ShaderExpansion::SMO_view_x_to_view: { const ShaderInput *input = _target._shader->get_shader_input(name); if (input->get_nodepath().is_empty()) { @@ -927,7 +927,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa get_scene()->get_world_transform()->get_mat(); return &t; } - case ShaderContext::SMO_view_to_view_x: { + case ShaderExpansion::SMO_view_to_view_x: { const ShaderInput *input = _target._shader->get_shader_input(name); if (input->get_nodepath().is_empty()) { @@ -942,7 +942,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa invert(input->get_nodepath().get_net_transform()->get_mat()); return &t; } - case ShaderContext::SMO_apiview_x_to_view: { + case ShaderExpansion::SMO_apiview_x_to_view: { const ShaderInput *input = _target._shader->get_shader_input(name); nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); t = LMatrix4f::convert_mat(_internal_coordinate_system, _coordinate_system) * @@ -950,7 +950,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa get_scene()->get_world_transform()->get_mat(); return &t; } - case ShaderContext::SMO_view_to_apiview_x: { + case ShaderExpansion::SMO_view_to_apiview_x: { const ShaderInput *input = _target._shader->get_shader_input(name); nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); t = (get_scene()->get_camera_transform()->get_mat() * @@ -958,7 +958,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa LMatrix4f::convert_mat(_coordinate_system, _internal_coordinate_system)); return &t; } - case ShaderContext::SMO_clip_x_to_view: { + case ShaderExpansion::SMO_clip_x_to_view: { const ShaderInput *input = _target._shader->get_shader_input(name); nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); @@ -968,7 +968,7 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa get_scene()->get_world_transform()->get_mat(); return &t; } - case ShaderContext::SMO_view_to_clip_x: { + case ShaderExpansion::SMO_view_to_clip_x: { const ShaderInput *input = _target._shader->get_shader_input(name); nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); @@ -978,11 +978,11 @@ fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMa lens->get_projection_mat(_current_stereo_channel); return &t; } - case ShaderContext::SMO_apiclip_x_to_view: { + case ShaderExpansion::SMO_apiclip_x_to_view: { // NOT IMPLEMENTED return &LMatrix4f::ident_mat(); } - case ShaderContext::SMO_view_to_apiclip_x: { + case ShaderExpansion::SMO_view_to_apiclip_x: { // NOT IMPLEMENTED return &LMatrix4f::ident_mat(); } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index ec8cc55826..1d11830f56 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -194,8 +194,8 @@ public: void clear(DrawableRegion *clearable); - const LMatrix4f *fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered); - const LMatrix4f *fetch_specified_part(ShaderContext::ShaderMatInput input, InternalName *name, LMatrix4f &t); + const LMatrix4f *fetch_specified_value(ShaderExpansion::ShaderMatSpec &spec, bool altered); + const LMatrix4f *fetch_specified_part(ShaderExpansion::ShaderMatInput input, InternalName *name, LMatrix4f &t); virtual void prepare_display_region(DisplayRegionPipelineReader *dr, Lens::StereoChannel stereo_channel); @@ -410,6 +410,8 @@ protected: static PT(TextureStage) _alpha_scale_texture_stage; + ShaderExpansion::ShaderCaps _shader_caps; + public: // Statistics static PStatCollector _vertex_buffer_switch_pcollector; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 87ad2c99da..d53de0a0a4 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -61,6 +61,9 @@ #include "pStatTimer.h" #include "pStatCollector.h" #include "wdxGraphicsBuffer9.h" +#ifdef HAVE_CG +#include "Cg/cgD3D9.h" +#endif #include @@ -147,10 +150,6 @@ DXGraphicsStateGuardian9(GraphicsPipe *pipe) : _vertex_shader_maximum_constants = 0; _supports_stream_offset = false; - -#ifdef HAVE_CGDX9 - _cg_context = 0; -#endif } //////////////////////////////////////////////////////////////////// @@ -169,14 +168,6 @@ DXGraphicsStateGuardian9:: delete _lru; _lru = 0; } - -#ifdef HAVE_CGDX9 - if (_cg_context) { - cgD3D9SetDevice (NULL); - cgDestroyContext (_cg_context); - _cg_context = 0; - } -#endif } //////////////////////////////////////////////////////////////////// @@ -346,10 +337,9 @@ release_texture(TextureContext *tc) { //////////////////////////////////////////////////////////////////// ShaderContext *CLP(GraphicsStateGuardian):: prepare_shader(ShaderExpansion *se) { -#ifdef HAVE_CGDX9 +#ifdef HAVE_CG CLP(ShaderContext) *result = new CLP(ShaderContext)(se, this); - if (this -> _cg_context) return result; - delete result; + return result; #endif return NULL; } @@ -2395,7 +2385,6 @@ reset() { _vertex_shader_maximum_constants = d3d_caps.MaxVertexShaderConst; -#ifdef HAVE_CGDX9 switch (_pixel_shader_version_major) { case 0: @@ -2419,11 +2408,49 @@ reset() { _shader_model = SM_40; break; } -#else - _shader_model = SM_00; -#endif + _auto_detect_shader_model = _shader_model; +#ifdef HAVE_CG + cgD3D9SetDevice (_d3d_device); + + if (cgD3D9IsProfileSupported(CG_PROFILE_PS_2_0) && + cgD3D9IsProfileSupported(CG_PROFILE_VS_2_0)) { + _supports_basic_shaders = true; + _shader_caps._active_vprofile = (int)cgD3D9GetLatestVertexProfile(); + _shader_caps._active_fprofile = (int)cgD3D9GetLatestPixelProfile(); + _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_3_0; + _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_3_0; + } + + if (dxgsg9_cat.is_debug()) { + + CGprofile vertex_profile; + CGprofile pixel_profile; + + vertex_profile = cgD3D9GetLatestVertexProfile( ); + pixel_profile = cgD3D9GetLatestPixelProfile( ); + + const char *vertex_profile_str = + cgGetProfileString(vertex_profile); + const char *pixel_profile_str = + cgGetProfileString(pixel_profile); + + if (vertex_profile_str == NULL) { + vertex_profile_str = "(null)"; + } + if (pixel_profile_str == NULL) { + pixel_profile_str = "(null)"; + } + + dxgsg9_cat.debug() + << "\nCg vertex profile = " << vertex_profile_str << " id = " << vertex_profile + << "\nCg pixel profile = " << pixel_profile_str << " id = " << pixel_profile + << "\nshader model = " << _shader_model + << "\n"; + } +#endif + _supports_stream_offset = (d3d_caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET) != 0; _screen->_supports_dynamic_textures = ((d3d_caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0); _screen->_supports_automatic_mipmap_generation = ((d3d_caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0); @@ -2475,52 +2502,6 @@ reset() { this -> reset_render_states ( ); - // duplicates OpenGL version (ARB_vertex_program extension and - // ARB_fragment_program extension) - if (_vertex_shader_version_major >= 1 && - _pixel_shader_version_major >= 2) { - _supports_basic_shaders = true; - } - -#ifdef HAVE_CGDX9 - if (_cg_context == 0) { - _cg_context = cgCreateContext ( ); - cgD3D9SetDevice (_d3d_device); - } - else { - cgD3D9SetDevice (_d3d_device); - } - - if (_cg_context) { - if (dxgsg9_cat.is_debug()) { - - CGprofile vertex_profile; - CGprofile pixel_profile; - - vertex_profile = cgD3D9GetLatestVertexProfile( ); - pixel_profile = cgD3D9GetLatestPixelProfile( ); - - const char *vertex_profile_str = - cgGetProfileString(vertex_profile); - const char *pixel_profile_str = - cgGetProfileString(pixel_profile); - - if (vertex_profile_str == NULL) { - vertex_profile_str = "(null)"; - } - if (pixel_profile_str == NULL) { - pixel_profile_str = "(null)"; - } - - dxgsg9_cat.debug() - << "\nCg vertex profile = " << vertex_profile_str << " id = " << vertex_profile - << "\nCg pixel profile = " << pixel_profile_str << " id = " << pixel_profile - << "\nshader model = " << _shader_model - << "\n"; - } - } -#endif - _max_vertices_per_array = d3d_caps.MaxVertexIndex; _max_vertices_per_primitive = d3d_caps.MaxPrimitiveCount; @@ -2945,7 +2926,7 @@ do_issue_shader() { ShaderExpansion *expansion = _target_rs->get_shader_expansion(); if (expansion == 0) { if (_target._shader->get_shader() != 0) { - expansion = _target._shader->get_shader()->macroexpand(_target_rs); + expansion = _target._shader->get_shader()->macroexpand(_target_rs, _shader_caps); // I am casting away the const-ness of this pointer, because // the 'shader-expansion' field is just a cache. ((RenderState *)((const RenderState*)_target_rs))-> diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 44c505a70f..605a6b0755 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -250,11 +250,7 @@ protected: public: DXScreenData *_screen; - -#ifdef HAVE_CGDX9 - CGcontext _cg_context; -#endif - + protected: LPDIRECT3DDEVICE9 _d3d_device; // same as _screen->_d3d_device, cached for spd IDirect3DSwapChain9 *_swap_chain; diff --git a/panda/src/dxgsg9/dxShaderContext9.I b/panda/src/dxgsg9/dxShaderContext9.I index e0751bf4a7..0b049d96e1 100644 --- a/panda/src/dxgsg9/dxShaderContext9.I +++ b/panda/src/dxgsg9/dxShaderContext9.I @@ -27,6 +27,11 @@ //////////////////////////////////////////////////////////////////// INLINE bool CLP(ShaderContext):: valid (GSG *gsg) { - return _state; +#ifdef HAVE_CG + if (_cg_context) { + return true; + } +#endif + return false; } diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index c25c70112d..7cd13f7962 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -25,54 +25,14 @@ #include #include #include +#ifdef HAVE_CG +#include "Cg/cgD3D9.h" +#endif #define DEBUG_SHADER 0 TypeHandle CLP(ShaderContext)::_type_handle; -static char *vertex_shader_function_name = "vshader"; -static char *pixel_shader_function_name = "fshader"; - -#ifdef HAVE_CGDX9 -//////////////////////////////////////////////////////////////////// -// Function: cg_type_to_panda_type -// Access: Public, Static -// Description: convert a cg shader-arg type to a panda shader-arg type. -//////////////////////////////////////////////////////////////////// -static ShaderContext::ShaderArgType -cg_type_to_panda_type(CGtype n) { - switch (n) { - case CG_FLOAT1: return ShaderContext::SAT_float1; - case CG_FLOAT2: return ShaderContext::SAT_float2; - case CG_FLOAT3: return ShaderContext::SAT_float3; - case CG_FLOAT4: return ShaderContext::SAT_float4; - case CG_FLOAT4x4: return ShaderContext::SAT_float4x4; - case CG_SAMPLER1D: return ShaderContext::SAT_sampler1d; - case CG_SAMPLER2D: return ShaderContext::SAT_sampler2d; - case CG_SAMPLER3D: return ShaderContext::SAT_sampler3d; - case CG_SAMPLERCUBE: return ShaderContext::SAT_samplercube; - default: return ShaderContext::SAT_unknown; - } -} -#endif // HAVE_CGDX9 - -#ifdef HAVE_CGDX9 -//////////////////////////////////////////////////////////////////// -// Function: cg_dir_to_panda_dir -// Access: Public, Static -// Description: convert a cg shader-arg type to a panda shader-arg type. -//////////////////////////////////////////////////////////////////// -static ShaderContext::ShaderArgDir -cg_dir_to_panda_dir(CGenum n) { - switch (n) { - case CG_IN: return ShaderContext::SAD_in; - case CG_OUT: return ShaderContext::SAD_out; - case CG_INOUT: return ShaderContext::SAD_inout; - default: return ShaderContext::SAD_unknown; - } -} -#endif // HAVE_CGDX9 - //////////////////////////////////////////////////////////////////// // Function: DXShaderContext9::Constructor // Access: Public @@ -80,80 +40,70 @@ cg_dir_to_panda_dir(CGenum n) { //////////////////////////////////////////////////////////////////// CLP(ShaderContext):: CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) { - string header; - s->parse_init(); - s->parse_line(header, true, true); - - _state = false; - -#ifdef HAVE_CGDX9 - - DBG_SH2 dxgsg9_cat.debug ( ) << "SHADER: Create ShaderContext \n"; DBG_E - - _cg_shader = false; - - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - _cg_program[SHADER_type_vert] = (CGprogram)0; - _cg_program[SHADER_type_frag] = (CGprogram)0; _vertex_size = 0; _vertex_element_array = 0; - - _total_dx_parameters = 0; - _dx_parameter_array = 0; - - _transpose_matrix = false; - _name = s->get_name ( ); - if (header == "//Cg") { +#ifdef HAVE_CG + if (s->get_header() == "//Cg") { + + // Ask the shader expansion to compile itself for us and + // to give us the resulting Cg program objects. - // CGcontext is created once during Reset ( ) - if (gsg -> _cg_context == 0) { - release_resources(); - dxgsg9_cat.error() << "Cg not supported by this video card.\n"; + if (!s->cg_compile_for(gsg->_shader_caps, + _cg_context, + _cg_vprogram, + _cg_fprogram, + _cg_parameter_map)) { return; } + + // Load the program. - // Parse any directives in the source. - // IGNORE SPECIFIC PROFILES IN DX FOR NOW - if (false) { - string directive; - while (!s->parse_eof()) { - s->parse_line(directive, true, true); - vector_string pieces; - tokenize(directive, pieces, " \t"); - if ((pieces.size()==4)&&(pieces[0]=="//Cg")&&(pieces[1]=="profile")) { - suggest_cg_profile(pieces[2], pieces[3]); - } - } - } - - // Select a profile if no preferred profile specified in the source. - if (_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN) { - _cg_profile[SHADER_type_vert] = cgD3D9GetLatestVertexProfile( ); - } - if (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN) { - _cg_profile[SHADER_type_frag] = cgD3D9GetLatestPixelProfile( ); - } - - // If we still haven't chosen a profile, give up. - if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { - release_resources(); - dxgsg9_cat.error() << "Cg not supported by this video card.\n"; - return; - } - - // Compile the program. - _cg_shader = true; - try_cg_compile(s, gsg); - return; - } + BOOL paramater_shadowing; + DWORD assembly_flags; + + paramater_shadowing = FALSE; + assembly_flags = 0; + +#if DEBUG_SHADER + assembly_flags |= D3DXSHADER_DEBUG; #endif - dxgsg9_cat.error() << s->get_name() << ": unrecognized shader language " << header << "\n"; + HRESULT hr; + bool success = true; + hr = cgD3D9LoadProgram(_cg_vprogram, paramater_shadowing, assembly_flags); + if (FAILED (hr)) { + dxgsg9_cat.error() + << "vertex shader cgD3D9LoadProgram failed " + << D3DERRORSTRING(hr); + + CGerror error = cgGetError(); + if (error != CG_NO_ERROR) { + dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; + } + success = false; + } + + hr = cgD3D9LoadProgram(_cg_fprogram, paramater_shadowing, assembly_flags); + if (FAILED (hr)) { + dxgsg9_cat.error() + << "pixel shader cgD3D9LoadProgram failed " + << D3DERRORSTRING(hr); + + CGerror error = cgGetError(); + if (error != CG_NO_ERROR) { + dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; + } + success = false; + } + + if (!success) { + release_resources(); + } + } +#endif } //////////////////////////////////////////////////////////////////// @@ -171,340 +121,53 @@ CLP(ShaderContext):: } } -#ifdef HAVE_CGDX9 -//////////////////////////////////////////////////////////////////// -// Function: Shader::report_cg_compile_errors -// Access: Public, Static -// Description: Used only after a Cg compile command, to print -// out any error messages that may have occurred -// during the Cg shader compilation. The 'file' -// is the name of the file containing the Cg code. -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -report_cg_compile_errors(const string &file, CGcontext ctx) -{ - CGerror err = cgGetError(); - if (err != CG_NO_ERROR) { - if (err == CG_COMPILER_ERROR) { - string listing = cgGetLastListing(ctx); - vector_string errlines; - tokenize(listing, errlines, "\n"); - for (int i=0; i<(int)errlines.size(); i++) { - string line = trim(errlines[i]); - if (line != "") { - dxgsg9_cat.error() << file << " " << errlines[i] << "\n"; - } - } - } else { - dxgsg9_cat.error() << file << ": " << cgGetErrorString(err) << "\n"; - } - } -} -#endif // HAVE_CGDX9 - -//////////////////////////////////////////////////////////////////// -// Function: DXShaderContext9::suggest_cg_profile -// Access: Private -// Description: xyz -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGDX9 -void CLP(ShaderContext):: -suggest_cg_profile(const string &vpro, const string &fpro) -{ - // If a good profile has already been suggested, ignore suggestion. - if ((_cg_profile[SHADER_type_vert] != CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] != CG_PROFILE_UNKNOWN)) { - return; - } - - // Parse the suggestion. If not parseable, print error and ignore. - _cg_profile[SHADER_type_vert] = parse_cg_profile(vpro, true); - _cg_profile[SHADER_type_frag] = parse_cg_profile(fpro, false); - if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { - dxgsg9_cat.error() << "Cg: unrecognized profile name: " << vpro << " " << fpro << "\n"; - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - return; - } - -// NO EQUIVALENT FUNCTIONALITY FROM GL TO DX -/* - // If the suggestion is parseable, but not supported, ignore silently. - if ((!cgGLIsProfileSupported(_cg_profile[SHADER_type_vert]))|| - (!cgGLIsProfileSupported(_cg_profile[SHADER_type_frag]))) { - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - return; - } -*/ - -} -#endif - -//////////////////////////////////////////////////////////////////// -// Function: DXShaderContext9::parse_cg_profile -// Access: Private -// Description: xyz -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGDX9 -CGprofile CLP(ShaderContext):: -parse_cg_profile(const string &id, bool vertex) -{ - int i = 0; - CGprofile vprofiles[] = { CG_PROFILE_ARBVP1, CG_PROFILE_VP20, CG_PROFILE_VP30, CG_PROFILE_VP40, CG_PROFILE_UNKNOWN }; - CGprofile fprofiles[] = { CG_PROFILE_ARBFP1, CG_PROFILE_FP20, CG_PROFILE_FP30, CG_PROFILE_FP40, CG_PROFILE_UNKNOWN }; - - // near equivalent DX profiles -#if (CG_VERSION_NUM >= 1502) - CGprofile dx_vprofiles[] = { CG_PROFILE_VS_2_0, CG_PROFILE_VS_1_1, CG_PROFILE_VS_2_X, CG_PROFILE_VS_3_0, CG_PROFILE_UNKNOWN }; - CGprofile dx_fprofiles[] = { CG_PROFILE_PS_2_0, CG_PROFILE_PS_1_1, CG_PROFILE_PS_2_X, CG_PROFILE_PS_3_0, CG_PROFILE_UNKNOWN }; -#else - CGprofile dx_vprofiles[] = { CG_PROFILE_VS_2_0, CG_PROFILE_VS_1_1, CG_PROFILE_VS_2_X, CG_PROFILE_VS_2_X, CG_PROFILE_UNKNOWN }; - CGprofile dx_fprofiles[] = { CG_PROFILE_PS_2_0, CG_PROFILE_PS_1_1, CG_PROFILE_PS_2_X, CG_PROFILE_PS_2_X, CG_PROFILE_UNKNOWN }; -#endif - - if (vertex) { - while (vprofiles[i] != CG_PROFILE_UNKNOWN) { - if (id == cgGetProfileString(vprofiles[i])) { - return dx_vprofiles[i]; - } - i++; - } - } else { - while (fprofiles[i] != CG_PROFILE_UNKNOWN) { - if (id == cgGetProfileString(fprofiles[i])) { - return dx_fprofiles[i]; - } - i++; - } - } - return CG_PROFILE_UNKNOWN; -} -#endif // HAVE_CGDX9 - -int save_file (int size, void *data, char *file_path) -{ - int state; - int file_handle; - - state = false; - file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE); - if (file_handle != -1) { - if (_write (file_handle, data, size) == size) { - state = true; - } - _close (file_handle); - } - - return state; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXShaderContext9::try_cg_compile -// Access: Private -// Description: xyz -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGDX9 -bool CLP(ShaderContext):: -try_cg_compile(ShaderExpansion *s, GSG *gsg) -{ - cgGetError(); - _cg_program[0] = - cgCreateProgram(gsg -> _cg_context, CG_SOURCE, s->_text.c_str(), - _cg_profile[0], vertex_shader_function_name, (const char**)NULL); - report_cg_compile_errors(s->get_name(), gsg -> _cg_context); - - cgGetError(); - _cg_program[1] = - cgCreateProgram(gsg -> _cg_context, CG_SOURCE, s->_text.c_str(), - _cg_profile[1], pixel_shader_function_name, (const char**)NULL); - report_cg_compile_errors(s->get_name(), gsg -> _cg_context); - - if ((_cg_program[SHADER_type_vert]==0)||(_cg_program[SHADER_type_frag]==0)) { - release_resources(); - return false; - } - - if (dxgsg9_cat.is_debug()) { - // DEBUG: output the generated program - const char *vertex_program; - const char *pixel_program; - - vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM); - pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); - - dxgsg9_cat.debug() << vertex_program << "\n"; - dxgsg9_cat.debug() << pixel_program << "\n"; - - // save the generated program to a file - int size; - char file_path [512]; - - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; - - _splitpath (_name.c_str ( ), drive, dir, fname, ext); - - size = strlen (vertex_program); - sprintf (file_path, "%s.vasm", fname); - save_file (size, (void *) vertex_program, file_path); - - size = strlen (pixel_program); - sprintf (file_path, "%s.pasm", fname); - save_file (size, (void *) pixel_program, file_path); - } - - // The following code is present to work around a bug in the Cg compiler. - // It does not generate correct code for shadow map lookups when using arbfp1. - // This is a particularly onerous limitation, given that arbfp1 is the only - // Cg target that works on radeons. I suspect this is an intentional - // omission on nvidia's part. The following code fetches the output listing, - // detects the error, repairs the code, and resumbits the repaired code to Cg. - if ((_cg_profile[1] == CG_PROFILE_ARBFP1) && (gsg->_supports_shadow_filter)) { - bool shadowunit[32]; - bool anyshadow = false; - memset(shadowunit, 0, sizeof(shadowunit)); - vector_string lines; - tokenize(cgGetProgramString(_cg_program[1], CG_COMPILED_PROGRAM), lines, "\n"); - // figure out which texture units contain shadow maps. - for (int lineno=0; lineno<(int)lines.size(); lineno++) { - if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) { - continue; - } - vector_string fields; - tokenize(lines[lineno], fields, ":"); - if (fields.size()!=5) { - continue; - } - vector_string words; - tokenize(trim(fields[2]), words, " "); - if (words.size()!=2) { - continue; - } - int unit = atoi(words[1].c_str()); - if ((unit < 0)||(unit >= 32)) { - continue; - } - anyshadow = true; - shadowunit[unit] = true; - } - // modify all TEX statements that use the relevant texture units. - if (anyshadow) { - for (int lineno=0; lineno<(int)lines.size(); lineno++) { - if (lines[lineno].compare(0,4,"TEX ")) { - continue; - } - vector_string fields; - tokenize(lines[lineno], fields, ","); - if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) { - continue; - } - vector_string texunitf; - tokenize(trim(fields[2]), texunitf, "[]"); - if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) { - continue; - } - int unit = atoi(texunitf[1].c_str()); - if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) { - continue; - } - lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;"; - } - string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n"; - for (int lineno=1; lineno<(int)lines.size(); lineno++) { - result += (lines[lineno] + "\n"); - } - cgDestroyProgram(_cg_program[1]); - _cg_program[1] = - cgCreateProgram(gsg -> _cg_context, CG_OBJECT, result.c_str(), - _cg_profile[1], "fshader", (const char**)NULL); - report_cg_compile_errors(s->get_name(), gsg -> _cg_context); - if (_cg_program[SHADER_type_frag]==0) { - release_resources(); - return false; - } - } - } - - bool success = true; - CGparameter parameter; - for (int progindex=0; progindex<2; progindex++) { - int nvtx = _var_spec.size(); - for (parameter = cgGetFirstLeafParameter(_cg_program[progindex],CG_PROGRAM); - parameter != 0; - parameter = cgGetNextLeafParameter(parameter)) { - CGenum vbl = cgGetParameterVariability(parameter); - if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) { - success &= compile_parameter(parameter, - cgGetParameterName(parameter), - cg_type_to_panda_type(cgGetParameterType(parameter)), - cg_dir_to_panda_dir(cgGetParameterDirection(parameter)), - (vbl == CG_VARYING), - dxgsg9_cat.get_safe_ptr()); - } - } - if ((progindex == SHADER_type_frag) && (nvtx != _var_spec.size())) { - dxgsg9_cat.error() << "Cannot use vtx parameters in an fshader\n"; - success = false; - } - } - if (!success) { - release_resources(); - return false; - } - - BOOL paramater_shadowing; - DWORD assembly_flags; - - paramater_shadowing = FALSE; - assembly_flags = 0; - - #if DEBUG_SHADER - assembly_flags |= D3DXSHADER_DEBUG; - #endif - - HRESULT hr; - - hr = cgD3D9LoadProgram(_cg_program[SHADER_type_vert], paramater_shadowing, assembly_flags); - if (FAILED (hr)) { - dxgsg9_cat.error() - << "vertex shader cgD3D9LoadProgram failed " - << D3DERRORSTRING(hr); - - CGerror error = cgGetError(); - if (error != CG_NO_ERROR) { - dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; - } - - release_resources(); - return false; - } - - hr = cgD3D9LoadProgram(_cg_program[SHADER_type_frag], paramater_shadowing, assembly_flags); - if (FAILED (hr)) { - dxgsg9_cat.error() - << "pixel shader cgD3D9LoadProgram failed " - << D3DERRORSTRING(hr); - - CGerror error = cgGetError(); - if (error != CG_NO_ERROR) { - dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; - } - - release_resources(); - return false; - } - - DBG_SH2 dxgsg9_cat.debug ( ) << "SHADER: end try_cg_compile \n"; DBG_E - - _state = true; - - return true; -} -#endif +// int save_file (int size, void *data, char *file_path) +// { +// int state; +// int file_handle; +// +// state = false; +// file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE); +// if (file_handle != -1) { +// if (_write (file_handle, data, size) == size) { +// state = true; +// } +// _close (file_handle); +// } +// +// return state; +// } +// +// if (dxgsg9_cat.is_debug()) { +// // DEBUG: output the generated program +// const char *vertex_program; +// const char *pixel_program; +// +// vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM); +// pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); +// +// dxgsg9_cat.debug() << vertex_program << "\n"; +// dxgsg9_cat.debug() << pixel_program << "\n"; +// +// // save the generated program to a file +// int size; +// char file_path [512]; +// +// char drive[_MAX_DRIVE]; +// char dir[_MAX_DIR]; +// char fname[_MAX_FNAME]; +// char ext[_MAX_EXT]; +// +// _splitpath (_name.c_str ( ), drive, dir, fname, ext); +// +// size = strlen (vertex_program); +// sprintf (file_path, "%s.vasm", fname); +// save_file (size, (void *) vertex_program, file_path); +// +// size = strlen (pixel_program); +// sprintf (file_path, "%s.pasm", fname); +// save_file (size, (void *) pixel_program, file_path); +// } //////////////////////////////////////////////////////////////////// // Function: DXShaderContext9::release_resources @@ -514,12 +177,13 @@ try_cg_compile(ShaderExpansion *s, GSG *gsg) //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: release_resources() { -#ifdef HAVE_CGDX9 - { - _cg_profile[SHADER_type_vert] = (CGprofile)0; - _cg_profile[SHADER_type_frag] = (CGprofile)0; - _cg_program[SHADER_type_vert] = (CGprogram)0; - _cg_program[SHADER_type_frag] = (CGprogram)0; +#ifdef HAVE_CG + if (_cg_context) { + cgDestroyContext(_cg_context); + _cg_context = 0; + _cg_vprogram = 0; + _cg_fprogram = 0; + _cg_parameter_map.clear(); } #endif } @@ -537,45 +201,42 @@ bind(GSG *gsg) { bool bind_state; bind_state = false; -#ifdef HAVE_CGDX9 - if (_state) { - if (gsg -> _cg_context != 0) { - DBG_SH5 dxgsg9_cat.debug ( ) << "SHADER: bind \n"; DBG_E +#ifdef HAVE_CG + if (_cg_context) { + DBG_SH5 dxgsg9_cat.debug ( ) << "SHADER: bind \n"; DBG_E + + // clear the last cached FVF to make sure the next SetFVF call goes through + + gsg -> _last_fvf = 0; - // clear the last cached FVF to make sure the next SetFVF call goes through - gsg -> _last_fvf = 0; - - // Pass in k-parameters and transform-parameters - issue_parameters(gsg, true); - - HRESULT hr; - - if (_cg_shader) { - // Bind the shaders. - bind_state = true; - hr = cgD3D9BindProgram(_cg_program[SHADER_type_vert]); - if (FAILED (hr)) { - dxgsg9_cat.error() << "cgD3D9BindProgram vertex shader failed " << D3DERRORSTRING(hr); - - CGerror error = cgGetError(); - if (error != CG_NO_ERROR) { - dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; - } - - bind_state = false; - } - hr = cgD3D9BindProgram(_cg_program[SHADER_type_frag]); - if (FAILED (hr)) { - dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr); - - CGerror error = cgGetError(); - if (error != CG_NO_ERROR) { - dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; - } - - bind_state = false; - } + // Pass in k-parameters and transform-parameters + issue_parameters(gsg, true); + + HRESULT hr; + + // Bind the shaders. + bind_state = true; + hr = cgD3D9BindProgram(_cg_vprogram); + if (FAILED (hr)) { + dxgsg9_cat.error() << "cgD3D9BindProgram vertex shader failed " << D3DERRORSTRING(hr); + + CGerror error = cgGetError(); + if (error != CG_NO_ERROR) { + dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; } + + bind_state = false; + } + hr = cgD3D9BindProgram(_cg_fprogram); + if (FAILED (hr)) { + dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr); + + CGerror error = cgGetError(); + if (error != CG_NO_ERROR) { + dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; + } + + bind_state = false; } } #endif @@ -591,8 +252,8 @@ bind(GSG *gsg) { void CLP(ShaderContext):: unbind(GSG *gsg) { -#ifdef HAVE_CGDX9 - if (_state) { +#ifdef HAVE_CG + if (_cg_context) { DBG_SH5 dxgsg9_cat.debug ( ) << "SHADER: unbind \n"; DBG_E @@ -638,12 +299,12 @@ InternalName *global_internal_name_1 = 0; void CLP(ShaderContext):: issue_parameters(GSG *gsg, bool altered) { -#ifdef HAVE_CGDX9 - if (gsg -> _cg_context != 0) { - for (int i=0; i<(int)_mat_spec.size(); i++) { - if (altered || _mat_spec[i]._trans_dependent) { - CGparameter p = (CGparameter)(_mat_spec[i]._parameter); - const LMatrix4f *val = gsg->fetch_specified_value(_mat_spec[i], altered); +#ifdef HAVE_CG + if (_cg_context) { + for (int i=0; i<(int)_expansion->_mat_spec.size(); i++) { + if (altered || _expansion->_mat_spec[i]._trans_dependent) { + CGparameter p = _cg_parameter_map[_expansion->_mat_spec[i]._id._seqno]; + const LMatrix4f *val = gsg->fetch_specified_value(_expansion->_mat_spec[i], altered); if (val) { HRESULT hr; float v [4]; @@ -658,13 +319,13 @@ issue_parameters(GSG *gsg, bool altered) #if DEBUG_SHADER // DEBUG global_data = (float *) data; - global_shader_mat_spec = &_mat_spec[i]; + global_shader_mat_spec = &_expansion->_mat_spec[i]; global_internal_name_0 = global_shader_mat_spec -> _arg [0]; global_internal_name_1 = global_shader_mat_spec -> _arg [1]; #endif - switch (_mat_spec[i]._piece) { - case SMP_whole: + switch (_expansion->_mat_spec[i]._piece) { + case ShaderExpansion::SMP_whole: // TRANSPOSE REQUIRED temp_matrix.transpose_from (*val); data = temp_matrix.get_data(); @@ -672,7 +333,7 @@ issue_parameters(GSG *gsg, bool altered) hr = cgD3D9SetUniform (p, data); DBG_SH2 - dxgsg9_cat.debug ( ) << "SMP_whole MATRIX \n" << + dxgsg9_cat.debug ( ) << "ShaderExpansion::SMP_whole MATRIX \n" << data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << @@ -681,44 +342,44 @@ issue_parameters(GSG *gsg, bool altered) break; - case SMP_transpose: + case ShaderExpansion::SMP_transpose: // NO TRANSPOSE REQUIRED hr = cgD3D9SetUniform (p, data); break; - case SMP_row0: + case ShaderExpansion::SMP_row0: hr = cgD3D9SetUniform (p, data + 0); break; - case SMP_row1: + case ShaderExpansion::SMP_row1: hr = cgD3D9SetUniform (p, data + 4); break; - case SMP_row2: + case ShaderExpansion::SMP_row2: hr = cgD3D9SetUniform (p, data + 8); break; - case SMP_row3: + case ShaderExpansion::SMP_row3: hr = cgD3D9SetUniform (p, data + 12); break; - case SMP_col0: + case ShaderExpansion::SMP_col0: v[0] = data[0]; v[1] = data[4]; v[2] = data[8]; v[3] = data[12]; hr = cgD3D9SetUniform (p, v); break; - case SMP_col1: + case ShaderExpansion::SMP_col1: v[0] = data[1]; v[1] = data[5]; v[2] = data[9]; v[3] = data[13]; hr = cgD3D9SetUniform (p, v); break; - case SMP_col2: + case ShaderExpansion::SMP_col2: v[0] = data[2]; v[1] = data[6]; v[2] = data[10]; v[3] = data[14]; hr = cgD3D9SetUniform (p, v); break; - case SMP_col3: + case ShaderExpansion::SMP_col3: v[0] = data[3]; v[1] = data[7]; v[2] = data[11]; v[3] = data[15]; hr = cgD3D9SetUniform (p, v); break; default: dxgsg9_cat.error() - << "issue_parameters ( ) SMP parameter type not implemented " << _mat_spec[i]._piece << "\n"; + << "issue_parameters ( ) SMP parameter type not implemented " << _expansion->_mat_spec[i]._piece << "\n"; break; } @@ -726,14 +387,14 @@ issue_parameters(GSG *gsg, bool altered) string name = "unnamed"; - if (_mat_spec[i]._arg [0]) { - name = _mat_spec[i]._arg [0] -> get_basename ( ); + if (_expansion->_mat_spec[i]._arg [0]) { + name = _expansion->_mat_spec[i]._arg [0] -> get_basename ( ); } dxgsg9_cat.error() << "NAME " << name << "\n" << "MAT TYPE " - << _mat_spec[i]._piece + << _expansion->_mat_spec[i]._piece << " cgD3D9SetUniform failed " << D3DERRORSTRING(hr); @@ -757,14 +418,9 @@ issue_parameters(GSG *gsg, bool altered) void CLP(ShaderContext):: disable_shader_vertex_arrays(GSG *gsg) { -#ifdef HAVE_CGDX9 - if (gsg -> _cg_context) { - for (int i=0; i<(int)_var_spec.size(); i++) { - CGparameter p = (CGparameter)(_var_spec[i]._parameter); - - // DO NOTHING, CURRENTLY USING ONLY ONE STREAM SOURCE - - } +#ifdef HAVE_CG + if (_cg_context) { + // DO NOTHING, CURRENTLY USING ONLY ONE STREAM SOURCE } #endif } @@ -790,8 +446,8 @@ void CLP(ShaderContext):: update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_vertex_arrays(gsg); -#ifdef HAVE_CGDX9 - if (gsg -> _cg_context) { +#ifdef HAVE_CG + if (_cg_context) { #ifdef SUPPORT_IMMEDIATE_MODE /* @@ -806,7 +462,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) const GeomVertexArrayDataPipelineReader *array_reader; Geom::NumericType numeric_type; int start, stride, num_values; - int nvarying = _var_spec.size(); + int nvarying = _expansion->_var_spec.size(); int stream_index; VertexElementArray *vertex_element_array; @@ -822,9 +478,9 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) #endif for (int i=0; i_var_spec[i]._id._seqno]; + InternalName *name = _expansion->_var_spec[i]._name; + int texslot = _expansion->_var_spec[i]._append_uv; if (texslot >= 0) { const Geom::ActiveTextureStages &active_stages = gsg->_state._texture->get_on_stages(); @@ -982,8 +638,8 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) state = vertex_element_array -> add_end_vertex_element ( ); if (state) { - if (_cg_shader) { - if (cgD3D9ValidateVertexDeclaration (_cg_program [SHADER_type_vert], + if (_cg_context) { + if (cgD3D9ValidateVertexDeclaration (_cg_vprogram, vertex_element_array -> vertex_element_array) == CG_TRUE) { dxgsg9_cat.debug() << "|||||cgD3D9ValidateVertexDeclaration succeeded\n"; } @@ -1013,7 +669,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) } } } -#endif // HAVE_CGDX9 +#endif // HAVE_CG } //////////////////////////////////////////////////////////////////// @@ -1024,10 +680,10 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) void CLP(ShaderContext):: disable_shader_texture_bindings(GSG *gsg) { -#ifdef HAVE_CGDX9 - if (gsg -> _cg_context) { - for (int i=0; i<(int)_tex_spec.size(); i++) { - CGparameter p = (CGparameter)(_tex_spec[i]._parameter); +#ifdef HAVE_CG + if (_cg_context) { + for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) { + CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno]; int texunit = cgGetParameterResourceIndex(p); HRESULT hr; @@ -1061,40 +717,40 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_texture_bindings(gsg); -#ifdef HAVE_CGDX9 - if (gsg -> _cg_context) { - for (int i=0; i<(int)_tex_spec.size(); i++) { - CGparameter p = (CGparameter)(_tex_spec[i]._parameter); +#ifdef HAVE_CG + if (_cg_context) { + for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) { + CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno]; Texture *tex = 0; - InternalName *id = _tex_spec[i]._name; + InternalName *id = _expansion->_tex_spec[i]._name; if (id != 0) { const ShaderInput *input = gsg->_target._shader->get_shader_input(id); tex = input->get_texture(); } else { - if (_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) { + if (_expansion->_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) { continue; } - TextureStage *stage = gsg->_target._texture->get_on_stage(_tex_spec[i]._stage); + TextureStage *stage = gsg->_target._texture->get_on_stage(_expansion->_tex_spec[i]._stage); tex = gsg->_target._texture->get_on_texture(stage); } - if (_tex_spec[i]._suffix != 0) { + if (_expansion->_tex_spec[i]._suffix != 0) { // The suffix feature is inefficient. It is a temporary hack. if (tex == 0) { continue; } - tex = tex->load_related(_tex_spec[i]._suffix); + tex = tex->load_related(_expansion->_tex_spec[i]._suffix); } - if ((tex == 0) || (tex->get_texture_type() != _tex_spec[i]._desired_type)) { + if ((tex == 0) || (tex->get_texture_type() != _expansion->_tex_spec[i]._desired_type)) { continue; } TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg); -// TextureContext *tc = tex->prepare_now(gsg->get_prepared_objects(), gsg); + // TextureContext *tc = tex->prepare_now(gsg->get_prepared_objects(), gsg); if (tc == (TextureContext*)NULL) { continue; } - + int texunit = cgGetParameterResourceIndex(p); - + gsg->apply_texture(texunit, tc); } } diff --git a/panda/src/dxgsg9/dxShaderContext9.h b/panda/src/dxgsg9/dxShaderContext9.h index fe49012c6e..e4a7d0d8a0 100644 --- a/panda/src/dxgsg9/dxShaderContext9.h +++ b/panda/src/dxgsg9/dxShaderContext9.h @@ -21,11 +21,6 @@ #include "dtool_config.h" #include "pandabase.h" -#ifdef HAVE_CGDX9 -#include "Cg/cg.h" -#include "Cg/cgGL.h" -#include "Cg/cgD3D9.h" -#endif #include "string_utils.h" #include "internalName.h" #include "shaderExpansion.h" @@ -39,47 +34,49 @@ class VertexElementArray; class CLP(GraphicsStateGuardian); -typedef struct -{ - int vertex_shader; - int total_constant_descriptions; - D3DXCONSTANT_DESC *constant_description_array; -} -DX_PARAMETER; - -typedef struct -{ - int state; - union - { - DIRECT_3D_VERTEX_SHADER direct_3d_vertex_shader; - DIRECT_3D_PIXEL_SHADER direct_3d_pixel_shader; - }; - LPD3DXCONSTANTTABLE constant_table; - D3DXCONSTANTTABLE_DESC constant_table_description; - - int total_semantics; - D3DXSEMANTIC *semantic_array; -} -DIRECT_3D_SHADER; +// Caution: adding HLSL support is going to be tricky, as the parsing needs +// to be done in the cull thread, which cannot use the DX API. - Josh +// +// +// typedef struct +// { +// int vertex_shader; +// int total_constant_descriptions; +// D3DXCONSTANT_DESC *constant_description_array; +// } +// DX_PARAMETER; +// +// typedef struct +// { +// int state; +// union +// { +// DIRECT_3D_VERTEX_SHADER direct_3d_vertex_shader; +// DIRECT_3D_PIXEL_SHADER direct_3d_pixel_shader; +// }; +// LPD3DXCONSTANTTABLE constant_table; +// D3DXCONSTANTTABLE_DESC constant_table_description; +// +// int total_semantics; +// D3DXSEMANTIC *semantic_array; +// } +// DIRECT_3D_SHADER; //////////////////////////////////////////////////////////////////// // Class : DXShaderContext9 // Description : xyz //////////////////////////////////////////////////////////////////// -typedef CLP(GraphicsStateGuardian) GSG; - class EXPCL_PANDADX CLP(ShaderContext): public ShaderContext { public: - + typedef CLP(GraphicsStateGuardian) GSG; + CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg); ~CLP(ShaderContext)(); INLINE bool valid(GSG *gsg); bool bind(GSG *gsg); void unbind(GSG *gsg); - void issue_parameters(GSG *gsg, bool altered); void issue_transform(GSG *gsg); void disable_shader_vertex_arrays(GSG *gsg); @@ -87,69 +84,21 @@ public: void disable_shader_texture_bindings(GSG *gsg); void update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg); - int _vertex_size; class VertexElementArray *_vertex_element_array; // FOR DEBUGGING + int _vertex_size; string _name; - - bool _state; - bool _cg_shader; - bool _transpose_matrix; - + private: -#ifdef HAVE_CGDX9 - struct ShaderAutoBind { - CGparameter parameter; - int value; - DX_PARAMETER *dx_parameter; - }; - struct ShaderArgBind { - CGparameter parameter; - PT(InternalName) name; - DX_PARAMETER *dx_parameter; - }; - struct ShaderTexBind { - CGparameter parameter; - PT(InternalName) name; - int stage; - int desiredtype; - PT(InternalName) suffix; - DX_PARAMETER *dx_parameter; - }; - struct ShaderTransBind { - CGparameter parameter; - PT(InternalName) src_name; - PT(InternalName) rel_name; - int trans_piece; - DX_PARAMETER *dx_parameter; - }; - struct ShaderVarying { - CGparameter parameter; - PT(InternalName) name; - int append_uv; - DX_PARAMETER *dx_parameter; - }; - -// CGcontext _cg_context; - CGprofile _cg_profile[2]; - CGprogram _cg_program[2]; - - void report_cg_compile_errors(const string &file, CGcontext ctx); - - bool try_cg_compile(ShaderExpansion *s, GSG *gsg); - void suggest_cg_profile(const string &vpro, const string &fpro); - CGprofile parse_cg_profile(const string &id, bool vertex); +#ifdef HAVE_CG + CGcontext _cg_context; + CGprogram _cg_vprogram; + CGprogram _cg_fprogram; + pvector _cg_parameter_map; #endif -public: - - DIRECT_3D_SHADER _direct_3d_vertex_shader; - DIRECT_3D_SHADER _direct_3d_pixel_shader; - int _total_dx_parameters; - DX_PARAMETER *_dx_parameter_array; - private: void release_resources(void); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 92995818c2..fe196fe796 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -50,6 +50,10 @@ #include "indirectLess.h" #include "pStatTimer.h" +#ifdef HAVE_CG +#include "Cg/cgGL.h" +#endif + #include #define DEBUG_BUFFERS false @@ -669,10 +673,14 @@ reset() { } } -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) && cgGLIsProfileSupported(CG_PROFILE_ARBVP1)) { _supports_basic_shaders = true; + _shader_caps._active_vprofile = (int)cgGLGetLatestProfile(CG_GL_VERTEX); + _shader_caps._active_fprofile = (int)cgGLGetLatestProfile(CG_GL_FRAGMENT); + _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40; + _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40; } #endif @@ -1076,7 +1084,7 @@ reset() { void gl_set_stencil_functions (StencilRenderStates *stencil_render_states); gl_set_stencil_functions (_stencil_render_states); -#ifdef HAVE_CGGL +#ifdef HAVE_CG typedef struct { @@ -3357,7 +3365,7 @@ do_issue_shader() { ShaderExpansion *expansion = _target_rs->get_shader_expansion(); if (expansion == 0) { if (_target._shader->get_shader() != 0) { - expansion = _target._shader->get_shader()->macroexpand(_target_rs); + expansion = _target._shader->get_shader()->macroexpand(_target_rs, _shader_caps); // I am casting away the const-ness of this pointer, because // the 'shader-expansion' field is just a cache. ((RenderState *)((const RenderState*)_target_rs))-> diff --git a/panda/src/glstuff/glShaderContext_src.I b/panda/src/glstuff/glShaderContext_src.I index 129175f91c..60c4546b54 100755 --- a/panda/src/glstuff/glShaderContext_src.I +++ b/panda/src/glstuff/glShaderContext_src.I @@ -27,8 +27,8 @@ //////////////////////////////////////////////////////////////////// INLINE bool CLP(ShaderContext):: valid() { -#ifdef HAVE_CGGL - if (_state && _cg_context) return true; +#ifdef HAVE_CG + if (_cg_context) return true; #endif return false; } diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 5191f4be64..56793f689e 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -16,49 +16,14 @@ // //////////////////////////////////////////////////////////////////// +#ifdef HAVE_CG +#include "Cg/cgGL.h" +#endif + #define DEBUG_GL_SHADER 0 TypeHandle CLP(ShaderContext)::_type_handle; -#ifdef HAVE_CGGL -//////////////////////////////////////////////////////////////////// -// Function: cg_type_to_panda_type -// Access: Public, Static -// Description: convert a cg shader-arg type to a panda shader-arg type. -//////////////////////////////////////////////////////////////////// -static ShaderContext::ShaderArgType -cg_type_to_panda_type(CGtype n) { - switch (n) { - case CG_FLOAT1: return ShaderContext::SAT_float1; - case CG_FLOAT2: return ShaderContext::SAT_float2; - case CG_FLOAT3: return ShaderContext::SAT_float3; - case CG_FLOAT4: return ShaderContext::SAT_float4; - case CG_FLOAT4x4: return ShaderContext::SAT_float4x4; - case CG_SAMPLER1D: return ShaderContext::SAT_sampler1d; - case CG_SAMPLER2D: return ShaderContext::SAT_sampler2d; - case CG_SAMPLER3D: return ShaderContext::SAT_sampler3d; - case CG_SAMPLERCUBE: return ShaderContext::SAT_samplercube; - default: return ShaderContext::SAT_unknown; - } -} -#endif // HAVE_CGGL - -#ifdef HAVE_CGGL -//////////////////////////////////////////////////////////////////// -// Function: cg_dir_to_panda_dir -// Access: Public, Static -// Description: convert a cg shader-arg type to a panda shader-arg type. -//////////////////////////////////////////////////////////////////// -static ShaderContext::ShaderArgDir -cg_dir_to_panda_dir(CGenum n) { - switch (n) { - case CG_IN: return ShaderContext::SAD_in; - case CG_OUT: return ShaderContext::SAD_out; - case CG_INOUT: return ShaderContext::SAD_inout; - default: return ShaderContext::SAD_unknown; - } -} -#endif // HAVE_CGGL //////////////////////////////////////////////////////////////////// // Function: GLShaderContext::Constructor @@ -67,311 +32,34 @@ cg_dir_to_panda_dir(CGenum n) { //////////////////////////////////////////////////////////////////// CLP(ShaderContext):: CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) { - string header; - s->parse_init(); - s->parse_line(header, true, true); +#ifdef HAVE_CG + if (s->get_header() == "//Cg") { + + // Ask the shader expansion to compile itself for us and + // to give us the resulting Cg program objects. - _state = false; - -#ifdef HAVE_CGGL - _cg_context = (CGcontext)0; - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - _cg_program[SHADER_type_vert] = (CGprogram)0; - _cg_program[SHADER_type_frag] = (CGprogram)0; - _cg_program[2] = (CGprogram)0; - - if (header == "//Cg") { - // Create the Cg context. - _cg_context = cgCreateContext(); - if (_cg_context == 0) { - release_resources(); - GLCAT.error() << "Cg not supported by this video card.\n"; + if (!s->cg_compile_for(gsg->_shader_caps, + _cg_context, + _cg_vprogram, + _cg_fprogram, + _cg_parameter_map)) { return; } - - // Parse any directives in the source. - string directive; - while (!s->parse_eof()) { - s->parse_line(directive, true, true); - vector_string pieces; - tokenize(directive, pieces, " \t"); - if ((pieces.size()==4)&&(pieces[0]=="//Cg")&&(pieces[1]=="profile")) { - suggest_cg_profile(pieces[2], pieces[3]); - } - } - - // Select a profile if no preferred profile specified in the source. - if (_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN) { - _cg_profile[SHADER_type_vert] = cgGLGetLatestProfile(CG_GL_VERTEX); - } - if (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN) { - _cg_profile[SHADER_type_frag] = cgGLGetLatestProfile(CG_GL_FRAGMENT); - } - - // If we still haven't chosen a profile, give up. - if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { + + // Load the program. + + cgGLLoadProgram(_cg_vprogram); + CGerror verror = cgGetError(); + cgGLLoadProgram(_cg_fprogram); + CGerror ferror = cgGetError(); + if ((verror != CG_NO_ERROR)||(ferror != CG_NO_ERROR)) { + GLCAT.error() << "Could not load Cg shader:" << s->get_name() << "\n"; release_resources(); - GLCAT.error() << "Cg not supported by this video card.\n"; - return; } - - // Compile the program. - try_cg_compile(s, gsg); - return; } #endif - - GLCAT.error() << s->get_name() << ": unrecognized shader language " << header << "\n"; } -#ifdef HAVE_CGGL -//////////////////////////////////////////////////////////////////// -// Function: Shader::report_cg_compile_errors -// Access: Public, Static -// Description: Used only after a Cg compile command, to print -// out any error messages that may have occurred -// during the Cg shader compilation. The 'file' -// is the name of the file containing the Cg code. -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -report_cg_compile_errors(const string &file, CGcontext ctx) -{ - CGerror err = cgGetError(); - if (err != CG_NO_ERROR) { - if (err == CG_COMPILER_ERROR) { - string listing = cgGetLastListing(ctx); - vector_string errlines; - tokenize(listing, errlines, "\n"); - for (int i=0; i<(int)errlines.size(); i++) { - string line = trim(errlines[i]); - if (line != "") { - GLCAT.error() << file << " " << errlines[i] << "\n"; - } - } - } else { - GLCAT.error() << file << ": " << cgGetErrorString(err) << "\n"; - } - } -} -#endif // HAVE_CGGL - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::suggest_cg_profile -// Access: Private -// Description: xyz -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGGL -void CLP(ShaderContext):: -suggest_cg_profile(const string &vpro, const string &fpro) -{ - // If a good profile has already been suggested, ignore suggestion. - if ((_cg_profile[SHADER_type_vert] != CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] != CG_PROFILE_UNKNOWN)) { - return; - } - - // Parse the suggestion. If not parseable, print error and ignore. - _cg_profile[SHADER_type_vert] = parse_cg_profile(vpro, true); - _cg_profile[SHADER_type_frag] = parse_cg_profile(fpro, false); - if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| - (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { - GLCAT.error() << "Cg: unrecognized profile name: " << vpro << " " << fpro << "\n"; - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - return; - } - - // If the suggestion is parseable, but not supported, ignore silently. - if ((!cgGLIsProfileSupported(_cg_profile[SHADER_type_vert]))|| - (!cgGLIsProfileSupported(_cg_profile[SHADER_type_frag]))) { - _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; - _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; - return; - } -} -#endif - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::parse_cg_profile -// Access: Private -// Description: xyz -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGGL -CGprofile CLP(ShaderContext):: -parse_cg_profile(const string &id, bool vertex) -{ - int nvprofiles = 4; - int nfprofiles = 4; - CGprofile vprofiles[] = { CG_PROFILE_ARBVP1, CG_PROFILE_VP20, CG_PROFILE_VP30, CG_PROFILE_VP40 }; - CGprofile fprofiles[] = { CG_PROFILE_ARBFP1, CG_PROFILE_FP20, CG_PROFILE_FP30, CG_PROFILE_FP40 }; - if (vertex) { - for (int i=0; i_text.c_str(), - _cg_profile[0], "vshader", (const char**)NULL); - report_cg_compile_errors(s->get_name(), _cg_context); - - cgGetError(); - _cg_program[1] = - cgCreateProgram(_cg_context, CG_SOURCE, s->_text.c_str(), - _cg_profile[1], "fshader", (const char**)NULL); - report_cg_compile_errors(s->get_name(), _cg_context); - - if ((_cg_program[SHADER_type_vert]==0)||(_cg_program[SHADER_type_frag]==0)) { - release_resources(); - return false; - } - - bool success = true; - CGparameter parameter; - for (int progindex=0; progindex<2; progindex++) { - int nvtx = _var_spec.size(); - for (parameter = cgGetFirstLeafParameter(_cg_program[progindex],CG_PROGRAM); - parameter != 0; - parameter = cgGetNextLeafParameter(parameter)) { - CGenum vbl = cgGetParameterVariability(parameter); - if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) { - success &= compile_parameter(parameter, - cgGetParameterName(parameter), - cg_type_to_panda_type(cgGetParameterType(parameter)), - cg_dir_to_panda_dir(cgGetParameterDirection(parameter)), - (vbl == CG_VARYING), - GLCAT.get_safe_ptr()); - } - } - if ((progindex == SHADER_type_frag) && (nvtx != _var_spec.size())) { - GLCAT.error() << "Cannot use vtx parameters in an fshader\n"; - success = false; - } - } - if (!success) { - release_resources(); - return false; - } - - // DEBUG: output the generated program - if (GLCAT.is_debug()) { - const char *vertex_program; - const char *pixel_program; - - vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM); - pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); - - GLCAT.debug() << vertex_program << "\n"; - GLCAT.debug() << pixel_program << "\n"; - } - - // The following code is present to work around a bug in the Cg compiler. - // It does not generate correct code for shadow map lookups when using arbfp1. - // This is a particularly onerous limitation, given that arbfp1 is the only - // Cg target that works on radeons. I suspect this is an intentional - // omission on nvidia's part. The following code fetches the output listing, - // detects the error, repairs the code, and resumbits the repaired code to Cg. - if ((_cg_profile[1] == CG_PROFILE_ARBFP1) && (gsg->_supports_shadow_filter)) { - bool shadowunit[32]; - bool anyshadow = false; - memset(shadowunit, 0, sizeof(shadowunit)); - vector_string lines; - tokenize(cgGetProgramString(_cg_program[SHADER_type_frag], - CG_COMPILED_PROGRAM), lines, "\n"); - // figure out which texture units contain shadow maps. - for (int lineno=0; lineno<(int)lines.size(); lineno++) { - if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) { - continue; - } - vector_string fields; - tokenize(lines[lineno], fields, ":"); - if (fields.size()!=5) { - continue; - } - vector_string words; - tokenize(trim(fields[2]), words, " "); - if (words.size()!=2) { - continue; - } - int unit = atoi(words[1].c_str()); - if ((unit < 0)||(unit >= 32)) { - continue; - } - anyshadow = true; - shadowunit[unit] = true; - } - // modify all TEX statements that use the relevant texture units. - if (anyshadow) { - for (int lineno=0; lineno<(int)lines.size(); lineno++) { - if (lines[lineno].compare(0,4,"TEX ")) { - continue; - } - vector_string fields; - tokenize(lines[lineno], fields, ","); - if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) { - continue; - } - vector_string texunitf; - tokenize(trim(fields[2]), texunitf, "[]"); - if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) { - continue; - } - int unit = atoi(texunitf[1].c_str()); - if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) { - continue; - } - lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;"; - } - string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n"; - for (int lineno=1; lineno<(int)lines.size(); lineno++) { - result += (lines[lineno] + "\n"); - } - _cg_program[2] = _cg_program[SHADER_type_frag]; - _cg_program[SHADER_type_frag] = - cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(), - _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL); - report_cg_compile_errors(s->get_name(), _cg_context); - if (_cg_program[SHADER_type_frag]==0) { - release_resources(); - return false; - } - } - } - - cgGLLoadProgram(_cg_program[SHADER_type_vert]); - report_cg_compile_errors(s->get_name(), _cg_context); - cgGLLoadProgram(_cg_program[SHADER_type_frag]); - report_cg_compile_errors(s->get_name(), _cg_context); - - _state = true; - - return true; -} -#endif - //////////////////////////////////////////////////////////////////// // Function: GLShaderContext::Destructor // Access: Public @@ -390,15 +78,13 @@ CLP(ShaderContext):: //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: release_resources() { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context) { cgDestroyContext(_cg_context); - _cg_context = (CGcontext)0; - _cg_profile[SHADER_type_vert] = (CGprofile)0; - _cg_profile[SHADER_type_frag] = (CGprofile)0; - _cg_program[SHADER_type_vert] = (CGprogram)0; - _cg_program[SHADER_type_frag] = (CGprogram)0; - _cg_program[2] = (CGprogram)0; + _cg_context = 0; + _cg_vprogram = 0; + _cg_fprogram = 0; + _cg_parameter_map.clear(); } #endif } @@ -412,17 +98,17 @@ release_resources() { //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: bind(GSG *gsg) { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context != 0) { // Pass in k-parameters and transform-parameters issue_parameters(gsg, true); // Bind the shaders. - cgGLEnableProfile(_cg_profile[SHADER_type_vert]); - cgGLBindProgram(_cg_program[SHADER_type_vert]); - cgGLEnableProfile(_cg_profile[SHADER_type_frag]); - cgGLBindProgram(_cg_program[SHADER_type_frag]); + cgGLEnableProfile(cgGetProgramProfile(_cg_vprogram)); + cgGLBindProgram(_cg_vprogram); + cgGLEnableProfile(cgGetProgramProfile(_cg_fprogram)); + cgGLBindProgram(_cg_fprogram); } #endif } @@ -434,10 +120,10 @@ bind(GSG *gsg) { //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: unbind() { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context != 0) { - cgGLDisableProfile(_cg_profile[SHADER_type_vert]); - cgGLDisableProfile(_cg_profile[SHADER_type_frag]); + cgGLDisableProfile(cgGetProgramProfile(_cg_vprogram)); + cgGLDisableProfile(cgGetProgramProfile(_cg_fprogram)); } #endif } @@ -459,28 +145,28 @@ unbind() { //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: issue_parameters(GSG *gsg, bool altered) { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context == 0) { return; } - for (int i=0; i<(int)_mat_spec.size(); i++) { - if (altered || _mat_spec[i]._trans_dependent) { - CGparameter p = (CGparameter)(_mat_spec[i]._parameter); - const LMatrix4f *val = gsg->fetch_specified_value(_mat_spec[i], altered); + for (int i=0; i<(int)_expansion->_mat_spec.size(); i++) { + if (altered || _expansion->_mat_spec[i]._trans_dependent) { + CGparameter p = _cg_parameter_map[_expansion->_mat_spec[i]._id._seqno]; + const LMatrix4f *val = gsg->fetch_specified_value(_expansion->_mat_spec[i], altered); if (val) { const float *data = val->get_data(); - switch (_mat_spec[i]._piece) { - case SMP_whole: cgGLSetMatrixParameterfc(p, data); break; - case SMP_transpose: cgGLSetMatrixParameterfr(p, data); break; - case SMP_row0: cgGLSetParameter4fv(p, data+ 0); break; - case SMP_row1: cgGLSetParameter4fv(p, data+ 4); break; - case SMP_row2: cgGLSetParameter4fv(p, data+ 8); break; - case SMP_row3: cgGLSetParameter4fv(p, data+12); break; - case SMP_col0: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); break; - case SMP_col1: cgGLSetParameter4f(p, data[1], data[5], data[ 9], data[13]); break; - case SMP_col2: cgGLSetParameter4f(p, data[2], data[6], data[10], data[14]); break; - case SMP_col3: cgGLSetParameter4f(p, data[3], data[7], data[11], data[15]); break; + switch (_expansion->_mat_spec[i]._piece) { + case ShaderExpansion::SMP_whole: cgGLSetMatrixParameterfc(p, data); break; + case ShaderExpansion::SMP_transpose: cgGLSetMatrixParameterfr(p, data); break; + case ShaderExpansion::SMP_row0: cgGLSetParameter4fv(p, data+ 0); break; + case ShaderExpansion::SMP_row1: cgGLSetParameter4fv(p, data+ 4); break; + case ShaderExpansion::SMP_row2: cgGLSetParameter4fv(p, data+ 8); break; + case ShaderExpansion::SMP_row3: cgGLSetParameter4fv(p, data+12); break; + case ShaderExpansion::SMP_col0: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); break; + case ShaderExpansion::SMP_col1: cgGLSetParameter4f(p, data[1], data[5], data[ 9], data[13]); break; + case ShaderExpansion::SMP_col2: cgGLSetParameter4f(p, data[2], data[6], data[10], data[14]); break; + case ShaderExpansion::SMP_col3: cgGLSetParameter4f(p, data[3], data[7], data[11], data[15]); break; } } } @@ -495,13 +181,13 @@ issue_parameters(GSG *gsg, bool altered) { //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: disable_shader_vertex_arrays(GSG *gsg) { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context == 0) { return; } - for (int i=0; i<(int)_var_spec.size(); i++) { - CGparameter p = (CGparameter)(_var_spec[i]._parameter); + for (int i=0; i<(int)_expansion->_var_spec.size(); i++) { + CGparameter p = _cg_parameter_map[_expansion->_var_spec[i]._id._seqno]; cgGLDisableClientState(p); } #endif @@ -521,7 +207,7 @@ disable_shader_vertex_arrays(GSG *gsg) { void CLP(ShaderContext):: update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_vertex_arrays(gsg); -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context == 0) { return; } @@ -535,11 +221,11 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { const GeomVertexArrayDataPipelineReader *array_reader; Geom::NumericType numeric_type; int start, stride, num_values; - int nvarying = _var_spec.size(); + int nvarying = _expansion->_var_spec.size(); for (int i=0; i_var_spec[i]._id._seqno]; + InternalName *name = _expansion->_var_spec[i]._name; + int texslot = _expansion->_var_spec[i]._append_uv; if (texslot >= 0) { const Geom::ActiveTextureStages &active_stages = gsg->_state._texture->get_on_stages(); @@ -566,7 +252,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { } } } -#endif // HAVE_CGGL +#endif // HAVE_CG } //////////////////////////////////////////////////////////////////// @@ -576,13 +262,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: disable_shader_texture_bindings(GSG *gsg) { -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context == 0) { return; } - for (int i=0; i<(int)_tex_spec.size(); i++) { - CGparameter p = (CGparameter)(_tex_spec[i]._parameter); + for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) { + CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno]; int texunit = cgGetParameterResourceIndex(p); gsg->_glActiveTexture(GL_TEXTURE0 + texunit); GLP(Disable)(GL_TEXTURE_1D); @@ -613,33 +299,33 @@ disable_shader_texture_bindings(GSG *gsg) { void CLP(ShaderContext):: update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_texture_bindings(gsg); -#ifdef HAVE_CGGL +#ifdef HAVE_CG if (_cg_context == 0) { return; } - for (int i=0; i<(int)_tex_spec.size(); i++) { - CGparameter p = (CGparameter)(_tex_spec[i]._parameter); + for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) { + CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno]; Texture *tex = 0; - InternalName *id = _tex_spec[i]._name; + InternalName *id = _expansion->_tex_spec[i]._name; if (id != 0) { const ShaderInput *input = gsg->_target._shader->get_shader_input(id); tex = input->get_texture(); } else { - if (_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) { + if (_expansion->_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) { continue; } - TextureStage *stage = gsg->_target._texture->get_on_stage(_tex_spec[i]._stage); + TextureStage *stage = gsg->_target._texture->get_on_stage(_expansion->_tex_spec[i]._stage); tex = gsg->_target._texture->get_on_texture(stage); } - if (_tex_spec[i]._suffix != 0) { + if (_expansion->_tex_spec[i]._suffix != 0) { // The suffix feature is inefficient. It is a temporary hack. if (tex == 0) { continue; } - tex = tex->load_related(_tex_spec[i]._suffix); + tex = tex->load_related(_expansion->_tex_spec[i]._suffix); } - if ((tex == 0) || (tex->get_texture_type() != _tex_spec[i]._desired_type)) { + if ((tex == 0) || (tex->get_texture_type() != _expansion->_tex_spec[i]._desired_type)) { continue; } TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg); diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 806d2a3fc7..c98a641ef8 100755 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -17,9 +17,6 @@ //////////////////////////////////////////////////////////////////// #include "pandabase.h" -#ifdef HAVE_CGGL -#include "Cg/cgGL.h" -#endif #include "string_utils.h" #include "internalName.h" #include "shaderExpansion.h" @@ -49,23 +46,18 @@ public: void update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg); void disable_shader_texture_bindings(GSG *gsg); void update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg); - bool _state; private: -#ifdef HAVE_CGGL +#ifdef HAVE_CG CGcontext _cg_context; - CGprofile _cg_profile[2]; - CGprogram _cg_program[3]; - - void report_cg_compile_errors(const string &file, CGcontext ctx); - bool try_cg_compile(ShaderExpansion *s, GSG *gsg); - void suggest_cg_profile(const string &vpro, const string &fpro); - CGprofile parse_cg_profile(const string &id, bool vertex); + CGprogram _cg_vprogram; + CGprogram _cg_fprogram; + pvector _cg_parameter_map; #endif - - void release_resources(void); + void release_resources(void); + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index b7fb1657af..096032ab02 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -1,7 +1,7 @@ #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ dtoolutil:c dtoolbase:c dtool:m prc:c //#define OSX_SYS_LIBS mx -#define USE_PACKAGES zlib +#define USE_PACKAGES zlib cg #begin lib_target #define TARGET gobj diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index d0663c45fd..48c41bbae5 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -88,7 +88,7 @@ PreparedGraphicsObjects:: sci != _prepared_shaders.end(); ++sci) { ShaderContext *sc = (*sci); - sc->_shader_expansion->clear_prepared(this); + sc->_expansion->clear_prepared(this); } _prepared_shaders.clear(); @@ -460,12 +460,12 @@ void PreparedGraphicsObjects:: release_shader(ShaderContext *sc) { ReMutexHolder holder(_lock); - sc->_shader_expansion->clear_prepared(this); + sc->_expansion->clear_prepared(this); // We have to set the Shader pointer to NULL at this point, since // the Shader itself might destruct at any time after it has been // released. - sc->_shader_expansion = (ShaderExpansion *)NULL; + sc->_expansion = (ShaderExpansion *)NULL; bool removed = (_prepared_shaders.erase(sc) != 0); nassertv(removed); @@ -492,8 +492,8 @@ release_all_shaders() { sci != _prepared_shaders.end(); ++sci) { ShaderContext *sc = (*sci); - sc->_shader_expansion->clear_prepared(this); - sc->_shader_expansion = (ShaderExpansion *)NULL; + sc->_expansion->clear_prepared(this); + sc->_expansion = (ShaderExpansion *)NULL; _released_shaders.insert(sc); } diff --git a/panda/src/gobj/shaderContext.I b/panda/src/gobj/shaderContext.I index 46010f702a..0cc4a56c0e 100755 --- a/panda/src/gobj/shaderContext.I +++ b/panda/src/gobj/shaderContext.I @@ -23,7 +23,7 @@ //////////////////////////////////////////////////////////////////// INLINE ShaderContext:: ShaderContext(ShaderExpansion *se) : - _shader_expansion(se) + _expansion(se) { } diff --git a/panda/src/gobj/shaderContext.cxx b/panda/src/gobj/shaderContext.cxx index 12661289f2..a48e6f1dd7 100755 --- a/panda/src/gobj/shaderContext.cxx +++ b/panda/src/gobj/shaderContext.cxx @@ -22,678 +22,3 @@ TypeHandle ShaderContext::_type_handle; -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_report_error -// Access: Public -// Description: Generate an error message including a description -// of the specified parameter. -//////////////////////////////////////////////////////////////////// -void ShaderContext:: -cp_report_error(ShaderArgInfo &p, const string &msg) -{ - string vstr; - if (p._varying) vstr = "varying "; - else vstr = "uniform "; - - string dstr = "unknown "; - if (p._direction == SAD_in) dstr = "in "; - if (p._direction == SAD_out) dstr = "out "; - if (p._direction == SAD_inout) dstr = "inout "; - - string tstr = "invalid "; - switch (p._type) { - case SAT_float1: tstr = "float1 "; break; - case SAT_float2: tstr = "float2 "; break; - case SAT_float3: tstr = "float3 "; break; - case SAT_float4: tstr = "float4 "; break; - case SAT_float4x4: tstr = "float4x4 "; break; - case SAT_sampler1d: tstr = "sampler1d "; break; - case SAT_sampler2d: tstr = "sampler2d "; break; - case SAT_sampler3d: tstr = "sampler3d "; break; - case SAT_samplercube: tstr = "samplercube "; break; - case SAT_unknown: tstr = "unknown "; break; - } - - string fn = _shader_expansion->get_name(); - p._cat->error() << fn << ": " << msg << " (" << - vstr << dstr << tstr << p._name << ")\n"; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_words -// Access: Public, Static -// Description: Make sure the provided parameter contains -// the specified number of words. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_words(ShaderArgInfo &p, int len) -{ - vector_string words; - tokenize(p._name, words, "_"); - if ((int)words.size() != len) { - cp_report_error(p, "parameter name has wrong number of words"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_in -// Access: Public, Static -// Description: Make sure the provided parameter has the -// 'in' direction. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_in(ShaderArgInfo &p) -{ - if (p._direction != SAD_in) { - cp_report_error(p, "parameter should be declared 'in'"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_varying -// Access: Public, Static -// Description: Make sure the provided parameter has the -// correct variance. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_varying(ShaderArgInfo &p) -{ - if (!p._varying) { - cp_report_error(p, "parameter should be declared 'varying'"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_uniform -// Access: Public, Static -// Description: Make sure the provided parameter has the -// correct variance. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_uniform(ShaderArgInfo &p) -{ - if (p._varying) { - cp_report_error(p, "parameter should be declared 'uniform'"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_float -// Access: Public, Static -// Description: Make sure the provided parameter has -// a floating point type. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_float(ShaderArgInfo &p, int lo, int hi) -{ - int nfloat; - switch (p._type) { - case SAT_float1: nfloat = 1; break; - case SAT_float2: nfloat = 2; break; - case SAT_float3: nfloat = 3; break; - case SAT_float4: nfloat = 4; break; - case SAT_float4x4: nfloat = 16; break; - default: nfloat = 0; break; - } - if ((nfloat < lo)||(nfloat > hi)) { - string msg = "wrong type for parameter: should be float"; - cp_report_error(p, msg); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::cp_errchk_parameter_sampler -// Access: Public, Static -// Description: Make sure the provided parameter has -// a texture type. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_errchk_parameter_sampler(ShaderArgInfo &p) -{ - if ((p._type!=SAT_sampler1d)&& - (p._type!=SAT_sampler2d)&& - (p._type!=SAT_sampler3d)&& - (p._type!=SAT_samplercube)) { - cp_report_error(p, "parameter should have a 'sampler' type"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: ShaderContext::cp_parse_trans_clause -// Access: Public -// Description: Parses a single clause of a "trans" parameter. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, - int part, const vector_string &pieces, - int &next, ShaderMatInput ofop, ShaderMatInput op) { - if (pieces[next+1]=="of") { - if (pieces[next+2]=="") { - cp_report_error(p, "'of' should be followed by a name"); - return false; - } - spec._part[part] = ofop; - spec._arg[part] = InternalName::make(pieces[next+2]); - next += 3; - return true; - } else { - spec._part[part] = op; - spec._arg[part] = NULL; - next += 1; - return true; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ShaderContext::cp_optimize_mat_spec -// Access: Public -// Description: Analyzes a ShaderMatSpec and decides what it should -// use its cache for. It can cache the results of any -// one opcode, or, it can cache the entire result. This -// routine needs to be smart enough to know which -// data items can be correctly cached, and which cannot. -//////////////////////////////////////////////////////////////////// -void ShaderContext:: -cp_optimize_mat_spec(ShaderMatSpec &spec) { - - // If we're composing with identity, simplify. - if (spec._func == SMF_compose) { - if (spec._part[1] == SMO_identity) { - spec._func = SMF_first; - } - } - if (spec._func == SMF_compose) { - if (spec._part[0] == SMO_identity) { - spec._func = SMF_first; - spec._part[0] = spec._part[1]; - spec._arg[0] = spec._arg[1]; - } - } - - // See if either half can be cached. - bool can_cache_part0 = true; - bool can_cache_part1 = true; - if ((spec._part[0] == SMO_model_to_view)|| - (spec._part[0] == SMO_view_to_model)) { - can_cache_part0 = false; - } - if ((spec._part[1] == SMO_model_to_view)|| - (spec._part[1] == SMO_view_to_model)) { - can_cache_part1 = false; - } - - // See if we can use a compose-with-cache variant. - if (spec._func == SMF_compose) { - if (can_cache_part0) { - spec._func = SMF_compose_cache_first; - } else if (can_cache_part1) { - spec._func = SMF_compose_cache_second; - } - } - - // Determine transform-dependence. - if (can_cache_part0 && can_cache_part1) { - spec._trans_dependent = false; - } else { - spec._trans_dependent = true; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ShaderContext::compile_parameter -// Access: Public -// Description: Analyzes a parameter and decides how to -// bind the parameter to some part of panda's -// internal state. Updates one of the bind -// arrays to cause the binding to occur. -// -// If there is an error, this routine will append -// an error message onto the error messages. -//////////////////////////////////////////////////////////////////// -bool ShaderContext:: -compile_parameter(void *reference, - const string &arg_name, - ShaderArgType arg_type, - ShaderArgDir arg_direction, - bool arg_varying, - NotifyCategory *arg_cat) -{ - ShaderArgInfo p; - p._name = arg_name; - p._type = arg_type; - p._direction = arg_direction; - p._varying = arg_varying; - p._cat = arg_cat; - - if (p._name.size() == 0) return true; - if (p._name[0] == '$') return true; - vector_string pieces; - tokenize(p._name, pieces, "_"); - - if (pieces.size() < 2) { - cp_report_error(p, "invalid parameter name"); - return false; - } - - // Implement vtx parameters - the varying kind. - - if (pieces[0] == "vtx") { - if ((!cp_errchk_parameter_in(p)) || - (!cp_errchk_parameter_varying(p)) || - (!cp_errchk_parameter_float(p, 1, 4))) { - return false; - } - ShaderVarSpec bind; - bind._parameter = reference; - if (pieces.size() == 2) { - if (pieces[1]=="position") { - bind._name = InternalName::get_vertex(); - bind._append_uv = -1; - _var_spec.push_back(bind); - return true; - } - if (pieces[1].substr(0,8)=="texcoord") { - bind._name = InternalName::get_texcoord(); - bind._append_uv = atoi(pieces[1].c_str()+8); - _var_spec.push_back(bind); - return true; - } - if (pieces[1].substr(0,7)=="tangent") { - bind._name = InternalName::get_tangent(); - bind._append_uv = atoi(pieces[1].c_str()+7); - _var_spec.push_back(bind); - return true; - } - if (pieces[1].substr(0,8)=="binormal") { - bind._name = InternalName::get_binormal(); - bind._append_uv = atoi(pieces[1].c_str()+8); - _var_spec.push_back(bind); - return true; - } - } - bind._name = InternalName::get_root(); - bind._append_uv = -1; - for (int i=1; i<(int)(pieces.size()-0); i++) - bind._name = bind._name->append(pieces[i]); - _var_spec.push_back(bind); - return true; - } - - // Implement some macros. Macros work by altering the - // contents of the 'pieces' array, and then falling through. - - if (pieces[0] == "mstrans") { - pieces[0] = "trans"; - pieces.push_back("to"); - pieces.push_back("model"); - } - if (pieces[0] == "wstrans") { - pieces[0] = "trans"; - pieces.push_back("to"); - pieces.push_back("world"); - } - if (pieces[0] == "vstrans") { - pieces[0] = "trans"; - pieces.push_back("to"); - pieces.push_back("view"); - } - if (pieces[0] == "cstrans") { - pieces[0] = "trans"; - pieces.push_back("to"); - pieces.push_back("clip"); - } - if (pieces[0] == "mspos") { - pieces[0] = "row3"; - pieces.push_back("to"); - pieces.push_back("model"); - } - if (pieces[0] == "wspos") { - pieces[0] = "row3"; - pieces.push_back("to"); - pieces.push_back("world"); - } - if (pieces[0] == "vspos") { - pieces[0] = "row3"; - pieces.push_back("to"); - pieces.push_back("view"); - } - if (pieces[0] == "cspos") { - pieces[0] = "row3"; - pieces.push_back("to"); - pieces.push_back("clip"); - } - - // Implement the modelview macros. - - if ((pieces[0] == "mat")||(pieces[0] == "inv")|| - (pieces[0] == "tps")||(pieces[0] == "itp")) { - if (!cp_errchk_parameter_words(p, 2)) { - return false; - } - string trans = pieces[0]; - string matrix = pieces[1]; - pieces.clear(); - if (matrix == "modelview") { - tokenize("trans_model_to_apiview", pieces, "_"); - } else if (matrix == "projection") { - tokenize("trans_apiview_to_apiclip", pieces, "_"); - } else if (matrix == "modelproj") { - tokenize("trans_model_to_apiclip", pieces, "_"); - } else { - cp_report_error(p,"unrecognized matrix name"); - return false; - } - if (trans=="mat") { - pieces[0] = "trans"; - } else if (trans=="inv") { - string t = pieces[1]; - pieces[1] = pieces[3]; - pieces[3] = t; - } else if (trans=="tps") { - pieces[0] = "tpose"; - } else if (trans=="itp") { - string t = pieces[1]; - pieces[1] = pieces[3]; - pieces[3] = t; - pieces[0] = "tpose"; - } - } - - // Implement the transform-matrix generator. - - if ((pieces[0]=="trans")|| - (pieces[0]=="tpose")|| - (pieces[0]=="row0")|| - (pieces[0]=="row1")|| - (pieces[0]=="row2")|| - (pieces[0]=="row3")|| - (pieces[0]=="col0")|| - (pieces[0]=="col1")|| - (pieces[0]=="col2")|| - (pieces[0]=="col3")) { - - if ((!cp_errchk_parameter_in(p)) || - (!cp_errchk_parameter_uniform(p))) - return false; - - ShaderMatSpec bind; - bind._parameter = reference; - bind._func = SMF_compose; - - int next = 1; - pieces.push_back(""); - - // Decide whether this is a matrix or vector. - if (pieces[0]=="trans") bind._piece = SMP_whole; - else if (pieces[0]=="tpose") bind._piece = SMP_transpose; - else if (pieces[0]=="row0") bind._piece = SMP_row0; - else if (pieces[0]=="row1") bind._piece = SMP_row1; - else if (pieces[0]=="row2") bind._piece = SMP_row2; - else if (pieces[0]=="row3") bind._piece = SMP_row3; - else if (pieces[0]=="col0") bind._piece = SMP_col0; - else if (pieces[0]=="col1") bind._piece = SMP_col1; - else if (pieces[0]=="col2") bind._piece = SMP_col2; - else if (pieces[0]=="col3") bind._piece = SMP_col3; - if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) { - if (!cp_errchk_parameter_float(p, 16, 16)) return false; - } else { - if (!cp_errchk_parameter_float(p, 4, 4)) return false; - } - - // Parse the first half of the clause. - bool ok = true; - if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ - cp_report_error(p, "argument missing"); - return false; - } else if (pieces[next] == "world") { - bind._part[0] = SMO_world_to_view; - bind._arg[0] = NULL; - next += 1; - } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view); - } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); - } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity); - } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); - } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); - } else { - bind._part[0] = SMO_view_x_to_view; - bind._arg[0] = InternalName::make(pieces[next]); - next += 1; - } - - // Check for errors in the first clause. - if (!ok) { - return false; - } - - // Check for syntactic well-formed-ness. - if (pieces[next] != "to") { - cp_report_error(p, "keyword 'to' expected"); - return false; - } else { - next += 1; - } - - // Parse the second half of the clause. - if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ - cp_report_error(p, "argument missing"); - return false; - } else if (pieces[next] == "world") { - bind._part[1] = SMO_view_to_world; - bind._arg[1] = NULL; - next += 1; - } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model); - } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip); - } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity); - } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview); - } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip); - } else { - bind._part[1] = SMO_view_to_view_x; - bind._arg[1] = InternalName::make(pieces[next]); - next += 1; - } - - // Check for errors in the second clause. - if (!ok) { - return false; - } - - // Check for syntactic well-formed-ness. - if (pieces[next] != "") { - cp_report_error(p, "end of line expected"); - return false; - } - - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - return true; - } - - // Keywords to access unusual parameters. - - if (pieces[0] == "sys") { - if ((!cp_errchk_parameter_words(p,2)) || - (!cp_errchk_parameter_in(p)) || - (!cp_errchk_parameter_uniform(p))) { - return false; - } - ShaderMatSpec bind; - bind._parameter = reference; - bind._piece = SMP_row3; - bind._func = SMF_first; - bind._part[1] = SMO_identity; - bind._arg[1] = NULL; - if (pieces[1] == "pixelsize") { - if (!cp_errchk_parameter_float(p, 2, 2)) { - return false; - } - bind._part[0] = SMO_pixel_size; - bind._arg[0] = NULL; - } else if (pieces[1] == "windowsize") { - if (!cp_errchk_parameter_float(p, 2, 2)) { - return false; - } - bind._part[0] = SMO_window_size; - bind._arg[0] = NULL; - } else if (pieces[1] == "cardcenter") { - if (!cp_errchk_parameter_float(p, 2, 2)) { - return false; - } - bind._part[0] = SMO_card_center; - bind._arg[0] = NULL; - } else { - cp_report_error(p,"unknown system parameter"); - return false; - } - - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - return true; - } - - // Keywords to access textures. - - if (pieces[0] == "tex") { - if ((!cp_errchk_parameter_in(p)) || - (!cp_errchk_parameter_uniform(p)) || - (!cp_errchk_parameter_sampler(p))) - return false; - if ((pieces.size() != 2)&&(pieces.size() != 3)) { - cp_report_error(p, "Invalid parameter name"); - return false; - } - ShaderTexSpec bind; - bind._parameter = reference; - bind._name = 0; - bind._stage = atoi(pieces[1].c_str()); - switch (p._type) { - case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture; break; - case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break; - case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture; break; - case SAT_samplercube: bind._desired_type = Texture::TT_cube_map; break; - default: - cp_report_error(p, "Invalid type for a tex-parameter"); - return false; - } - if (pieces.size()==3) { - bind._suffix = InternalName::make(((string)"-") + pieces[2]); - } - _tex_spec.push_back(bind); - return true; - } - - // Keywords to access constants. - - if (pieces[0] == "k") { - if ((!cp_errchk_parameter_words(p,2)) || - (!cp_errchk_parameter_in(p)) || - (!cp_errchk_parameter_uniform(p))) - return false; - switch (p._type) { - case SAT_float4: { - ShaderMatSpec bind; - bind._parameter = reference; - bind._piece = SMP_row3; - bind._func = SMF_first; - bind._part[0] = SMO_vec_constant_x; - bind._arg[0] = InternalName::make(pieces[1]); - bind._part[1] = SMO_identity; - bind._arg[1] = NULL; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - break; - } - case SAT_float4x4: { - ShaderMatSpec bind; - bind._parameter = reference; - bind._piece = SMP_whole; - bind._func = SMF_first; - bind._part[0] = SMO_vec_constant_x; - bind._arg[0] = InternalName::make(pieces[1]); - bind._part[1] = SMO_identity; - bind._arg[1] = NULL; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - break; - } - case SAT_sampler1d: { - ShaderTexSpec bind; - bind._parameter = reference; - bind._name = InternalName::make(pieces[1]); - bind._desired_type=Texture::TT_1d_texture; - _tex_spec.push_back(bind); - break; - } - case SAT_sampler2d: { - ShaderTexSpec bind; - bind._parameter = reference; - bind._name = InternalName::make(pieces[1]); - bind._desired_type=Texture::TT_2d_texture; - _tex_spec.push_back(bind); - break; - } - case SAT_sampler3d: { - ShaderTexSpec bind; - bind._parameter = reference; - bind._name = InternalName::make(pieces[1]); - bind._desired_type=Texture::TT_3d_texture; - _tex_spec.push_back(bind); - break; - } - case SAT_samplercube: { - ShaderTexSpec bind; - bind._parameter = reference; - bind._name = InternalName::make(pieces[1]); - bind._desired_type = Texture::TT_cube_map; - _tex_spec.push_back(bind); - break; - } - default: - cp_report_error(p, "Invalid type for a k-parameter"); - return false; - } - return true; - } - - if (pieces[0] == "l") { - // IMPLEMENT THE ERROR CHECKING - return true; // Cg handles this automatically. - } - - if (pieces[0] == "o") { - // IMPLEMENT THE ERROR CHECKING - return true; // Cg handles this automatically. - } - - cp_report_error(p, "unrecognized parameter name"); - return false; -} - - diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index 4784f2d1fc..e8c2b0b73e 100755 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -40,156 +40,7 @@ class EXPCL_PANDA ShaderContext: public SavedContext { public: INLINE ShaderContext(ShaderExpansion *se); - ShaderExpansion *_shader_expansion; - -public: - enum { - SHADER_type_vert=0, - SHADER_type_frag=1, - SHADER_type_both=2, - }; - - enum ShaderMatInput { - SMO_identity, - - SMO_window_size, - SMO_pixel_size, - SMO_card_center, - - 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, - }; - - enum ShaderArgType { - SAT_float1, - SAT_float2, - SAT_float3, - SAT_float4, - SAT_float4x4, - SAT_sampler1d, - SAT_sampler2d, - SAT_sampler3d, - SAT_samplercube, - 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, - }; - - enum ShaderMatFunc { - SMF_compose, - SMF_compose_cache_first, - SMF_compose_cache_second, - SMF_first, - }; - - struct ShaderMatSpec { - ShaderMatFunc _func; - ShaderMatInput _part[2]; - PT(InternalName) _arg[2]; - LMatrix4f _cache; - ShaderMatPiece _piece; - bool _trans_dependent; - void *_parameter; - }; - - struct ShaderTexSpec { - PT(InternalName) _name; - int _stage; - int _desired_type; - PT(InternalName) _suffix; - void *_parameter; - }; - - struct ShaderVarSpec { - PT(InternalName) _name; - int _append_uv; - void *_parameter; - }; - - struct ShaderArgInfo { - string _name; - ShaderArgType _type; - ShaderArgDir _direction; - bool _varying; - NotifyCategory *_cat; - }; - -protected: - pvector _mat_spec; - pvector _tex_spec; - pvector _var_spec; - -private: - // These functions are only called from compile_parameter. - - void cp_report_error(ShaderArgInfo &arg, const string &msg); - bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len); - bool cp_errchk_parameter_in(ShaderArgInfo &arg); - 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_trans_clause(ShaderArgInfo &arg, - ShaderMatSpec &spec, - int part, - const vector_string &pieces, - int &next, - ShaderMatInput ofop, - ShaderMatInput op); - void cp_optimize_mat_spec(ShaderMatSpec &spec); - -protected: - bool compile_parameter(void *reference, - const string &arg_name, - ShaderArgType arg_type, - ShaderArgDir arg_direction, - bool arg_varying, - NotifyCategory *arg_cat); + ShaderExpansion *_expansion; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/shaderExpansion.I b/panda/src/gobj/shaderExpansion.I index 45255e3ed9..d0235f6fc6 100644 --- a/panda/src/gobj/shaderExpansion.I +++ b/panda/src/gobj/shaderExpansion.I @@ -36,3 +36,69 @@ get_text() const { return _text; } +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::get_header +// Access: Public +// Description: Return the ShaderExpansion's header line. +//////////////////////////////////////////////////////////////////// +INLINE const string &ShaderExpansion:: +get_header() const { + return _header; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::get_error_flag +// Access: Public +// Description: Returns true if the shader contains a compile-time +// error. This doesn't tell you whether or not the +// shader is supported on the current video card. +//////////////////////////////////////////////////////////////////// +INLINE bool ShaderExpansion:: +get_error_flag() const { + return _error_flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::ShaderCapabilities Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ShaderExpansion::ShaderCaps:: +ShaderCaps() { + clear(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::ShaderCapabilities::clear() +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ShaderExpansion::ShaderCaps:: +clear() { +#ifdef HAVE_CG + _active_vprofile = 0; + _active_fprofile = 0; + _ultimate_vprofile = 0; + _ultimate_fprofile = 0; +#endif +} + + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::ShaderCapabilities::operator == +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool ShaderExpansion::ShaderCaps:: +operator == (const ShaderCaps &other) const { +#ifdef HAVE_CG + if ((_active_vprofile != other._active_vprofile) || + (_active_fprofile != other._active_fprofile) || + (_ultimate_vprofile != other._ultimate_vprofile) || + (_ultimate_fprofile != other._ultimate_fprofile)) { + return false; + } +#endif + return true; +} \ No newline at end of file diff --git a/panda/src/gobj/shaderExpansion.cxx b/panda/src/gobj/shaderExpansion.cxx index 99fa619851..d723604cdd 100644 --- a/panda/src/gobj/shaderExpansion.cxx +++ b/panda/src/gobj/shaderExpansion.cxx @@ -20,16 +20,1146 @@ #include "shaderExpansion.h" #include "preparedGraphicsObjects.h" +#ifdef HAVE_CG +#include "Cg/cg.h" +#endif + TypeHandle ShaderExpansion::_type_handle; ShaderExpansion::ExpansionCache ShaderExpansion::_expansion_cache; +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_report_error +// Access: Public +// Description: Generate an error message including a description +// of the specified parameter. +//////////////////////////////////////////////////////////////////// +void ShaderExpansion:: +cp_report_error(ShaderArgInfo &p, const string &msg) +{ + string vstr; + if (p._varying) vstr = "varying "; + else vstr = "uniform "; + + string dstr = "unknown "; + if (p._direction == SAD_in) dstr = "in "; + if (p._direction == SAD_out) dstr = "out "; + if (p._direction == SAD_inout) dstr = "inout "; + + string tstr = "invalid "; + switch (p._type) { + case SAT_float1: tstr = "float1 "; break; + case SAT_float2: tstr = "float2 "; break; + case SAT_float3: tstr = "float3 "; break; + case SAT_float4: tstr = "float4 "; break; + case SAT_float4x4: tstr = "float4x4 "; break; + case SAT_sampler1d: tstr = "sampler1d "; break; + case SAT_sampler2d: tstr = "sampler2d "; break; + case SAT_sampler3d: tstr = "sampler3d "; break; + case SAT_samplercube: tstr = "samplercube "; break; + case SAT_unknown: tstr = "unknown "; break; + } + + string fn = get_name(); + p._cat->error() << fn << ": " << msg << " (" << + vstr << dstr << tstr << p._id._name << ")\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_words +// Access: Public, Static +// Description: Make sure the provided parameter contains +// the specified number of words. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_words(ShaderArgInfo &p, int len) +{ + vector_string words; + tokenize(p._id._name, words, "_"); + if ((int)words.size() != len) { + cp_report_error(p, "parameter name has wrong number of words"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_in +// Access: Public, Static +// Description: Make sure the provided parameter has the +// 'in' direction. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_in(ShaderArgInfo &p) +{ + if (p._direction != SAD_in) { + cp_report_error(p, "parameter should be declared 'in'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_varying +// Access: Public, Static +// Description: Make sure the provided parameter has the +// correct variance. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_varying(ShaderArgInfo &p) +{ + if (!p._varying) { + cp_report_error(p, "parameter should be declared 'varying'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_uniform +// Access: Public, Static +// Description: Make sure the provided parameter has the +// correct variance. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_uniform(ShaderArgInfo &p) +{ + if (p._varying) { + cp_report_error(p, "parameter should be declared 'uniform'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_float +// Access: Public, Static +// Description: Make sure the provided parameter has +// a floating point type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_float(ShaderArgInfo &p, int lo, int hi) +{ + int nfloat; + switch (p._type) { + case SAT_float1: nfloat = 1; break; + case SAT_float2: nfloat = 2; break; + case SAT_float3: nfloat = 3; break; + case SAT_float4: nfloat = 4; break; + case SAT_float4x4: nfloat = 16; break; + default: nfloat = 0; break; + } + if ((nfloat < lo)||(nfloat > hi)) { + string msg = "wrong type for parameter: should be float"; + cp_report_error(p, msg); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_errchk_parameter_sampler +// Access: Public, Static +// Description: Make sure the provided parameter has +// a texture type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_errchk_parameter_sampler(ShaderArgInfo &p) +{ + if ((p._type!=SAT_sampler1d)&& + (p._type!=SAT_sampler2d)&& + (p._type!=SAT_sampler3d)&& + (p._type!=SAT_samplercube)) { + cp_report_error(p, "parameter should have a 'sampler' type"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_parse_trans_clause +// Access: Public +// Description: Parses a single clause of a "trans" parameter. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, + int part, const vector_string &pieces, + int &next, ShaderMatInput ofop, ShaderMatInput op) { + if (pieces[next+1]=="of") { + if (pieces[next+2]=="") { + cp_report_error(p, "'of' should be followed by a name"); + return false; + } + spec._part[part] = ofop; + spec._arg[part] = InternalName::make(pieces[next+2]); + next += 3; + return true; + } else { + spec._part[part] = op; + spec._arg[part] = NULL; + next += 1; + return true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cp_optimize_mat_spec +// Access: Public +// Description: Analyzes a ShaderMatSpec and decides what it should +// use its cache for. It can cache the results of any +// one opcode, or, it can cache the entire result. This +// routine needs to be smart enough to know which +// data items can be correctly cached, and which cannot. +//////////////////////////////////////////////////////////////////// +void ShaderExpansion:: +cp_optimize_mat_spec(ShaderMatSpec &spec) { + + // If we're composing with identity, simplify. + if (spec._func == SMF_compose) { + if (spec._part[1] == SMO_identity) { + spec._func = SMF_first; + } + } + if (spec._func == SMF_compose) { + if (spec._part[0] == SMO_identity) { + spec._func = SMF_first; + spec._part[0] = spec._part[1]; + spec._arg[0] = spec._arg[1]; + } + } + + // See if either half can be cached. + bool can_cache_part0 = true; + bool can_cache_part1 = true; + if ((spec._part[0] == SMO_model_to_view)|| + (spec._part[0] == SMO_view_to_model)) { + can_cache_part0 = false; + } + if ((spec._part[1] == SMO_model_to_view)|| + (spec._part[1] == SMO_view_to_model)) { + can_cache_part1 = false; + } + + // See if we can use a compose-with-cache variant. + if (spec._func == SMF_compose) { + if (can_cache_part0) { + spec._func = SMF_compose_cache_first; + } else if (can_cache_part1) { + spec._func = SMF_compose_cache_second; + } + } + + // Determine transform-dependence. + if (can_cache_part0 && can_cache_part1) { + spec._trans_dependent = false; + } else { + spec._trans_dependent = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::compile_parameter +// Access: Public +// Description: Analyzes a parameter and decides how to +// bind the parameter to some part of panda's +// internal state. Updates one of the bind +// arrays to cause the binding to occur. +// +// If there is an error, this routine will append +// an error message onto the error messages. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +compile_parameter(const ShaderArgId &arg_id, + ShaderArgType arg_type, + ShaderArgDir arg_direction, + bool arg_varying, + NotifyCategory *arg_cat) +{ + ShaderArgInfo p; + p._id = arg_id; + p._type = arg_type; + p._direction = arg_direction; + p._varying = arg_varying; + p._cat = arg_cat; + + if (p._id._name.size() == 0) return true; + if (p._id._name[0] == '$') return true; + vector_string pieces; + tokenize(p._id._name, pieces, "_"); + + if (pieces.size() < 2) { + cp_report_error(p, "invalid parameter name"); + return false; + } + + // Implement vtx parameters - the varying kind. + + if (pieces[0] == "vtx") { + if ((!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_varying(p)) || + (!cp_errchk_parameter_float(p, 1, 4))) { + return false; + } + ShaderVarSpec bind; + bind._id = arg_id; + if (pieces.size() == 2) { + if (pieces[1]=="position") { + bind._name = InternalName::get_vertex(); + bind._append_uv = -1; + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,8)=="texcoord") { + bind._name = InternalName::get_texcoord(); + bind._append_uv = atoi(pieces[1].c_str()+8); + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,7)=="tangent") { + bind._name = InternalName::get_tangent(); + bind._append_uv = atoi(pieces[1].c_str()+7); + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,8)=="binormal") { + bind._name = InternalName::get_binormal(); + bind._append_uv = atoi(pieces[1].c_str()+8); + _var_spec.push_back(bind); + return true; + } + } + bind._name = InternalName::get_root(); + bind._append_uv = -1; + for (int i=1; i<(int)(pieces.size()-0); i++) + bind._name = bind._name->append(pieces[i]); + _var_spec.push_back(bind); + return true; + } + + // Implement some macros. Macros work by altering the + // contents of the 'pieces' array, and then falling through. + + if (pieces[0] == "mstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("model"); + } + if (pieces[0] == "wstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("world"); + } + if (pieces[0] == "vstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("view"); + } + if (pieces[0] == "cstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("clip"); + } + if (pieces[0] == "mspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("model"); + } + if (pieces[0] == "wspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("world"); + } + if (pieces[0] == "vspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("view"); + } + if (pieces[0] == "cspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("clip"); + } + + // Implement the modelview macros. + + if ((pieces[0] == "mat")||(pieces[0] == "inv")|| + (pieces[0] == "tps")||(pieces[0] == "itp")) { + if (!cp_errchk_parameter_words(p, 2)) { + return false; + } + string trans = pieces[0]; + string matrix = pieces[1]; + pieces.clear(); + if (matrix == "modelview") { + tokenize("trans_model_to_apiview", pieces, "_"); + } else if (matrix == "projection") { + tokenize("trans_apiview_to_apiclip", pieces, "_"); + } else if (matrix == "modelproj") { + tokenize("trans_model_to_apiclip", pieces, "_"); + } else { + cp_report_error(p,"unrecognized matrix name"); + return false; + } + if (trans=="mat") { + pieces[0] = "trans"; + } else if (trans=="inv") { + string t = pieces[1]; + pieces[1] = pieces[3]; + pieces[3] = t; + } else if (trans=="tps") { + pieces[0] = "tpose"; + } else if (trans=="itp") { + string t = pieces[1]; + pieces[1] = pieces[3]; + pieces[3] = t; + pieces[0] = "tpose"; + } + } + + // Implement the transform-matrix generator. + + if ((pieces[0]=="trans")|| + (pieces[0]=="tpose")|| + (pieces[0]=="row0")|| + (pieces[0]=="row1")|| + (pieces[0]=="row2")|| + (pieces[0]=="row3")|| + (pieces[0]=="col0")|| + (pieces[0]=="col1")|| + (pieces[0]=="col2")|| + (pieces[0]=="col3")) { + + if ((!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))) + return false; + + ShaderMatSpec bind; + bind._id = arg_id; + bind._func = SMF_compose; + + int next = 1; + pieces.push_back(""); + + // Decide whether this is a matrix or vector. + if (pieces[0]=="trans") bind._piece = SMP_whole; + else if (pieces[0]=="tpose") bind._piece = SMP_transpose; + else if (pieces[0]=="row0") bind._piece = SMP_row0; + else if (pieces[0]=="row1") bind._piece = SMP_row1; + else if (pieces[0]=="row2") bind._piece = SMP_row2; + else if (pieces[0]=="row3") bind._piece = SMP_row3; + else if (pieces[0]=="col0") bind._piece = SMP_col0; + else if (pieces[0]=="col1") bind._piece = SMP_col1; + else if (pieces[0]=="col2") bind._piece = SMP_col2; + else if (pieces[0]=="col3") bind._piece = SMP_col3; + if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) { + if (!cp_errchk_parameter_float(p, 16, 16)) return false; + } else { + if (!cp_errchk_parameter_float(p, 4, 4)) return false; + } + + // Parse the first half of the clause. + bool ok = true; + if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ + cp_report_error(p, "argument missing"); + return false; + } else if (pieces[next] == "world") { + bind._part[0] = SMO_world_to_view; + bind._arg[0] = NULL; + next += 1; + } else if (pieces[next] == "model") { + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view); + } else if (pieces[next] == "clip") { + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); + } else if (pieces[next] == "view") { + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity); + } else if (pieces[next] == "apiview") { + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); + } else if (pieces[next] == "apiclip") { + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); + } else { + bind._part[0] = SMO_view_x_to_view; + bind._arg[0] = InternalName::make(pieces[next]); + next += 1; + } + + // Check for errors in the first clause. + if (!ok) { + return false; + } + + // Check for syntactic well-formed-ness. + if (pieces[next] != "to") { + cp_report_error(p, "keyword 'to' expected"); + return false; + } else { + next += 1; + } + + // Parse the second half of the clause. + if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ + cp_report_error(p, "argument missing"); + return false; + } else if (pieces[next] == "world") { + bind._part[1] = SMO_view_to_world; + bind._arg[1] = NULL; + next += 1; + } else if (pieces[next] == "model") { + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model); + } else if (pieces[next] == "clip") { + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip); + } else if (pieces[next] == "view") { + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity); + } else if (pieces[next] == "apiview") { + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview); + } else if (pieces[next] == "apiclip") { + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip); + } else { + bind._part[1] = SMO_view_to_view_x; + bind._arg[1] = InternalName::make(pieces[next]); + next += 1; + } + + // Check for errors in the second clause. + if (!ok) { + return false; + } + + // Check for syntactic well-formed-ness. + if (pieces[next] != "") { + cp_report_error(p, "end of line expected"); + return false; + } + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + // Keywords to access unusual parameters. + + if (pieces[0] == "sys") { + if ((!cp_errchk_parameter_words(p,2)) || + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))) { + return false; + } + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + if (pieces[1] == "pixelsize") { + if (!cp_errchk_parameter_float(p, 2, 2)) { + return false; + } + bind._part[0] = SMO_pixel_size; + bind._arg[0] = NULL; + } else if (pieces[1] == "windowsize") { + if (!cp_errchk_parameter_float(p, 2, 2)) { + return false; + } + bind._part[0] = SMO_window_size; + bind._arg[0] = NULL; + } else if (pieces[1] == "cardcenter") { + if (!cp_errchk_parameter_float(p, 2, 2)) { + return false; + } + bind._part[0] = SMO_card_center; + bind._arg[0] = NULL; + } else { + cp_report_error(p,"unknown system parameter"); + return false; + } + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + // Keywords to access textures. + + if (pieces[0] == "tex") { + if ((!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p)) || + (!cp_errchk_parameter_sampler(p))) + return false; + if ((pieces.size() != 2)&&(pieces.size() != 3)) { + cp_report_error(p, "Invalid parameter name"); + return false; + } + ShaderTexSpec bind; + bind._id = arg_id; + bind._name = 0; + bind._stage = atoi(pieces[1].c_str()); + switch (p._type) { + case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture; break; + case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break; + case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture; break; + case SAT_samplercube: bind._desired_type = Texture::TT_cube_map; break; + default: + cp_report_error(p, "Invalid type for a tex-parameter"); + return false; + } + if (pieces.size()==3) { + bind._suffix = InternalName::make(((string)"-") + pieces[2]); + } + _tex_spec.push_back(bind); + return true; + } + + // Keywords to access constants. + + if (pieces[0] == "k") { + if ((!cp_errchk_parameter_words(p,2)) || + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))) + return false; + switch (p._type) { + case SAT_float4: { + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_vec_constant_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + break; + } + case SAT_float4x4: { + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_whole; + bind._func = SMF_first; + bind._part[0] = SMO_vec_constant_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + break; + } + case SAT_sampler1d: { + ShaderTexSpec bind; + bind._id = arg_id; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_1d_texture; + _tex_spec.push_back(bind); + break; + } + case SAT_sampler2d: { + ShaderTexSpec bind; + bind._id = arg_id; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_2d_texture; + _tex_spec.push_back(bind); + break; + } + case SAT_sampler3d: { + ShaderTexSpec bind; + bind._id = arg_id; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_3d_texture; + _tex_spec.push_back(bind); + break; + } + case SAT_samplercube: { + ShaderTexSpec bind; + bind._id = arg_id; + bind._name = InternalName::make(pieces[1]); + bind._desired_type = Texture::TT_cube_map; + _tex_spec.push_back(bind); + break; + } + default: + cp_report_error(p, "Invalid type for a k-parameter"); + return false; + } + return true; + } + + if (pieces[0] == "l") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + if (pieces[0] == "o") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + cp_report_error(p, "unrecognized parameter name"); + return false; +} + + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::clear_parameters +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void ShaderExpansion:: +clear_parameters() { + _mat_spec.clear(); + _var_spec.clear(); + _tex_spec.clear(); +} + +#ifdef HAVE_CG +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_parameter_type +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +ShaderExpansion::ShaderArgType ShaderExpansion:: +cg_parameter_type(CGparameter p) { + switch (cgGetParameterType(p)) { + case CG_FLOAT1: return ShaderExpansion::SAT_float1; + case CG_FLOAT2: return ShaderExpansion::SAT_float2; + case CG_FLOAT3: return ShaderExpansion::SAT_float3; + case CG_FLOAT4: return ShaderExpansion::SAT_float4; + case CG_FLOAT4x4: return ShaderExpansion::SAT_float4x4; + case CG_SAMPLER1D: return ShaderExpansion::SAT_sampler1d; + case CG_SAMPLER2D: return ShaderExpansion::SAT_sampler2d; + case CG_SAMPLER3D: return ShaderExpansion::SAT_sampler3d; + case CG_SAMPLERCUBE: return ShaderExpansion::SAT_samplercube; + default: return ShaderExpansion::SAT_unknown; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_parameter_dir +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +ShaderExpansion::ShaderArgDir ShaderExpansion:: +cg_parameter_dir(CGparameter p) { + switch (cgGetParameterDirection(p)) { + case CG_IN: return ShaderExpansion::SAD_in; + case CG_OUT: return ShaderExpansion::SAD_out; + case CG_INOUT: return ShaderExpansion::SAD_inout; + default: return ShaderExpansion::SAD_unknown; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_release_resources +// Access: Private +// Description: xyz +//////////////////////////////////////////////////////////////////// +void ShaderExpansion:: +cg_release_resources() { + if (_cg_vprogram != 0) { + cgDestroyProgram(_cg_vprogram); + _cg_vprogram = 0; + } + if (_cg_fprogram != 0) { + cgDestroyProgram(_cg_fprogram); + _cg_fprogram = 0; + } + if (_cg_context != 0) { + cgDestroyContext(_cg_context); + _cg_context = 0; + } +} +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_compile_entry_point +// Access: Private +// Description: xyz +//////////////////////////////////////////////////////////////////// +CGprogram ShaderExpansion:: +cg_compile_entry_point(char *entry, int active, int ultimate) +{ + CGprogram prog; + CGerror err; + + if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) { + prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(), + (CGprofile)active, entry, (const char**)NULL); + if (cgGetError() == CG_NO_ERROR) { + return prog; + } + if (prog != 0) { + cgDestroyProgram(prog); + } + } + + prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(), + (CGprofile)ultimate, entry, (const char**)NULL); + err = cgGetError(); + if (err == CG_NO_ERROR) { + return prog; + } + if (err == CG_COMPILER_ERROR) { + string listing = cgGetLastListing(_cg_context); + vector_string errlines; + tokenize(listing, errlines, "\n"); + for (int i=0; i<(int)errlines.size(); i++) { + string line = trim(errlines[i]); + if (line != "") { + gobj_cat.error() << _name << " " << errlines[i] << "\n"; + } + } + } else { + gobj_cat.error() << _name << ": " << cgGetErrorString(err) << "\n"; + } + if (prog != 0) { + cgDestroyProgram(prog); + } + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_compile_shader +// Access: Private +// Description: Compiles a Cg shader for a given set of capabilities. +// If successful, the shader is stored in the instance +// variables _cg_context, _cg_vprogram, _cg_fprogram. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cg_compile_shader(const ShaderCaps &caps) { + + // If we already tried compiling for this set of caps, there's no point + // trying again. Just return the results of the previous compile. + if (caps == _cg_last_caps) { + if (_cg_context == 0) { + return false; + } else { + return true; + } + } + + _cg_last_caps = caps; + + _cg_context = cgCreateContext(); + + if (_cg_context == 0) { + gobj_cat.error() << "could not create a Cg context object.\n"; + return false; + } + + _cg_vprogram = cg_compile_entry_point("vshader", + caps._active_vprofile, + caps._ultimate_vprofile); + + _cg_fprogram = cg_compile_entry_point("fshader", + caps._active_fprofile, + caps._ultimate_fprofile); + + if ((_cg_vprogram == 0)||(_cg_fprogram == 0)) { + cg_release_resources(); + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_analyze_entry_point +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cg_analyze_entry_point(CGprogram prog, bool fshader) { + CGparameter parameter; + bool success = true; + for (parameter = cgGetFirstLeafParameter(prog, CG_PROGRAM); + parameter != 0; + parameter = cgGetNextLeafParameter(parameter)) { + CGenum vbl = cgGetParameterVariability(parameter); + if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) { + ShaderArgId id; + id._name = cgGetParameterName(parameter); + id._fshader = fshader; + id._seqno = -1; + success &= compile_parameter(id, + cg_parameter_type(parameter), + cg_parameter_dir(parameter), + (vbl == CG_VARYING), + gobj_cat.get_safe_ptr()); + } + } + return success; +} + + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_analyze_shader +// Access: Private +// Description: This subroutine analyzes the parameters of a Cg +// shader. The output is stored in instance variables: +// _mat_spec, _var_spec, and _tex_spec. +// +// In order to do this, it is necessary to compile the +// shader. It would be a waste of CPU time to compile +// the shader, analyze the parameters, and then discard +// the compiled shader. This would force us to compile it +// again later, when we need to build the ShaderContext. +// Instead, we cache the compiled Cg program in instance +// variables. Later, a ShaderContext can pull the +// compiled shader from these instance vars. +// +// To compile a shader, you need to first choose a profile. +// There are two contradictory objectives: +// +// 1. If you don't use the gsg's active profile, +// then the cached compiled shader will not be useful to +// the ShaderContext. +// +// 2. If you use too weak a profile, then the shader may +// not compile. So to guarantee success, you should use +// the ultimate profile. +// +// To resolve this conflict, we try the active profile +// first, and if that doesn't work, we try the ultimate +// profile. +// +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cg_analyze_shader(const ShaderCaps &caps) { + + if (!cg_compile_shader(caps)) { + return false; + } + + if (!cg_analyze_entry_point(_cg_fprogram, true)) { + cg_release_resources(); + clear_parameters(); + return false; + } + + if (_var_spec.size() != 0) { + gobj_cat.error() << "Cannot use vtx parameters in an fshader\n"; + cg_release_resources(); + clear_parameters(); + return false; + } + + if (!cg_analyze_entry_point(_cg_vprogram, false)) { + cg_release_resources(); + clear_parameters(); + return false; + } + + // Assign sequence numbers to all parameters. + int seqno = 0; + for (int i=0; i<(int)_mat_spec.size(); i++) { + _mat_spec[i]._id._seqno = seqno++; + } + for (int i=0; i<(int)_tex_spec.size(); i++) { + _tex_spec[i]._id._seqno = seqno++; + } + for (int i=0; i<(int)_var_spec.size(); i++) { + _var_spec[i]._id._seqno = seqno++; + } + + // DEBUG: output the generated program + if (gobj_cat.is_debug()) { + const char *vertex_program; + const char *pixel_program; + + vertex_program = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM); + pixel_program = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM); + + gobj_cat.debug() << vertex_program << "\n"; + gobj_cat.debug() << pixel_program << "\n"; + } + + // // The following code is present to work around a bug in the Cg compiler. + // // It does not generate correct code for shadow map lookups when using arbfp1. + // // This is a particularly onerous limitation, given that arbfp1 is the only + // // Cg target that works on radeons. I suspect this is an intentional + // // omission on nvidia's part. The following code fetches the output listing, + // // detects the error, repairs the code, and resumbits the repaired code to Cg. + // if ((_cg_fprofile == CG_PROFILE_ARBFP1) && (gsghint->_supports_shadow_filter)) { + // bool shadowunit[32]; + // bool anyshadow = false; + // memset(shadowunit, 0, sizeof(shadowunit)); + // vector_string lines; + // tokenize(cgGetProgramString(_cg_program[SHADER_type_frag], + // CG_COMPILED_PROGRAM), lines, "\n"); + // // figure out which texture units contain shadow maps. + // for (int lineno=0; lineno<(int)lines.size(); lineno++) { + // if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) { + // continue; + // } + // vector_string fields; + // tokenize(lines[lineno], fields, ":"); + // if (fields.size()!=5) { + // continue; + // } + // vector_string words; + // tokenize(trim(fields[2]), words, " "); + // if (words.size()!=2) { + // continue; + // } + // int unit = atoi(words[1].c_str()); + // if ((unit < 0)||(unit >= 32)) { + // continue; + // } + // anyshadow = true; + // shadowunit[unit] = true; + // } + // // modify all TEX statements that use the relevant texture units. + // if (anyshadow) { + // for (int lineno=0; lineno<(int)lines.size(); lineno++) { + // if (lines[lineno].compare(0,4,"TEX ")) { + // continue; + // } + // vector_string fields; + // tokenize(lines[lineno], fields, ","); + // if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) { + // continue; + // } + // vector_string texunitf; + // tokenize(trim(fields[2]), texunitf, "[]"); + // if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) { + // continue; + // } + // int unit = atoi(texunitf[1].c_str()); + // if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) { + // continue; + // } + // lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;"; + // } + // string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n"; + // for (int lineno=1; lineno<(int)lines.size(); lineno++) { + // result += (lines[lineno] + "\n"); + // } + // _cg_program[2] = _cg_program[SHADER_type_frag]; + // _cg_program[SHADER_type_frag] = + // cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(), + // _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL); + // cg_report_errors(s->get_name(), _cg_context); + // if (_cg_program[SHADER_type_frag]==0) { + // release_resources(); + // return false; + // } + // } + // } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderExpansion::cg_compile_for +// Access: Public +// Description: This routine is used by the ShaderContext constructor +// to compile the shader. The CGprogram +// objects are turned over to the ShaderContext, we no +// longer own them. +//////////////////////////////////////////////////////////////////// +bool ShaderExpansion:: +cg_compile_for(const ShaderCaps &caps, + CGcontext &ctx, + CGprogram &vprogram, + CGprogram &fprogram, + pvector &map) { + + // Initialize the return values to empty. + + ctx = 0; + vprogram = 0; + fprogram = 0; + map.clear(); + + // Make sure the shader is compiled for the target caps. + // Most of the time, it will already be - this is usually a no-op. + + if (!cg_compile_shader(caps)) { + return false; + } + + // If the compile routine used the ultimate profile instead of the + // active one, it means the active one isn't powerful enough to + // compile the shader. + + if ((cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile)|| + (cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile)) { + gobj_cat.error() << "Cg program too complex for driver:" << get_name() << "\n"; + return false; + } + + // Build a parameter map. + + int n_mat = (int)_mat_spec.size(); + int n_tex = (int)_tex_spec.size(); + int n_var = (int)_var_spec.size(); + + map.resize(n_mat + n_tex + n_var); + + for (int i=0; isecond; } - ShaderExpansion *result = new ShaderExpansion(); - result->_name = name; - result->_text = text; + ShaderExpansion *result = new ShaderExpansion(name, text, caps); _expansion_cache.insert(ExpansionCache::value_type(key,result)); return result; } diff --git a/panda/src/gobj/shaderExpansion.h b/panda/src/gobj/shaderExpansion.h index 264f68bd83..2d107aca43 100644 --- a/panda/src/gobj/shaderExpansion.h +++ b/panda/src/gobj/shaderExpansion.h @@ -25,29 +25,169 @@ #include "graphicsStateGuardianBase.h" #include "internalName.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 : ShaderExpansion // Summary: A shader can contain context-sensitive macros. // A ShaderExpansion is the output you get when you // run the macro preprocessor on a shader. // The ShaderExpansion contains the shader's -// macroexpanded text, and a map of ShaderContext +// macroexpanded text, an analysis of the shader's +// parameters, and a map of ShaderContext // objects. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA ShaderExpansion: public TypedReferenceCount { PUBLISHED: - static PT(ShaderExpansion) make(const string &name, const string &body); INLINE const string &get_name() const; INLINE const string &get_text() const; - + INLINE const string &get_header() const; + INLINE bool get_error_flag() const; + void prepare(PreparedGraphicsObjects *prepared_objects); bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); -PUBLISHED: +public: + + enum ShaderMatInput { + SMO_identity, + + SMO_window_size, + SMO_pixel_size, + SMO_card_center, + + 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, + }; + + enum ShaderArgType { + SAT_float1, + SAT_float2, + SAT_float3, + SAT_float4, + SAT_float4x4, + SAT_sampler1d, + SAT_sampler2d, + SAT_sampler3d, + SAT_samplercube, + 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, + }; + + enum ShaderMatFunc { + SMF_compose, + SMF_compose_cache_first, + SMF_compose_cache_second, + SMF_first, + }; + + struct ShaderArgId { + string _name; + bool _fshader; + int _seqno; + }; + + struct ShaderMatSpec { + ShaderArgId _id; + ShaderMatFunc _func; + ShaderMatInput _part[2]; + PT(InternalName) _arg[2]; + LMatrix4f _cache; + ShaderMatPiece _piece; + bool _trans_dependent; + }; + + struct ShaderTexSpec { + ShaderArgId _id; + PT(InternalName) _name; + int _stage; + int _desired_type; + PT(InternalName) _suffix; + }; + + struct ShaderVarSpec { + ShaderArgId _id; + PT(InternalName) _name; + int _append_uv; + }; + + struct ShaderArgInfo { + ShaderArgId _id; + ShaderArgType _type; + ShaderArgDir _direction; + bool _varying; + NotifyCategory *_cat; + }; + + struct ShaderCaps { +#ifdef HAVE_CG + int _active_vprofile; + int _active_fprofile; + int _ultimate_vprofile; + int _ultimate_fprofile; +#endif; + INLINE void clear(); + INLINE bool operator == (const ShaderCaps &other) const; + INLINE ShaderCaps(); + }; + + private: // These routines help split the shader into sections, // for those shader implementations that need to do so. void parse_init(); @@ -57,11 +197,65 @@ PUBLISHED: int parse_lineno(); bool parse_eof(); -public: - ~ShaderExpansion(); + void cp_report_error(ShaderArgInfo &arg, const string &msg); + bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len); + bool cp_errchk_parameter_in(ShaderArgInfo &arg); + 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_trans_clause(ShaderArgInfo &arg, + ShaderMatSpec &spec, + int part, + const vector_string &pieces, + int &next, + ShaderMatInput ofop, + ShaderMatInput op); + void cp_optimize_mat_spec(ShaderMatSpec &spec); + + bool compile_parameter(const ShaderArgId &arg_id, + ShaderArgType arg_type, + ShaderArgDir arg_direction, + bool arg_varying, + NotifyCategory *arg_cat); + void clear_parameters(); + +#ifdef HAVE_CG + private: + ShaderArgType cg_parameter_type(CGparameter p); + ShaderArgDir cg_parameter_dir(CGparameter p); + CGprogram cg_compile_entry_point(char *entry, int active, int ultimate); + bool cg_analyze_entry_point(CGprogram prog, bool fshader); + bool cg_analyze_shader(const ShaderCaps &caps); + bool cg_compile_shader(const ShaderCaps &caps); + void cg_release_resources(); + + ShaderCaps _cg_last_caps; + CGcontext _cg_context; + CGprogram _cg_vprogram; + CGprogram _cg_fprogram; + + public: + + bool cg_compile_for(const ShaderCaps &caps, + CGcontext &ctx, + CGprogram &vprogram, + CGprogram &fprogram, + pvector &map); + +#endif + + public: + pvector _mat_spec; + pvector _tex_spec; + pvector _var_spec; + + protected: string _name; string _text; + string _header; + bool _error_flag; int _parse; typedef pair < string, string > ExpansionKey; @@ -73,15 +267,23 @@ public: typedef pmap Contexts; Contexts _contexts; - + + public: ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg); -private: - ShaderExpansion(); + private: + ShaderExpansion(const string &name, const string &text, + const ShaderCaps &caps); void clear_prepared(PreparedGraphicsObjects *prepared_objects); -public: + public: + static PT(ShaderExpansion) make(const string &name, const string &body, + const ShaderCaps &caps); + + ~ShaderExpansion(); + + public: static TypeHandle get_class_type() { return _type_handle; } @@ -95,7 +297,7 @@ public: } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} -private: + private: static TypeHandle _type_handle; }; diff --git a/panda/src/mesadisplay/mesagsg.h b/panda/src/mesadisplay/mesagsg.h index d7081b0df5..54d487f7c2 100644 --- a/panda/src/mesadisplay/mesagsg.h +++ b/panda/src/mesadisplay/mesagsg.h @@ -44,9 +44,6 @@ #define EXPCL_GL EXPCL_PANDAMESA #define EXPTP_GL EXPTP_PANDAMESA -#undef HAVE_CGGL // Mesa does not support Nvidia Cg... make sure it tries to compile - // without it - // Don't include Mesa's provided glext.h file; we'll provide our own // that's more current. #define __glext_h_ diff --git a/panda/src/pgraph/shader.cxx b/panda/src/pgraph/shader.cxx index 09675fa246..2da144c4b2 100644 --- a/panda/src/pgraph/shader.cxx +++ b/panda/src/pgraph/shader.cxx @@ -140,15 +140,19 @@ make(const string &body, int preprocessor) { // // Currently, macroexpand is just a stub that returns an // expansion which is exactly equal to the input string. +// +// The "caps" parameter should describe the capabilities +// of the gsg on which this is intended to run. //////////////////////////////////////////////////////////////////// PT(ShaderExpansion) Shader:: -macroexpand(const RenderState *context) const { +macroexpand(const RenderState *context, + const ShaderExpansion::ShaderCaps &caps) const { if (_fixed_expansion) { return _fixed_expansion; } // I am casting away the 'const' so as to be able // to write to this field. This field is just a cache. - ((Shader*)this)->_fixed_expansion = ShaderExpansion::make(_name,_body); + ((Shader*)this)->_fixed_expansion = ShaderExpansion::make(_name,_body,caps); return _fixed_expansion; } diff --git a/panda/src/pgraph/shader.h b/panda/src/pgraph/shader.h index 6bf10ea0e9..3eb324a410 100644 --- a/panda/src/pgraph/shader.h +++ b/panda/src/pgraph/shader.h @@ -45,7 +45,8 @@ PUBLISHED: INLINE bool get_loaded() const; INLINE bool get_load_error() const; - PT(ShaderExpansion) macroexpand(const RenderState *context) const; + PT(ShaderExpansion) macroexpand(const RenderState *context, + const ShaderExpansion::ShaderCaps &caps) const; public: Shader();