glsl: handle same struct redeclaration (v2)
authorDave Airlie <airlied@redhat.com>
Tue, 17 May 2016 00:58:53 +0000 (10:58 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 20 May 2016 01:22:52 +0000 (11:22 +1000)
This works around a bug in older version of UE4, where a shader
defines the same structure twice. Although we aren't sure this is correct
GLSL (it most likely isn't) there are enough UE4 based things out there
we should deal with this.

This drops the error to a warning if the struct names and contents match.

v1.1: do better C++ on record_compare declaration (Rob)
v2: restrict this to desktop GL only (Ian)

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=95005
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
src/compiler/glsl/ast_to_hir.cpp
src/compiler/glsl_types.cpp
src/compiler/glsl_types.h

index b4c6de2a6a1972f46b8da5cf19b197bfb059df77..ecfe684a0f47a58f4df10cd49dc70e521a738a95 100644 (file)
@@ -6918,7 +6918,12 @@ ast_struct_specifier::hir(exec_list *instructions,
       glsl_type::get_record_instance(fields, decl_count, this->name);
 
    if (!state->symbols->add_type(name, t)) {
-      _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
+      const glsl_type *match = state->symbols->get_type(name);
+      /* allow struct matching for desktop GL - older UE4 does this */
+      if (state->is_version(130, 0) && match->record_compare(t, false))
+         _mesa_glsl_warning(& loc, state, "struct `%s' previously defined", name);
+      else
+         _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
    } else {
       const glsl_type **s = reralloc(state, state->user_structures,
                                      const glsl_type *,
index c058283c48df241da36cd593969304454d129425..11f1e85ec1c3be775104a3bd0d1a9c28bbfbd290 100644 (file)
@@ -856,7 +856,7 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
 
 
 bool
-glsl_type::record_compare(const glsl_type *b) const
+glsl_type::record_compare(const glsl_type *b, bool match_locations) const
 {
    if (this->length != b->length)
       return false;
@@ -887,7 +887,7 @@ glsl_type::record_compare(const glsl_type *b) const
       if (this->fields.structure[i].matrix_layout
          != b->fields.structure[i].matrix_layout)
         return false;
-      if (this->fields.structure[i].location
+      if (match_locations && this->fields.structure[i].location
           != b->fields.structure[i].location)
          return false;
       if (this->fields.structure[i].offset
index a47b0ffe5a24858cae3c93cea5b826f088940210..7f9e3184ca913be1aecc357be143c95e95fd54e2 100644 (file)
@@ -740,8 +740,10 @@ struct glsl_type {
     * Compare a record type against another record type.
     *
     * This is useful for matching record types declared across shader stages.
+    * The option to not match locations is to deal with places where the
+    * same struct is defined in a block which has a location set on it.
     */
-   bool record_compare(const glsl_type *b) const;
+   bool record_compare(const glsl_type *b, bool match_locations = true) const;
 
 private: