D3D11: Fix varying packing with structs.

Previously we would try to pass an entire struct through HLSL's
shader interface. Instead, split this off as if each field was
its own variable, which seems to be spec compliant (see ESSL 3.10).

In the future we may want to fix register packing to use specific
components of float4/int4/uint4 HLSL registers. This could also fix
the remaining bugs in the SM3 packing.

TEST=dEQP-GLES3.functional.shaders.linkage.varying.*
BUG=angleproject:910
BUG=angleproject:1202

Change-Id: I1fd8b4505abc39bd2385ed5c088c316d55d0bc2c
Reviewed-on: https://chromium-review.googlesource.com/311242
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 58ac5f8..30020b7 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -104,7 +104,7 @@
 // true if varying x has a higher priority in packing than y
 bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
 {
-    return gl::CompareVarying(*x.varying, *y.varying);
+    return gl::CompareShaderVar(*x.varying, *y.varying);
 }
 
 std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader,
@@ -127,7 +127,20 @@
         {
             if (output.name == input.name)
             {
-                packedVaryings.push_back(PackedVarying(input));
+                if (output.isStruct())
+                {
+                    ASSERT(!output.isArray());
+                    for (const auto &field : output.fields)
+                    {
+                        ASSERT(!field.isStruct() && !field.isArray());
+                        packedVaryings.push_back(
+                            PackedVarying(field, input.interpolation, input.name));
+                    }
+                }
+                else
+                {
+                    packedVaryings.push_back(PackedVarying(input, input.interpolation));
+                }
                 packed = true;
                 break;
             }
@@ -140,8 +153,14 @@
             {
                 if (tfVarying == output.name)
                 {
-                    packedVaryings.push_back(PackedVarying(output));
-                    packedVaryings.back().vertexOnly = true;
+                    // Transform feedback for varying structs is underspecified.
+                    // See Khronos bug 9856.
+                    // TODO(jmadill): Figure out how to be spec-compliant here.
+                    if (!output.isStruct())
+                    {
+                        packedVaryings.push_back(PackedVarying(output, output.interpolation));
+                        packedVaryings.back().vertexOnly = true;
+                    }
                     break;
                 }
             }
@@ -1391,9 +1410,10 @@
     mUsesFragDepth = metadata.usesFragDepth(mData);
 
     // Cache if we use flat shading
+    mUsesFlatInterpolation = false;
     for (const auto &varying : packedVaryings)
     {
-        if (varying.varying->interpolation == sh::INTERPOLATION_FLAT)
+        if (varying.interpolation == sh::INTERPOLATION_FLAT)
         {
             mUsesFlatInterpolation = true;
             break;
@@ -2251,11 +2271,17 @@
         {
             for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
             {
-                const sh::Varying &varying = *registerInfo.packedVarying->varying;
-                GLenum transposedType      = gl::TransposeMatrixType(varying.type);
+                const auto &varying   = *registerInfo.packedVarying->varying;
+                GLenum transposedType = gl::TransposeMatrixType(varying.type);
                 int componentCount = gl::VariableColumnCount(transposedType);
                 ASSERT(!varying.isBuiltIn());
 
+                // Transform feedback for varying structs is underspecified.
+                // See Khronos bug 9856.
+                // TODO(jmadill): Figure out how to be spec-compliant here.
+                if (registerInfo.packedVarying->isStructField() || varying.isStruct())
+                    continue;
+
                 // There can be more than one register assigned to a particular varying, and each
                 // register needs its own stream out entry.
                 if (tfVaryingName == varying.name)