Browse Source

This fixes most issues with Cg's GLSL profiles on non-NVIDIA cards

rdb 11 years ago
parent
commit
3b1bd9ef39

+ 16 - 6
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -84,7 +84,9 @@ D3DMATRIX DXGraphicsStateGuardian9::_d3d_ident_mat;
 unsigned char *DXGraphicsStateGuardian9::_temp_buffer = NULL;
 unsigned char *DXGraphicsStateGuardian9::_safe_buffer_start = NULL;
 
+#ifdef HAVE_CG
 LPDIRECT3DDEVICE9 DXGraphicsStateGuardian9::_cg_device = NULL;
+#endif
 
 #define __D3DLIGHT_RANGE_MAX ((PN_stdfloat)sqrt(FLT_MAX))  //for some reason this is missing in dx9 hdrs
 
@@ -150,6 +152,10 @@ DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) :
 
   _supports_stream_offset = false;
 
+#ifdef HAVE_CG
+  _cg_context = 0;
+#endif
+
   get_gamma_table();
   atexit (atexit_function);
 }
@@ -2372,6 +2378,8 @@ reset() {
 #ifdef HAVE_CG
   set_cg_device(_d3d_device);
 
+  _cg_context = cgCreateContext();
+
   if (cgD3D9IsProfileSupported(CG_PROFILE_PS_2_0) &&
       cgD3D9IsProfileSupported(CG_PROFILE_VS_2_0)) {
     _supports_basic_shaders = true;
@@ -2388,7 +2396,6 @@ reset() {
   }
 
   if (dxgsg9_cat.is_debug()) {
-
     CGprofile vertex_profile;
     CGprofile pixel_profile;
 
@@ -2408,8 +2415,8 @@ reset() {
     }
 
     dxgsg9_cat.debug()
-      << "\nCg vertex profile = " << vertex_profile_str << "  id = " << vertex_profile
-      << "\nCg pixel profile = " << pixel_profile_str << "  id = " << pixel_profile
+      << "\nCg latest vertex profile = " << vertex_profile_str << "  id = " << vertex_profile
+      << "\nCg latest pixel profile = " << pixel_profile_str << "  id = " << pixel_profile
       << "\nshader model = " << _shader_model
       << "\n";
   }
@@ -4152,6 +4159,12 @@ close_gsg() {
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian9::
 free_nondx_resources() {
+#ifdef HAVE_CG
+  if (_cg_context) {
+    cgDestroyContext(_cg_context);
+    _cg_context = 0;
+  }
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5628,9 +5641,6 @@ set_cg_device(LPDIRECT3DDEVICE9 cg_device) {
 #endif // HAVE_CG
 }
 
-
-
-
 typedef string KEY;
 
 typedef struct _KEY_ELEMENT

+ 3 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -377,7 +377,10 @@ protected:
 
   int _supports_gamma_calibration;
 
+#ifdef HAVE_CG
+  CGcontext _cg_context;
   static LPDIRECT3DDEVICE9 _cg_device;
+#endif
 
 public:
   virtual TypeHandle get_type() const {

+ 5 - 6
panda/src/dxgsg9/dxShaderContext9.I

@@ -12,6 +12,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXShaderContext9::valid
 //       Access: Public
@@ -22,12 +23,10 @@
 //               or if no shader languages are compiled into panda.
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(ShaderContext)::
-valid (GSG *gsg) {
+valid(GSG *gsg) {
 #ifdef HAVE_CG
-  if (_cg_context) {
-    return true;
-  }
-#endif
+  return (_cg_program != 0);
+#else
   return false;
+#endif
 }
-

+ 28 - 113
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -22,8 +22,9 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+
 #ifdef HAVE_CG
-#include "Cg/cgD3D9.h"
+#include <Cg/cgD3D9.h>
 #endif
 
 #define DEBUG_SHADER 0
@@ -37,89 +38,42 @@ TypeHandle CLP(ShaderContext)::_type_handle;
 ////////////////////////////////////////////////////////////////////
 CLP(ShaderContext)::
 CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
-
   _vertex_element_array = NULL;
   _vertex_declaration = NULL;
 
   _num_bound_streams = 0;
 
-  _name = s->get_filename ( );
+  _name = s->get_filename();
 
 #ifdef HAVE_CG
-  _cg_context = 0;
+  CGcontext context = DCAST(DXGraphicsStateGuardian9, gsg)->_cg_context;
+
   if (s->get_language() == Shader::SL_Cg) {
 
     // Ask the shader to compile itself for us and
     // to give us the resulting Cg program objects.
-
-    if (!s->cg_compile_for(gsg->_shader_caps,
-                           _cg_context,
-                           _cg_vprogram,
-                           _cg_fprogram,
-                           _cg_gprogram,        // CG2 CHANGE
-                           _cg_parameter_map)) {
+    if (!s->cg_compile_for(gsg->_shader_caps, context,
+                           _cg_program, _cg_parameter_map)) {
       return;
     }
 
     // Load the program.
-
-    BOOL paramater_shadowing;
-    DWORD assembly_flags;
-
-    paramater_shadowing = FALSE;
-    assembly_flags = 0;
-
+    DWORD assembly_flags = 0;
 #if DEBUG_SHADER
     assembly_flags |= D3DXSHADER_DEBUG;
 #endif
 
     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);
+    hr = cgD3D9LoadProgram(_cg_program, FALSE, assembly_flags);
     if (FAILED (hr)) {
       dxgsg9_cat.error()
-        << "pixel shader cgD3D9LoadProgram failed "
-        << D3DERRORSTRING(hr);
+        << "cgD3D9LoadProgram failed " << D3DERRORSTRING(hr);
 
       CGerror error = cgGetError();
       if (error != CG_NO_ERROR) {
         dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
       }
-      success = false;
-    }
-
-    // BEGIN CG2 CHANGE
-    if (_cg_gprogram != 0)
-    {
-        hr = cgD3D9LoadProgram(_cg_gprogram, paramater_shadowing, assembly_flags);
-        if (FAILED (hr)) {
-          dxgsg9_cat.error()
-            << "geometry shader cgD3D9LoadProgram failed "
-            << D3DERRORSTRING(hr);
-
-          CGerror error = cgGetError();
-          if (error != CG_NO_ERROR) {
-            dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
-          }
-          success = false;
-        }
-    }
-    // END CG2 CHANGE
-
-    if (!success) {
       release_resources();
     }
   }
@@ -203,12 +157,9 @@ CLP(ShaderContext)::
 void CLP(ShaderContext)::
 release_resources() {
 #ifdef HAVE_CG
-  if (_cg_context) {
-    cgDestroyContext(_cg_context);
-    _cg_context = 0;
-    _cg_vprogram = 0;
-    _cg_fprogram = 0;
-    _cg_gprogram = 0;   // CG2 CHANGE
+  if (_cg_program) {
+    cgDestroyProgram(_cg_program);
+    _cg_program = 0;
     _cg_parameter_map.clear();
   }
 #endif
@@ -228,11 +179,10 @@ release_resources() {
 bool CLP(ShaderContext)::
 bind(GSG *gsg) {
 
-  bool bind_state;
+  bool bind_state = false;
 
-  bind_state = false;
 #ifdef HAVE_CG
-  if (_cg_context) {
+  if (_cg_program) {
     // clear the last cached FVF to make sure the next SetFVF call goes through
 
     gsg -> _last_fvf = 0;
@@ -244,20 +194,9 @@ bind(GSG *gsg) {
 
     // 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);
+    hr = cgD3D9BindProgram(_cg_program);
     if (FAILED (hr)) {
-      dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr);
+      dxgsg9_cat.error() << "cgD3D9BindProgram failed " << D3DERRORSTRING(hr);
 
       CGerror error = cgGetError();
       if (error != CG_NO_ERROR) {
@@ -266,23 +205,6 @@ bind(GSG *gsg) {
 
       bind_state = false;
     }
-
-    // BEGIN CG2 CHANGE
-    if (_cg_gprogram != 0)
-    {
-        hr = cgD3D9BindProgram(_cg_gprogram);
-        if (FAILED (hr)) {
-          dxgsg9_cat.error() << "cgD3D9BindProgram geometry shader failed " << D3DERRORSTRING(hr);
-
-          CGerror error = cgGetError();
-          if (error != CG_NO_ERROR) {
-            dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
-          }
-
-          bind_state = false;
-        }
-    }
-    // END CG2 CHANGE
   }
 #endif
 
@@ -298,18 +220,12 @@ void CLP(ShaderContext)::
 unbind(GSG *gsg) {
 
 #ifdef HAVE_CG
-  if (_cg_context) {
+  if (_cg_program) {
     HRESULT hr;
-
-    hr = gsg -> _d3d_device -> SetVertexShader (NULL);
-    if (FAILED (hr)) {
+    hr = cgD3D9UnbindProgram(_cg_program);
+    if (FAILED(hr)) {
       dxgsg9_cat.error()
-        << "SetVertexShader (NULL) failed " << D3DERRORSTRING(hr);
-    }
-    hr = gsg -> _d3d_device -> SetPixelShader (NULL);
-    if (FAILED (hr)) {
-      dxgsg9_cat.error()
-        << "SetPixelShader (NULL) failed " << D3DERRORSTRING(hr);
+        << "cgD3D9UnbindProgram failed " << D3DERRORSTRING(hr);
     }
   }
 #endif
@@ -339,10 +255,9 @@ InternalName *global_internal_name_1 = 0;
 #endif
 
 void CLP(ShaderContext)::
-issue_parameters(GSG *gsg, int altered)
-{
+issue_parameters(GSG *gsg, int altered) {
 #ifdef HAVE_CG
-  if (_cg_context) {
+  if (_cg_program) {
 
   // Iterate through _ptr parameters
     for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
@@ -510,7 +425,7 @@ bool CLP(ShaderContext)::
 update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) {
   if (prev) prev->disable_shader_vertex_arrays(gsg);
 #ifdef HAVE_CG
-  if (!_cg_context) {
+  if (!_cg_program) {
     return true;
   }
 
@@ -717,11 +632,11 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) {
 
     if (( _vertex_element_array != NULL ) &&
         ( _vertex_element_array->add_end_vertex_element() != false )) {
-      if ( dxgsg9_cat.is_debug() ) {
+      if (dxgsg9_cat.is_debug()) {
         // Note that the currently generated vertex declaration works but never validates.
         // My theory is that this is due to the shader programs always using float4 whereas
         // the vertex declaration correctly sets the number of inputs (float2, float3, etc.).
-        if (cgD3D9ValidateVertexDeclaration(_cg_vprogram,
+        if (cgD3D9ValidateVertexDeclaration(_cg_program,
                                             _vertex_element_array->_vertex_element_array) == CG_TRUE) {
           dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration succeeded\n";
         } else {
@@ -763,7 +678,7 @@ void CLP(ShaderContext)::
 disable_shader_texture_bindings(GSG *gsg)
 {
 #ifdef HAVE_CG
-  if (_cg_context) {
+  if (_cg_program) {
     for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
       CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
       if (p == NULL) {
@@ -803,7 +718,7 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg)
   if (prev) prev->disable_shader_texture_bindings(gsg);
 
 #ifdef HAVE_CG
-  if (_cg_context) {
+  if (_cg_program) {
 
     for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
       CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];

+ 6 - 18
panda/src/dxgsg9/dxShaderContext9.h

@@ -22,11 +22,9 @@
 #include "shader.h"
 #include "shaderContext.h"
 
-
 #define CLP(name) DX##name##9
 #define CLASSPREFIX_QUOTED "DX"
 
-
 class VertexElementArray;
 class CLP(GraphicsStateGuardian);
 
@@ -41,7 +39,7 @@ class CLP(GraphicsStateGuardian);
 //   D3DXCONSTANT_DESC *constant_description_array;
 // }
 // DX_PARAMETER;
-// 
+//
 // typedef struct
 // {
 //   int state;
@@ -52,7 +50,7 @@ class CLP(GraphicsStateGuardian);
 //   };
 //   LPD3DXCONSTANTTABLE constant_table;
 //   D3DXCONSTANTTABLE_DESC constant_table_description;
-// 
+//
 //   int total_semantics;
 //   D3DXSEMANTIC *semantic_array;
 // }
@@ -62,11 +60,10 @@ class CLP(GraphicsStateGuardian);
 //       Class : DXShaderContext9
 // Description : xyz
 ////////////////////////////////////////////////////////////////////
-
-class EXPCL_PANDADX CLP(ShaderContext): public ShaderContext {
+class EXPCL_PANDADX CLP(ShaderContext) : public ShaderContext {
 public:
   typedef CLP(GraphicsStateGuardian) GSG;
-  
+
   CLP(ShaderContext)(Shader *s, GSG *gsg);
   ~CLP(ShaderContext)();
 
@@ -88,23 +85,14 @@ public:
 
   // FOR DEBUGGING
   string _name;
-  
-private:
 
+private:
 #ifdef HAVE_CG
-  CGcontext _cg_context;
-  CGprogram _cg_vprogram;
-  CGprogram _cg_fprogram;
-
-  // BEGIN CG2 CHANGE
-  CGprogram _cg_gprogram;   // Geometry program
-  // END CG2 CHANGE
-
+  CGprogram _cg_program;
   pvector <CGparameter> _cg_parameter_map;
 #endif
 
 private:
-
   void release_resources(void);
 
 public:

+ 1 - 2
panda/src/glstuff/glCgShaderContext_src.I

@@ -27,8 +27,7 @@ INLINE bool CLP(CgShaderContext)::
 valid() {
   if (_shader->get_error_flag()) return false;
   if (_shader->get_language() != Shader::SL_Cg) return false;
-  if (_cg_context) return true;
-  return false;
+  return (_cg_program != 0);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 117 - 95
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -40,63 +40,40 @@ TypeHandle CLP(CgShaderContext)::_type_handle;
 CLP(CgShaderContext)::
 CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
   _glgsg = glgsg;
-  _cg_context = 0;
-  _cg_vprogram = 0;
-  _cg_fprogram = 0;
-  _cg_gprogram = 0;
-  _cg_vprofile = CG_PROFILE_UNKNOWN;
-  _cg_fprofile = CG_PROFILE_UNKNOWN;
-  _cg_gprofile = CG_PROFILE_UNKNOWN;
+  _cg_program = 0;
+  _glsl_profile = false;
 
   nassertv(s->get_language() == Shader::SL_Cg);
 
+  CGcontext context = _glgsg->_cg_context;
+
   // Ask the shader to compile itself for us and
   // to give us the resulting Cg program objects.
-  if (!s->cg_compile_for(_glgsg->_shader_caps,
-                         _cg_context,
-                         _cg_vprogram,
-                         _cg_fprogram,
-                         _cg_gprogram,
-                         _cg_parameter_map)) {
+  if (!s->cg_compile_for(_glgsg->_shader_caps, context,
+                         _cg_program, _cg_parameter_map)) {
     return;
   }
 
   // Load the program.
-  if (_cg_vprogram != 0) {
-    _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
-    cgGLLoadProgram(_cg_vprogram);
-    CGerror verror = cgGetError();
-    if (verror != CG_NO_ERROR) {
-      const char *str = cgGetErrorString(verror);
-      GLCAT.error()
-        << "Could not load Cg vertex program: " << s->get_filename(Shader::ST_vertex)
-        << " (" << cgGetProfileString(_cg_vprofile) << " " << str << ")\n";
-      release_resources();
+  if (_cg_program == 0) {
+    const char *str = cgGetErrorString(cgGetError());
+    GLCAT.error()
+      << "Could not combine Cg program: " << s->get_filename()
+      << " (" << str << ")\n";
+    release_resources();
+
+  } else {
+    if (cgGetProgramProfile(_cg_program) == CG_PROFILE_GLSLC) {
+      _glsl_profile = true;
     }
-  }
 
-  if (_cg_fprogram != 0) {
-    _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
-    cgGLLoadProgram(_cg_fprogram);
-    CGerror ferror = cgGetError();
-    if (ferror != CG_NO_ERROR) {
-      const char *str = cgGetErrorString(ferror);
+    cgGLLoadProgram(_cg_program);
+    CGerror error = cgGetError();
+    if (error != CG_NO_ERROR) {
+      const char *str = cgGetErrorString(error);
       GLCAT.error()
-        << "Could not load Cg fragment program: " << s->get_filename(Shader::ST_fragment)
-        << " (" << cgGetProfileString(_cg_fprofile) << " " << str << ")\n";
-      release_resources();
-    }
-  }
-
-  if (_cg_gprogram != 0) {
-    _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
-    cgGLLoadProgram(_cg_gprogram);
-    CGerror gerror = cgGetError();
-    if (gerror != CG_NO_ERROR) {
-      const char *str = cgGetErrorString(gerror);
-      GLCAT.error()
-        << "Could not load Cg geometry program: " << s->get_filename(Shader::ST_geometry)
-        << " (" << cgGetProfileString(_cg_gprofile) << " " << str << ")\n";
+        << "Could not load program: " << s->get_filename()
+        << " (" << str << ")\n";
       release_resources();
     }
   }
@@ -122,20 +99,14 @@ CLP(CgShaderContext)::
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 release_resources() {
-  if (_cg_context) {
-    cgDestroyContext(_cg_context);
-    _cg_context  = 0;
-    // Do *NOT* destroy the programs here! It causes problems.
-//  if (_cg_vprogram != 0) cgDestroyProgram(_cg_vprogram);
-//  if (_cg_fprogram != 0) cgDestroyProgram(_cg_fprogram);
-//  if (_cg_gprogram != 0) cgDestroyProgram(_cg_gprogram);
-    _cg_vprogram = 0;
-    _cg_fprogram = 0;
-    _cg_gprogram = 0;
-    _cg_parameter_map.clear();
+  if (_cg_program != 0) {
+    cgDestroyProgram(_cg_program);
+    _cg_program = 0;
   }
+  _cg_parameter_map.clear();
   if (_glgsg) {
     _glgsg->report_my_gl_errors();
+
   } else if (glGetError() != GL_NO_ERROR) {
     GLCAT.error() << "GL error in ShaderContext destructor\n";
   }
@@ -155,25 +126,15 @@ release_resources() {
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 bind(bool reissue_parameters) {
-  if (reissue_parameters) {
-    // Pass in k-parameters and transform-parameters
-    issue_parameters(Shader::SSD_general);
-  }
+  if (_cg_program != 0) {
+    if (reissue_parameters) {
+      // Pass in k-parameters and transform-parameters
+      issue_parameters(Shader::SSD_general);
+    }
 
-  if (_cg_context != 0) {
     // Bind the shaders.
-    if (_cg_vprogram != 0) {
-      cgGLEnableProfile(_cg_vprofile);
-      cgGLBindProgram(_cg_vprogram);
-    }
-    if (_cg_fprogram != 0) {
-      cgGLEnableProfile(_cg_fprofile);
-      cgGLBindProgram(_cg_fprogram);
-    }
-    if (_cg_gprogram != 0) {
-      cgGLEnableProfile(_cg_gprofile);
-      cgGLBindProgram(_cg_gprogram);
-    }
+    cgGLEnableProgramProfiles(_cg_program);
+    cgGLBindProgram(_cg_program);
 
     cg_report_errors();
     _glgsg->report_my_gl_errors();
@@ -187,18 +148,12 @@ bind(bool reissue_parameters) {
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 unbind() {
-  if (_cg_context != 0) {
-    if (_cg_vprogram != 0) {
-      cgGLUnbindProgram(_cg_vprofile);
-      cgGLDisableProfile(_cg_vprofile);
-    }
-    if (_cg_fprogram != 0) {
-      cgGLUnbindProgram(_cg_fprofile);
-      cgGLDisableProfile(_cg_fprofile);
-    }
-    if (_cg_gprogram != 0) {
-      cgGLUnbindProgram(_cg_gprofile);
-      cgGLDisableProfile(_cg_gprofile);
+  if (_cg_program != 0) {
+    int num_domains = cgGetNumProgramDomains(_cg_program);
+    for (int i = 0; i < num_domains; ++i) {
+      CGprofile profile = cgGetProgramDomainProfile(_cg_program, i);
+      cgGLUnbindProgram(profile);
+      cgGLDisableProfile(profile);
     }
 
     cg_report_errors();
@@ -396,7 +351,25 @@ disable_shader_vertex_arrays() {
   for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
     CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
     if (p == 0) continue;
-    cgGLDisableClientState(p);
+
+    if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) {
+      int index = cgGetParameterResourceIndex(p);
+      if (index >= 8) {
+        _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+      } else if (index == 0) {
+        glDisableClientState(GL_VERTEX_ARRAY);
+
+      } else if (index == 2) {
+        glDisableClientState(GL_NORMAL_ARRAY);
+
+      } else if (index == 3) {
+        glDisableClientState(GL_COLOR_ARRAY);
+      }
+    } else {
+      cgGLDisableClientState(p);
+    }
   }
 
   cg_report_errors();
@@ -464,20 +437,68 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
 
         if (numeric_type == GeomEnums::NT_packed_dabc) {
-          cgGLSetParameterPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
-                                  stride, client_pointer + start);
+          // Yes, this is a thing.
+          num_values = GL_BGRA;
+        }
+
+        // This is truly the most preposterous hack.  When using the GLSL
+        // profiles, cgGLSetParameterPointer relies on the the driver mapping
+        // standard attributes to fixed indices (and breaking the spec doing
+        // so), which only the NVIDIA drivers do.  Unbelievable.
+        if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) {
+          int index = cgGetParameterResourceIndex(p);
+          switch (index) {
+          case 0:  // gl_Vertex
+            glVertexPointer(num_values, _glgsg->get_numeric_type(numeric_type),
+                            stride, client_pointer + start);
+            glEnableClientState(GL_VERTEX_ARRAY);
+            break;
+
+          case 2:  // gl_Normal
+            glNormalPointer(_glgsg->get_numeric_type(numeric_type),
+                            stride, client_pointer + start);
+            glEnableClientState(GL_NORMAL_ARRAY);
+            break;
+
+          case 3:  // gl_Color
+            glColorPointer(num_values, _glgsg->get_numeric_type(numeric_type),
+                           stride, client_pointer + start);
+            glEnableClientState(GL_COLOR_ARRAY);
+            break;
+
+          case 4:  // gl_SecondaryColor
+            //glSecondaryColorPointer(num_values, _glgsg->get_numeric_type(numeric_type),
+            //                        stride, client_pointer + start);
+            //glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
+            //break;
+          case 5:  // gl_FogCoord
+          case 6:  // PSIZE?
+          case 7:  // BLENDINDICES?
+          case 1:  // glWeightPointerARB?
+            GLCAT.error()
+              << "Unable to bind " << *name << " to "
+              << cgGetParameterResourceName(p) << "\n";
+            break;
+
+          default:
+            _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
+            glTexCoordPointer(num_values, _glgsg->get_numeric_type(numeric_type),
+                              stride, client_pointer + start);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            break;
+          }
         } else {
           if (name == InternalName::get_normal() && num_values == 4) {
-            // In some cases, the normals are aligned to 4 values.
-            // This would cause an error on some rivers, so we tell it
-            // to use the first three values only.
+            // In some cases, the normals are aligned to 4 values.  We tell
+            // it to use three values exactly, otherwise we get the error:
+            // An unsupported GL extension was required to perform this operation.
             num_values = 3;
           }
-          cgGLSetParameterPointer(p,
-                                  num_values, _glgsg->get_numeric_type(numeric_type),
+          cgGLSetParameterPointer(p, num_values,
+                                  _glgsg->get_numeric_type(numeric_type),
                                   stride, client_pointer + start);
+          cgGLEnableClientState(p);
         }
-        cgGLEnableClientState(p);
       } else {
         CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
         cgGLDisableClientState(p);
@@ -506,6 +527,7 @@ disable_shader_texture_bindings() {
   for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
     CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
     if (p == 0) continue;
+
     int texunit = cgGetParameterResourceIndex(p);
     _glgsg->_glActiveTexture(GL_TEXTURE0 + texunit);
 
@@ -527,7 +549,7 @@ disable_shader_texture_bindings() {
       glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
     }
     // This is probably faster - but maybe not as safe?
-    // cgGLDisableTextureParameter(p);
+    //cgGLDisableTextureParameter(p);
   }
 #endif  // OPENGLES_2
 

+ 5 - 10
panda/src/glstuff/glCgShaderContext_src.h

@@ -1,4 +1,4 @@
-// Filename: glShaderContext_src.h
+// Filename: glCgShaderContext_src.h
 // Created by: jyelon (01Sep05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -51,15 +51,10 @@ public:
   INLINE bool uses_custom_texture_bindings(void);
 
 private:
-  CGcontext _cg_context;
-  CGprogram _cg_vprogram;
-  CGprogram _cg_fprogram;
-  CGprogram _cg_gprogram;
-  CGprofile _cg_vprofile;
-  CGprofile _cg_fprofile;
-  CGprofile _cg_gprofile;
-
-  pvector <CGparameter> _cg_parameter_map;
+  CGprogram _cg_program;
+  bool _glsl_profile;
+
+  pvector<CGparameter> _cg_parameter_map;
 
   CLP(GraphicsStateGuardian) *_glgsg;
 

+ 52 - 22
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -318,6 +318,10 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
   _scissor_enabled = false;
   _scissor_attrib_active = false;
 
+#ifdef HAVE_CG
+  _cg_context = 0;
+#endif
+
 #ifdef DO_PSTATS
   if (gl_finish) {
     GLCAT.warning()
@@ -1083,15 +1087,19 @@ reset() {
     _supports_depth_texture = true;
   }
 
-  if (_supports_depth_texture &&
+  if (gl_support_shadow_filter &&
+      _supports_depth_texture &&
       has_extension("GL_ARB_shadow") &&
       has_extension("GL_ARB_fragment_program_shadow")) {
     _supports_shadow_filter = true;
   }
-  if (_gl_vendor.substr(0,3)=="ATI") {
+  // Actually, we can't keep forever disabling ARB_shadow on ATI cards,
+  // since they do work correctly now.  Maybe there is some feature
+  // level we can check somewhere?
+  /*if (_gl_vendor.substr(0,3)=="ATI") {
     // ATI drivers have never provided correct shadow support.
     _supports_shadow_filter = false;
-  }
+  }*/
 
   _supports_texture_combine =
     has_extension("GL_ARB_texture_env_combine") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1);
@@ -1156,30 +1164,37 @@ reset() {
 
       // cgGLGetLatestProfile doesn't seem to return anything other
       // arbvp1/arbfp1 on non-NVIDIA cards, which is severely limiting.
-      // Actually, it seems that these profiles are horribly broken on these
-      // cards.  Let's not do this.
-      //if ((_shader_caps._active_vprofile == CG_PROFILE_ARBVP1 ||
-      //     _shader_caps._active_fprofile == CG_PROFILE_ARBFP1) &&
-      //    cgGLIsProfileSupported(CG_PROFILE_GLSLV) &&
-      //    cgGLIsProfileSupported(CG_PROFILE_GLSLF)) {
-
-      //  // So, if this happens, we set it to GLSL, which is
-      //  // usually supported on all cards.
-      //  _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
-      //  _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
+      // So, if this happens, we set it to GLSL, which is
+      // usually supported on all cards.
+      // The GLSL profiles are horribly broken on non-NVIDIA cards, but
+      // I think I've worked around the issues sufficiently.
+      if ((_shader_caps._active_vprofile == CG_PROFILE_ARBVP1 ||
+           _shader_caps._active_fprofile == CG_PROFILE_ARBFP1) &&
+          cgGLIsProfileSupported(CG_PROFILE_GLSLV) &&
+          cgGLIsProfileSupported(CG_PROFILE_GLSLF)) {
+
+        _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
+        _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
 #if CG_VERSION_NUM >= 2200
-      //  if (cgGLIsProfileSupported(CG_PROFILE_GLSLG)) {
-      //    _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
-      //  }
+        if (cgGLIsProfileSupported(CG_PROFILE_GLSLG)) {
+          _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
+        }
 #endif
-      //}
+      }
     }
     _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
     _shader_caps._ultimate_gprofile = (int)CG_PROFILE_GPU_GP;
 
-    _glBindProgram = (PFNGLBINDPROGRAMARBPROC)
-      get_extension_func("glBindProgramARB");
+    _cg_context = cgCreateContext();
+
+#if CG_VERSION_NUM >= 3100
+    // This just sounds like a good thing to do.
+    cgGLSetContextGLSLVersion(_cg_context, cgGLDetectGLSLVersion());
+    if (_shader_caps._active_vprofile == CG_PROFILE_GLSLV) {
+      cgGLSetContextOptimalOptions(_cg_context, CG_PROFILE_GLSLC);
+    }
+#endif
 
     // Bug workaround for radeons.
     if (_shader_caps._active_fprofile == CG_PROFILE_ARBFP1) {
@@ -2244,9 +2259,17 @@ reset() {
     }
 #endif  // CG_VERSION_NUM >= 2200
 
+#if CG_VERSION_NUM >= 3100
+    if (GLCAT.is_debug()) {
+      CGGLglslversion ver = cgGLGetContextGLSLVersion(_cg_context);
+      GLCAT.debug()
+        << "Cg GLSL version: " << cgGLGetGLSLVersionString(ver) << "\n";
+    }
+#endif
+
     GLCAT.debug()
-      << "\nCg vertex profile = " << cgGetProfileString(vertex_profile) << "  id = " << vertex_profile
-      << "\nCg pixel profile = " << cgGetProfileString(pixel_profile) << "  id = " << pixel_profile
+      << "\nCg latest vertex profile = " << cgGetProfileString(vertex_profile) << "  id = " << vertex_profile
+      << "\nCg latest pixel profile = " << cgGetProfileString(pixel_profile) << "  id = " << pixel_profile
       << "\nshader model = " << _shader_model
       << "\n";
   }
@@ -2591,6 +2614,7 @@ clear_before_callback() {
   // texture stage is still set to stage 0.  CEGUI, in particular,
   // makes this assumption.
   _glActiveTexture(GL_TEXTURE0);
+  _glClientActiveTexture(GL_TEXTURE0);
 
   // Clear the bound sampler object, so that we do not inadvertently
   // override the callback's desired sampler settings.
@@ -9009,6 +9033,12 @@ set_state_and_transform(const RenderState *target,
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 free_pointers() {
+#ifdef HAVE_CG
+  if (_cg_context != 0) {
+    cgDestroyContext(_cg_context);
+    _cg_context = 0;
+  }
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -568,6 +568,10 @@ protected:
   static PT(Shader)  _default_shader;
 #endif
 
+#ifdef HAVE_CG
+  CGcontext _cg_context;
+#endif
+
 #ifdef SUPPORT_IMMEDIATE_MODE
   CLP(ImmediateModeSender) _sender;
   bool _use_sender;

+ 7 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -265,6 +265,13 @@ ConfigVariableBool gl_support_sampler_objects
             "objects.  Set to false if you suspect a bug in the "
             "driver implementation."));
 
+ConfigVariableBool gl_support_shadow_filter
+  ("gl-support-shadow-filter", true,
+   PRC_DESC("Disable this if you suspect a bug in the driver "
+            "implementation of ARB_shadow.  Particularly, older ATI "
+            "cards suffered from a broken implementation of the "
+            "shadow map filtering features."));
+
 extern ConfigVariableBool gl_parallel_arrays;
 
 void CLP(init_classes)() {

+ 1 - 0
panda/src/glstuff/glmisc_src.h

@@ -74,6 +74,7 @@ extern ConfigVariableBool gl_enable_memory_barriers;
 extern ConfigVariableBool gl_vertex_array_objects;
 extern ConfigVariableBool gl_support_primitive_restart_index;
 extern ConfigVariableBool gl_support_sampler_objects;
+extern ConfigVariableBool gl_support_shadow_filter;
 
 extern EXPCL_GL void CLP(init_classes)();
 

+ 190 - 124
panda/src/gobj/shader.cxx

@@ -27,6 +27,7 @@ TypeHandle Shader::_type_handle;
 Shader::ShaderTable Shader::_load_table;
 Shader::ShaderTable Shader::_make_table;
 Shader::ShaderCaps Shader::_default_caps;
+CGcontext Shader::_cg_context = 0;
 int Shader::_shaders_generated;
 ShaderUtilization Shader::_shader_utilization = SUT_unspecified;
 
@@ -480,46 +481,54 @@ cp_optimize_mat_spec(ShaderMatSpec &spec) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void Shader::cg_recurse_parameters(CGparameter parameter,
-    const ShaderType& type, bool& success) {
+void Shader::
+cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
+                      bool &success) {
 
-  if (parameter == 0)
+  if (parameter == 0) {
     return;
+  }
 
   do {
-    int                arg_dim[]    = {1,0,0};
-    ShaderArgDir       arg_dir      = cg_parameter_dir(parameter);
-    ShaderArgType      arg_type     = cg_parameter_type(parameter);
-    ShaderArgClass     arg_class    = cg_parameter_class(parameter);
-    ShaderArgClass     arg_subclass = arg_class;
-
-    CGenum vbl = cgGetParameterVariability(parameter);
-
-    if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
-      switch (cgGetParameterType(parameter)) {
-        case CG_STRUCT:
-          cg_recurse_parameters(
-            cgGetFirstStructParameter(parameter), type, success);
-          break;
-
-        case CG_ARRAY:
-          arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
-          arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
-
-          arg_dim[0]  = cgGetArraySize(parameter, 0);
-
-        default: {
-          arg_dim[1] = cgGetParameterRows(parameter);
-          arg_dim[2] = cgGetParameterColumns(parameter);
-
-          ShaderArgId id;
-          id._name = cgGetParameterName(parameter);
-          id._type  = type;
-          id._seqno = -1;
-          success &= compile_parameter(id, arg_class, arg_subclass, arg_type,
-              arg_dir, (vbl == CG_VARYING), arg_dim, gobj_cat.get_safe_ptr()); break;
+    if (cgIsParameterReferenced(parameter)) {
+      int                arg_dim[]    = {1,0,0};
+      ShaderArgDir       arg_dir      = cg_parameter_dir(parameter);
+      ShaderArgType      arg_type     = cg_parameter_type(parameter);
+      ShaderArgClass     arg_class    = cg_parameter_class(parameter);
+      ShaderArgClass     arg_subclass = arg_class;
+
+      CGenum vbl = cgGetParameterVariability(parameter);
+
+      if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
+        switch (cgGetParameterType(parameter)) {
+          case CG_STRUCT:
+            cg_recurse_parameters(
+              cgGetFirstStructParameter(parameter), type, success);
+            break;
+
+          case CG_ARRAY:
+            arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
+            arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
+
+            arg_dim[0]  = cgGetArraySize(parameter, 0);
+
+          default: {
+            arg_dim[1] = cgGetParameterRows(parameter);
+            arg_dim[2] = cgGetParameterColumns(parameter);
+
+            ShaderArgId id;
+            id._name = cgGetParameterName(parameter);
+            id._type  = type;
+            id._seqno = -1;
+            success &= compile_parameter(id, arg_class, arg_subclass, arg_type,
+                arg_dir, (vbl == CG_VARYING), arg_dim, gobj_cat.get_safe_ptr()); break;
+          }
         }
       }
+    } else if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Parameter " << cgGetParameterName(parameter)
+        << " is unreferenced within shader " << get_filename(type) << "\n";
     }
   } while((parameter = cgGetNextParameter(parameter))!= 0);
 }
@@ -1375,10 +1384,6 @@ cg_release_resources() {
     cgDestroyProgram(_cg_gprogram);
     _cg_gprogram = 0;
   }
-  if (_cg_context != 0) {
-    cgDestroyContext(_cg_context);
-    _cg_context = 0;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1387,7 +1392,8 @@ cg_release_resources() {
 //  Description: xyz
 ////////////////////////////////////////////////////////////////////
 CGprogram Shader::
-cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type) {
+cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
+                       CGcontext context, ShaderType type) {
   CGprogram prog;
   CGerror err;
   const char *compiler_args[100];
@@ -1457,7 +1463,7 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
     }
 
     // Compile the shader with the active profile.
-    prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
+    prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
                            (CGprofile)active, entry, (const char **)compiler_args);
     err = cgGetError();
     if (err == CG_NO_ERROR) {
@@ -1479,30 +1485,35 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
   }
 
   // The active profile failed, so recompile it with the ultimate profile.
-  prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
+  prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
                          (CGprofile)ultimate, entry, (const char **)NULL);
+
+  // Extract the output listing.
   err = cgGetError();
+  const char *listing = cgGetLastListing(context);
+
+  if (err == CG_NO_ERROR && listing != NULL && strlen(listing) > 1) {
+    gobj_cat.warning()
+      << "Encountered warnings during compilation of " << get_filename(type)
+      << ":\n" << listing;
+
+  } else if (err == CG_COMPILER_ERROR) {
+    gobj_cat.error()
+      << "Failed to compile Cg shader " << get_filename(type);
+    if (listing != NULL) {
+      gobj_cat.error(false) << ":\n" << listing;
+    } else {
+      gobj_cat.error(false) << "!\n";
+    }
+  }
+
   if (err == CG_NO_ERROR) {
     return prog;
   }
-  if (err == CG_COMPILER_ERROR) {
-    // A compiler error has occurred.  Extract the error messages.
-    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() << get_filename(type) << ": " << errlines[i] << "\n";
-      }
-    }
-  } else {
-    gobj_cat.error() << get_filename(type) << ": " << cgGetErrorString(err) << "\n";
-  }
+
   if (prog != 0) {
     cgDestroyProgram(prog);
   }
-
   return 0;
 }
 
@@ -1514,29 +1525,11 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
 //               variables _cg_context, _cg_vprogram, _cg_fprogram.
 ////////////////////////////////////////////////////////////////////
 bool Shader::
-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_compile_shader(const ShaderCaps &caps, CGcontext context) {
   _cg_last_caps = caps;
 
-  _cg_context = cgCreateContext();
-
-  if (_cg_context == 0) {
-    gobj_cat.error() << "Could not create a Cg context object.\n";
-    return false;
-  }
-
   if (!_text._separate || !_text._vertex.empty()) {
-    _cg_vprogram = cg_compile_entry_point("vshader", caps, ST_vertex);
+    _cg_vprogram = cg_compile_entry_point("vshader", caps, context, ST_vertex);
     if (_cg_vprogram == 0) {
       cg_release_resources();
       return false;
@@ -1545,7 +1538,7 @@ cg_compile_shader(const ShaderCaps &caps) {
   }
 
   if (!_text._separate || !_text._fragment.empty()) {
-    _cg_fprogram = cg_compile_entry_point("fshader", caps, ST_fragment);
+    _cg_fprogram = cg_compile_entry_point("fshader", caps, context, ST_fragment);
     if (_cg_fprogram == 0) {
       cg_release_resources();
       return false;
@@ -1554,7 +1547,7 @@ cg_compile_shader(const ShaderCaps &caps) {
   }
 
   if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find("gshader") != string::npos)) {
-    _cg_gprogram = cg_compile_entry_point("gshader", caps, ST_geometry);
+    _cg_gprogram = cg_compile_entry_point("gshader", caps, context, ST_geometry);
     if (_cg_gprogram == 0) {
       cg_release_resources();
       return false;
@@ -1606,7 +1599,7 @@ bool Shader::
 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
   bool success = true;
 
-  cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM),type,success);
+  cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
   return success;
 }
 
@@ -1645,7 +1638,18 @@ cg_analyze_entry_point(CGprogram prog, ShaderType type) {
 bool Shader::
 cg_analyze_shader(const ShaderCaps &caps) {
 
-  if (!cg_compile_shader(caps)) {
+  // Make sure we have a context for analyzing the shader.
+  if (_cg_context == 0) {
+    _cg_context = cgCreateContext();
+    if (_cg_context == 0) {
+      gobj_cat.error()
+        << "Could not create a Cg context object: "
+        << cgGetErrorString(cgGetError()) << "\n";
+      return false;
+    }
+  }
+
+  if (!cg_compile_shader(caps, _cg_context)) {
     return false;
   }
 
@@ -1805,26 +1809,18 @@ cg_program_from_shadertype(ShaderType type) {
 //               longer own them.
 ////////////////////////////////////////////////////////////////////
 bool Shader::
-cg_compile_for(const ShaderCaps &caps,
-               CGcontext &ctx,
-               CGprogram &vprogram,
-               CGprogram &fprogram,
-               CGprogram &gprogram,
-               pvector<CGparameter> &map) {
+cg_compile_for(const ShaderCaps &caps, CGcontext context,
+               CGprogram &combined_program, pvector<CGparameter> &map) {
 
   // Initialize the return values to empty.
-  ctx = 0;
-  vprogram = 0;
-  fprogram = 0;
-  gprogram = 0;
-
+  combined_program = 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.
 
   _default_caps = caps;
-  if (!cg_compile_shader(caps)) {
+  if (!cg_compile_shader(caps, context)) {
     return false;
   }
 
@@ -1850,8 +1846,24 @@ cg_compile_for(const ShaderCaps &caps,
     return false;
   }
 
-  // Build a parameter map.
+  // Gather the programs we will be combining.
+  pvector<CGprogram> programs;
+  if (_cg_vprogram != 0) {
+    programs.push_back(_cg_vprogram);
+  }
+  if (_cg_fprogram != 0) {
+    programs.push_back(_cg_fprogram);
+  }
+  if (_cg_gprogram != 0) {
+    programs.push_back(_cg_gprogram);
+  }
+
+  // Combine the programs.  This can be more optimal than loading them
+  // individually, and it is even necessary for some profiles
+  // (particularly GLSL profiles on non-NVIDIA GPUs).
+  combined_program = cgCombinePrograms(programs.size(), &programs[0]);
 
+  // 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();
@@ -1859,46 +1871,103 @@ cg_compile_for(const ShaderCaps &caps,
 
   map.resize(n_mat + n_tex + n_var + n_ptr);
 
-  for (int i=0; i<n_mat; i++) {
-    const ShaderArgId &id = _mat_spec[i]._id;
+  // This is a bit awkward, we have to go in and seperate out the
+  // combined program, since all the parameter bindings have changed.
+  CGprogram programs_by_type[ST_COUNT];
+  for (int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
+    // Conveniently, the CGdomain enum overlaps with ShaderType.
+    CGprogram program = cgGetProgramDomainProgram(combined_program, i);
+    programs_by_type[cgGetProgramDomain(program)] = program;
+  }
 
-    CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
-    map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
+  for (int i = 0; i < n_mat; ++i) {
+    const ShaderArgId &id = _mat_spec[i]._id;
+    map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
   }
-  for (int i=0; i<n_tex; i++) {
+
+  for (int i = 0; i < n_tex; ++i) {
     const ShaderArgId &id = _tex_spec[i]._id;
-    CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
-    map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
-    if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
-      map[id._seqno] = 0;
+    CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
+
+    if (gobj_cat.is_debug()) {
+      const char *resource = cgGetParameterResourceName(p);
+      if (resource != NULL) {
+        gobj_cat.debug() << "Texture parameter " << id._name
+                         << " is bound to resource " << resource << "\n";
+      }
     }
+    map[id._seqno] = p;
   }
-  for (int i=0; i<n_var; i++) {
+
+  for (int i = 0; i < n_var; ++i) {
     const ShaderArgId &id = _var_spec[i]._id;
+    CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
+
+    const char *resource = cgGetParameterResourceName(p);
+    if (gobj_cat.is_debug() && resource != NULL) {
+      gobj_cat.debug()
+        << "Varying parameter " << id._name << " is bound to resource "
+        << cgGetParameterResourceName(p) << "\n";
+    }
+
+    if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
+      // I really don't know what this means, but it happens when I
+      // use the NORMAL0 semantic instead of NORMAL, or POSITION0
+      // instead of POSITION, etc.  Not catching this results in a
+      // continuous stream of errors at the renderer side.
+      gobj_cat.error()
+        << "Varying parameter " << id._name;
 
-    CGprogram prog = cg_program_from_shadertype(id._type);      // CG2 CHANGE
-    map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
-    if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
-      map[id._seqno] = 0;
+      const char *semantic = cgGetParameterSemantic(p);
+      if (semantic != NULL) {
+        gobj_cat.error(false) << " : " << semantic;
+      }
+      if (resource != NULL) {
+        gobj_cat.error(false) << " (bound to resource " << resource << ")";
+      }
+      gobj_cat.error(false) << " is invalid!\n";
+
+#ifndef NDEBUG
+      // Let's try to give the developer a hint...
+      if (semantic != NULL) {
+        if (strcmp(semantic, "POSITION0") == 0) {
+          gobj_cat.error() << "Try using the semantic POSITION instead of POSITION0.\n";
+        } else if (strcmp(semantic, "NORMAL0") == 0) {
+          gobj_cat.error() << "Try using the semantic NORMAL instead of NORMAL0.\n";
+        } else if (strcmp(semantic, "DIFFUSE0") == 0) {
+          gobj_cat.error() << "Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
+        } else if (strcmp(semantic, "SPECULAR0") == 0) {
+          gobj_cat.error() << "Try using the semantic SPECULAR instead of SPECULAR0.\n";
+        } else if (strcmp(semantic, "FOGCOORD0") == 0) {
+          gobj_cat.error() << "Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
+        } else if (strcmp(semantic, "PSIZE0") == 0) {
+          gobj_cat.error() << "Try using the semantic PSIZE instead of PSIZE0.\n";
+        }
+      }
+#endif  // NDEBUG
+      p = 0;
     }
+    map[id._seqno] = p;
   }
-  for (int i=0; i<n_ptr; i++) {
-    const ShaderArgId &id = _ptr_spec[i]._id;
 
-    CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
-    map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
+  for (int i = 0; i < n_ptr; ++i) {
+    const ShaderArgId &id = _ptr_spec[i]._id;
+    map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
   }
 
   // Transfer ownership of the compiled shader.
-  ctx = _cg_context;
-  vprogram = _cg_vprogram;
-  fprogram = _cg_fprogram;
-  gprogram = _cg_gprogram;
-
-  _cg_context = 0;
-  _cg_vprogram = 0;
-  _cg_fprogram = 0;
-  _cg_gprogram = 0;
+  if (_cg_vprogram != 0) {
+    cgDestroyProgram(_cg_vprogram);
+    _cg_vprogram = 0;
+  }
+  if (_cg_fprogram != 0) {
+    cgDestroyProgram(_cg_fprogram);
+    _cg_fprogram = 0;
+  }
+  if (_cg_gprogram != 0) {
+    cgDestroyProgram(_cg_gprogram);
+    _cg_gprogram = 0;
+  }
 
   _cg_last_caps.clear();
 
@@ -1921,7 +1990,6 @@ Shader(ShaderLanguage lang) :
   _last_modified(0)
 {
 #ifdef HAVE_CG
-  _cg_context = 0;
   _cg_vprogram = 0;
   _cg_fprogram = 0;
   _cg_gprogram = 0;
@@ -2006,9 +2074,7 @@ read(const ShaderFile &sfile) {
     // Determine which language the shader is written in.
     if (_language == SL_Cg) {
 #ifdef HAVE_CG
-      if (!_text._separate) {
-        cg_get_profile_from_header(_default_caps);
-      }
+      cg_get_profile_from_header(_default_caps);
 
       if (!cg_analyze_shader(_default_caps)) {
         gobj_cat.error()

+ 7 - 6
panda/src/gobj/shader.h

@@ -63,6 +63,7 @@ PUBLISHED:
     ST_tess_control,
     ST_tess_evaluation,
     ST_compute,
+    ST_COUNT
   };
 
   enum AutoShaderSwitch {
@@ -472,12 +473,13 @@ private:
   ShaderArgType cg_parameter_type(CGparameter p);
   ShaderArgDir cg_parameter_dir(CGparameter p);
 
-  CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_vertex);
+  CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
+                                   CGcontext context, ShaderType type);
 
   bool cg_analyze_entry_point(CGprogram prog, ShaderType type);
 
   bool cg_analyze_shader(const ShaderCaps &caps);
-  bool cg_compile_shader(const ShaderCaps &caps);
+  bool cg_compile_shader(const ShaderCaps &caps, CGcontext context);
   void cg_release_resources();
   void cg_report_errors();
 
@@ -486,7 +488,7 @@ private:
   void cg_get_profile_from_header(ShaderCaps &caps);
 
   ShaderCaps _cg_last_caps;
-  CGcontext  _cg_context;
+  static CGcontext  _cg_context;
   CGprogram  _cg_vprogram;
   CGprogram  _cg_fprogram;
   CGprogram  _cg_gprogram;
@@ -498,9 +500,8 @@ private:
   CGprogram cg_program_from_shadertype(ShaderType type);
 
 public:
-  bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx,
-                      CGprogram &vprogram, CGprogram &fprogram,
-                      CGprogram &gprogram, pvector<CGparameter> &map);
+  bool cg_compile_for(const ShaderCaps &caps, CGcontext context,
+                      CGprogram &combined_program, pvector<CGparameter> &map);
 
 #endif