Browse Source

shaderpipeline: Fix struct support, nested structs

rdb 5 years ago
parent
commit
ae975d38af

+ 13 - 1
panda/src/glstuff/glShaderContext_src.cxx

@@ -3432,6 +3432,16 @@ attach_shader(const ShaderModule *module) {
           sprintf(buf, "p%u", loc);
           compiler.set_name(id, buf);
 
+          // Find out how many locations this parameter occupies.
+          int num_locations = 1;
+          for (size_t i = 0; i < spv->get_num_parameters(); ++i) {
+            const ShaderModule::Variable &var = spv->get_parameter(i);
+            if (var._location == loc) {
+              num_locations = var.type->get_num_parameter_locations();
+              break;
+            }
+          }
+
           // Older versions of OpenGL (ES) do not support explicit uniform
           // locations, and we need to query the locations later.
           if ((!options.es && options.version < 430) ||
@@ -3439,7 +3449,9 @@ attach_shader(const ShaderModule *module) {
             _needs_query_uniform_locations = true;
           }
           else {
-            set_uniform_location(loc, loc);
+            for (int loc2 = loc; loc2 < loc + num_locations; ++loc2) {
+              set_uniform_location(loc2, loc2);
+            }
           }
         }
         else if (sc == spv::StorageClassInput) {

+ 32 - 15
panda/src/gobj/shader.cxx

@@ -1927,6 +1927,8 @@ bind_parameter(const Parameter &param) {
   if (struct_type != nullptr && name_str.empty()) {
     bool success = true;
 
+    int location = param._location;
+
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
@@ -1934,19 +1936,29 @@ bind_parameter(const Parameter &param) {
       Parameter member_param(param);
       member_param._name = member.name;
       member_param._type = member.type;
-      member_param._location += i;
+      member_param._location = location;
       if (!bind_parameter(member_param)) {
         success = false;
       }
+
+      location += member.type->get_num_parameter_locations();
     }
 
     return success;
   }
 
   if (shader_cat.is_debug()) {
-    shader_cat.debug()
-      << "Binding parameter " << name_str << " with type " << *type
-      << " (location=" << param._location << ")\n";
+    int num_locations = type->get_num_parameter_locations();
+    if (num_locations < 2) {
+      shader_cat.debug()
+        << "Binding parameter " << name_str << " with type " << *type
+        << " (location=" << param._location << ")\n";
+    } else {
+      shader_cat.debug()
+        << "Binding parameter " << name_str << " with type " << *type
+        << " (location=" << param._location << ".."
+        << param._location + num_locations - 1 << ")\n";
+    }
   }
 
   // Split it at the underscores.
@@ -3070,6 +3082,8 @@ bind_parameter(const Parameter &param) {
     // Is this a struct?  If so, bind the individual members.
     bool success = true;
 
+    int location = param._location;
+
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
@@ -3087,7 +3101,7 @@ bind_parameter(const Parameter &param) {
         // We can't know yet, so we always have to handle it specially.
         ShaderMatSpec bind;
         bind._id = param;
-        bind._id._location += i;
+        bind._id._location = location;
         if (member.name == "shadowMatrix" && dim[1] == 4 && dim[2] == 4) {
           // Special exception for shadowMatrix, which is deprecated because it
           // includes the model transformation.  It is far more efficient to do
@@ -3137,17 +3151,18 @@ bind_parameter(const Parameter &param) {
           bind._arg[1] = nullptr;
         }
         cp_add_mat_spec(bind);
-        continue;
       }
-
-      // Otherwise, recurse.
-      Parameter member_param(param);
-      member_param._name = fqname;
-      member_param._type = member.type;
-      member_param._location += i;
-      if (!bind_parameter(member_param)) {
-        success = false;
+      else {
+        // Otherwise, recurse.
+        Parameter member_param(param);
+        member_param._name = fqname;
+        member_param._type = member.type;
+        member_param._location = location;
+        if (!bind_parameter(member_param)) {
+          success = false;
+        }
       }
+      location += member.type->get_num_parameter_locations();
     }
 
     return success;
@@ -3176,10 +3191,12 @@ bind_parameter(const Parameter &param) {
           Parameter member_param(param);
           member_param._name = elemname->append(member.name);
           member_param._type = member.type;
-          member_param._location = location++;
+          member_param._location = location;
           if (!bind_parameter(member_param)) {
             success = false;
           }
+
+          location += member.type->get_num_parameter_locations();
         }
       }
       return success;

+ 41 - 0
tests/display/test_glsl_shader.py

@@ -430,6 +430,47 @@ def test_glsl_struct(gsg):
     })
 
 
+def test_glsl_struct_nested(gsg):
+    preamble = """
+    struct TestSubStruct1 {
+        float a;
+        float b;
+    };
+    struct TestSubStruct2 {
+        float unused;
+        sampler2D a;
+        vec2 b;
+    };
+    uniform struct TestStruct {
+        vec3 a;
+        TestSubStruct1 b;
+        TestSubStruct2 c;
+        float d;
+    } test;
+    """
+    code = """
+    assert(test.a == vec3(1, 2, 3));
+    assert(test.b.a == 4);
+    assert(test.b.b == 5);
+    assert(texture(test.c.a, vec2(0, 0)).r == 6);
+    assert(test.c.b == vec2(7, 8));
+    assert(test.d == 9);
+    """
+    tex_c_a = core.Texture()
+    tex_c_a.setup_2d_texture(1, 1, core.Texture.T_float, core.Texture.F_r32)
+    tex_c_a.set_clear_color((6, 0, 0, 0))
+    run_glsl_test(gsg, code, preamble, {
+        'test.unused': 0,
+        'test.a': (1, 2, 3),
+        'test.b.a': 4,
+        'test.b.b': 5,
+        'test.c.unused': 0,
+        'test.c.a': tex_c_a,
+        'test.c.b': (7, 8),
+        'test.d': 9,
+    })
+
+
 def test_glsl_struct_array(gsg):
     preamble = """
     uniform struct TestStruct {