Add support to the HLSL translator to output interface blocks to constant buffers, using HLSL register packing rules.

TRAC #22930

Signed-off-by: Nicolas Capens
Signed-off-by: Geoff Lang
Author: Jamie Madill

git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2344 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 3b6ad2d..808c99b 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -7,6 +7,7 @@
 #include "compiler/OutputHLSL.h"
 
 #include "common/angleutils.h"
+#include "common/utilities.h"
 #include "compiler/debug.h"
 #include "compiler/DetectDiscontinuity.h"
 #include "compiler/InfoSink.h"
@@ -113,6 +114,7 @@
     }
 
     mSamplerRegister = 0;
+    mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants
 }
 
 OutputHLSL::~OutputHLSL()
@@ -141,6 +143,11 @@
     return mActiveUniforms;
 }
 
+const ActiveInterfaceBlocks &OutputHLSL::getInterfaceBlocks() const
+{
+    return mActiveInterfaceBlocks;
+}
+
 int OutputHLSL::vectorSize(const TType &type) const
 {
     int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
@@ -165,6 +172,7 @@
     }
 
     TString uniforms;
+    TString interfaceBlocks;
     TString varyings;
     TString attributes;
 
@@ -180,7 +188,7 @@
             uniforms += "uniform SamplerState sampler_" + decorateUniform(name, type) + arrayString(type) + 
                         " : register(s" + str(index) + ");\n";
 
-            uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) + 
+            uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) +
                         " : register(t" + str(index) + ");\n";
         }
         else
@@ -190,6 +198,36 @@
         }
     }
 
+    for (ReferencedSymbols::const_iterator interfaceBlockIt = mReferencedInterfaceBlocks.begin(); interfaceBlockIt != mReferencedInterfaceBlocks.end(); interfaceBlockIt++)
+    {
+        const TType &interfaceBlockType = *interfaceBlockIt->second->getType().getInterfaceBlockType();
+        const TString &blockName = interfaceBlockType.getTypeName();
+        const TTypeList &typeList = *interfaceBlockType.getStruct();
+
+        sh::InterfaceBlock interfaceBlock(blockName.c_str(), 0, mInterfaceBlockRegister++);
+        for (unsigned int typeIndex = 0; typeIndex < typeList.size(); typeIndex++)
+        {
+            const TType &memberType = *typeList[typeIndex].type;
+            declareUniformToList(memberType, memberType.getFieldName(), typeIndex, interfaceBlock.activeUniforms);
+        }
+
+        // TODO: handle other block layouts
+        interfaceBlock.setPackedBlockLayout();
+        mActiveInterfaceBlocks.push_back(interfaceBlock);
+
+        interfaceBlocks += "cbuffer " + blockName + " : register(b" + str(interfaceBlock.registerIndex) + ")\n"
+                           "{\n";
+
+        for (unsigned int typeIndex = 0; typeIndex < typeList.size(); typeIndex++)
+        {
+            // TODO: padding for standard layout
+            const TType &memberType = *typeList[typeIndex].type;
+            interfaceBlocks += "    " + typeString(memberType) + " " + decorate(memberType.getFieldName()) + arrayString(memberType) + ";\n";
+        }
+
+        interfaceBlocks += "};\n\n";
+    }
+
     for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
     {
         const TType &type = varying->second->getType();
@@ -310,6 +348,12 @@
         out <<  uniforms;
         out << "\n";
 
+        if (!interfaceBlocks.empty())
+        {
+            out << interfaceBlocks;
+            out << "\n";
+        }
+
         if (mUsesTexture2D)
         {
             if (mOutputType == SH_HLSL9_OUTPUT)
@@ -678,6 +722,12 @@
         out << uniforms;
         out << "\n";
         
+        if (!interfaceBlocks.empty())
+        {
+            out << interfaceBlocks;
+            out << "\n";
+        }
+
         if (mUsesTexture2D)
         {
             if (mOutputType == SH_HLSL9_OUTPUT)
@@ -1148,8 +1198,17 @@
 
         if (qualifier == EvqUniform)
         {
-            mReferencedUniforms[name] = node;
-            out << decorateUniform(name, node->getType());
+            if (node->getType().isInterfaceBlockMember())
+            {
+                const TString& interfaceBlockTypeName = node->getType().getInterfaceBlockType()->getTypeName();
+                mReferencedInterfaceBlocks[interfaceBlockTypeName] = node;
+                out << decorateUniform(name, node->getType());
+            }
+            else
+            {
+                mReferencedUniforms[name] = node;
+                out << decorateUniform(name, node->getType());
+            }
         }
         else if (qualifier == EvqAttribute)
         {
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index 4e6e600..a4f8be9 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -33,6 +33,7 @@
 
     TInfoSinkBase &getBodyStream();
     const ActiveUniforms &getUniforms();
+    const ActiveInterfaceBlocks &getInterfaceBlocks() const;
 
     TString typeString(const TType &type);
     TString textureString(const TType &type);
@@ -84,6 +85,7 @@
 
     typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
     ReferencedSymbols mReferencedUniforms;
+    ReferencedSymbols mReferencedInterfaceBlocks;
     ReferencedSymbols mReferencedAttributes;
     ReferencedSymbols mReferencedVaryings;
 
@@ -163,6 +165,7 @@
     TIntermSymbol *mExcessiveLoopIndex;
 
     int mUniformRegister;
+    int mInterfaceBlockRegister;
     int mSamplerRegister;
 
     TString registerString(TIntermSymbol *operand);
@@ -178,6 +181,7 @@
     static bool isVarying(TQualifier qualifier);
 
     ActiveUniforms mActiveUniforms;
+    ActiveInterfaceBlocks mActiveInterfaceBlocks;
 };
 }