Browse Source

Better type matching (and error reporting) for GLSL shader inputs

rdb 10 years ago
parent
commit
b894954fda
1 changed files with 115 additions and 16 deletions
  1. 115 16
      panda/src/glstuff/glShaderContext_src.cxx

+ 115 - 16
panda/src/glstuff/glShaderContext_src.cxx

@@ -689,6 +689,26 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
                 case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
                 case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
                 case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
               }
               }
+              switch (param_type) {
+              case GL_BOOL:
+              case GL_BOOL_VEC2:
+              case GL_BOOL_VEC3:
+              case GL_BOOL_VEC4:
+              case GL_INT:
+              case GL_INT_VEC2:
+              case GL_INT_VEC3:
+              case GL_INT_VEC4:
+                bind._type = Shader::SPT_int;
+                break;
+              case GL_FLOAT:
+              case GL_FLOAT_VEC2:
+              case GL_FLOAT_VEC3:
+              case GL_FLOAT_VEC4:
+              case GL_FLOAT_MAT3:
+              case GL_FLOAT_MAT4:
+                bind._type = Shader::SPT_float;
+                break;
+              }
               bind._arg = InternalName::make(param_name);
               bind._arg = InternalName::make(param_name);
               bind._dim[0] = 1;
               bind._dim[0] = 1;
               bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
               bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@@ -767,6 +787,26 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
               case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
               case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
               case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
             }
             }
+            switch (param_type) {
+            case GL_BOOL:
+            case GL_BOOL_VEC2:
+            case GL_BOOL_VEC3:
+            case GL_BOOL_VEC4:
+            case GL_INT:
+            case GL_INT_VEC2:
+            case GL_INT_VEC3:
+            case GL_INT_VEC4:
+              bind._type = Shader::SPT_int;
+              break;
+            case GL_FLOAT:
+            case GL_FLOAT_VEC2:
+            case GL_FLOAT_VEC3:
+            case GL_FLOAT_VEC4:
+            case GL_FLOAT_MAT3:
+            case GL_FLOAT_MAT4:
+              bind._type = Shader::SPT_float;
+              break;
+            }
             bind._arg = InternalName::make(param_name);
             bind._arg = InternalName::make(param_name);
             bind._dim[0] = param_size;
             bind._dim[0] = param_size;
             bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
             bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@@ -1002,46 +1042,97 @@ issue_parameters(int altered) {
   }
   }
 
 
   // Iterate through _ptr parameters
   // Iterate through _ptr parameters
-  for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
-    const Shader::ShaderPtrSpec& spec = _shader->_ptr_spec[i];
+  for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
+    Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
 
 
     if (altered & (spec._dep[0] | spec._dep[1])) {
     if (altered & (spec._dep[0] | spec._dep[1])) {
-      Shader::ShaderPtrData* ptr_data =
-        const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(spec));
+      const Shader::ShaderPtrData* ptr_data = _glgsg->fetch_ptr_parameter(spec);
       if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
       if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
         release_resources();
         release_resources();
         return;
         return;
       }
       }
 
 
       GLint p = _glsl_parameter_map[spec._id._seqno];
       GLint p = _glsl_parameter_map[spec._id._seqno];
-      switch (ptr_data->_type) {
+      switch (spec._type) {
       case Shader::SPT_float:
       case Shader::SPT_float:
-        switch (spec._dim[1]) {
+        {
+          float *data = NULL;
+
+          switch (ptr_data->_type) {
+          case Shader::SPT_int:
+            // Convert int data to float data.
+            data = (float*) alloca(sizeof(float) * spec._dim[0] * spec._dim[1]);
+            for (int i = 0; i < (spec._dim[0] * spec._dim[1]); ++i) {
+              data[i] = (int)(((float*)ptr_data->_ptr)[i]);
+            }
+            break;
+
+          case Shader::SPT_double:
+            // Downgrade double data to float data.
+            data = (float*) alloca(sizeof(float) * spec._dim[0] * spec._dim[1]);
+            for (int i = 0; i < (spec._dim[0] * spec._dim[1]); ++i) {
+              data[i] = (float)(((double*)ptr_data->_ptr)[i]);
+            }
+            break;
+
+          case Shader::SPT_float:
+            data = (float*)ptr_data->_ptr;
+            break;
+
+          default:
+            nassertd(false) continue;
+          }
+
+          switch (spec._dim[1]) {
           case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
           case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
           case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
           case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
           case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
+          }
+          nassertd(false) continue;
         }
         }
+        break;
+
       case Shader::SPT_int:
       case Shader::SPT_int:
-        switch (spec._dim[1]) {
+        if (ptr_data->_type != Shader::SPT_int) {
+          GLCAT.error()
+            << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+          // Deactivate it to make sure the user doesn't get flooded with this error.
+          spec._dep[0] = 0;
+          spec._dep[1] = 0;
+
+        } else {
+          switch (spec._dim[1]) {
           case 1: _glgsg->_glUniform1iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 1: _glgsg->_glUniform1iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 2: _glgsg->_glUniform2iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 2: _glgsg->_glUniform2iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 3: _glgsg->_glUniform3iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 3: _glgsg->_glUniform3iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 4: _glgsg->_glUniform4iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
           case 4: _glgsg->_glUniform4iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
+          }
+          nassertd(false) continue;
         }
         }
+        break;
+
       case Shader::SPT_double:
       case Shader::SPT_double:
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
+
+        // Deactivate it to make sure the user doesn't get flooded with this error.
+        spec._dep[0] = 0;
+        spec._dep[1] = 0;
+
       default:
       default:
         continue;
         continue;
       }
       }
     }
     }
   }
   }
 
 
-  for (int i=0; i<(int)_shader->_mat_spec.size(); i++) {
-    if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
-      const LMatrix4 *val = _glgsg->fetch_specified_value(_shader->_mat_spec[i], altered);
+  for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
+    Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+
+    if (altered & (spec._dep[0] | spec._dep[1])) {
+      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered);
       if (!val) continue;
       if (!val) continue;
 #ifndef STDFLOAT_DOUBLE
 #ifndef STDFLOAT_DOUBLE
       // In this case, the data is already single-precision.
       // In this case, the data is already single-precision.
@@ -1052,8 +1143,8 @@ issue_parameters(int altered) {
       const PN_float32 *data = valf.get_data();
       const PN_float32 *data = valf.get_data();
 #endif
 #endif
 
 
-      GLint p = _glsl_parameter_map[_shader->_mat_spec[i]._id._seqno];
-      switch (_shader->_mat_spec[i]._piece) {
+      GLint p = _glsl_parameter_map[spec._id._seqno];
+      switch (spec._piece) {
       case Shader::SMP_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue;
       case Shader::SMP_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue;
       case Shader::SMP_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue;
       case Shader::SMP_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue;
       case Shader::SMP_col0: _glgsg->_glUniform4f(p, data[0], data[4], data[ 8], data[12]); continue;
       case Shader::SMP_col0: _glgsg->_glUniform4f(p, data[0], data[4], data[ 8], data[12]); continue;
@@ -1400,8 +1491,9 @@ update_shader_texture_bindings(ShaderContext *prev) {
   nassertv(texattrib != (TextureAttrib *)NULL);
   nassertv(texattrib != (TextureAttrib *)NULL);
 
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
-    const InternalName *id = _shader->_tex_spec[i]._name;
-    int texunit = _shader->_tex_spec[i]._stage;
+    const Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
+    const InternalName *id = spec._name;
+    int texunit = spec._stage;
 
 
     Texture *tex = NULL;
     Texture *tex = NULL;
     int view = _glgsg->get_current_tex_view_offset();
     int view = _glgsg->get_current_tex_view_offset();
@@ -1422,16 +1514,23 @@ update_shader_texture_bindings(ShaderContext *prev) {
       view += stage->get_tex_view_offset();
       view += stage->get_tex_view_offset();
     }
     }
 
 
-    if (tex == NULL || tex->get_texture_type() != _shader->_tex_spec[i]._desired_type) {
+    if (tex == NULL) {
       continue;
       continue;
     }
     }
 
 
+    if (tex->get_texture_type() != spec._desired_type) {
+      GLCAT.error()
+        << "Sampler type of GLSL shader input '" << *id << "' does not "
+           "match type of texture " << *tex << ".\n";
+      //TODO: also check whether shadow sampler textures have shadow filter enabled.
+    }
+
     CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
     CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
     if (gtc == NULL) {
     if (gtc == NULL) {
       continue;
       continue;
     }
     }
 
 
-    GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
+    GLint p = _glsl_parameter_map[spec._id._seqno];
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
     // If it was recently written to, we will have to issue a memory barrier soon.
     // If it was recently written to, we will have to issue a memory barrier soon.