Move ShaderVariables to common shared source.

Also move the block layout encoding utilities to the common folder.
The combined changes allow us to include the shader and block code
into both libGLESv2 and the translator separately. This in turn
fixes the Chromium component build, where we were calling internal
translator functions directly from libGLESv2.

BUG=angle:568

Change-Id: Ibcfa2c936a7c737ad515c10bd24061ff39ee5747
Reviewed-on: https://chromium-review.googlesource.com/192891
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/blocklayout.cpp b/src/common/blocklayout.cpp
new file mode 100644
index 0000000..45f516f
--- /dev/null
+++ b/src/common/blocklayout.cpp
@@ -0,0 +1,305 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.cpp:
+//   Implementation for block layout classes and methods.
+//
+
+#include "common/blocklayout.h"
+#include "common/shadervars.h"
+#include "common/mathutil.h"
+#include "common/utilities.h"
+
+namespace gl
+{
+
+BlockLayoutEncoder::BlockLayoutEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
+    : mCurrentOffset(0),
+      mBlockInfoOut(blockInfoOut)
+{
+}
+
+void BlockLayoutEncoder::encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields)
+{
+    for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+    {
+        const InterfaceBlockField &variable = fields[fieldIndex];
+
+        if (variable.fields.size() > 0)
+        {
+            const unsigned int elementCount = std::max(1u, variable.arraySize);
+
+            for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
+            {
+                enterAggregateType();
+                encodeInterfaceBlockFields(variable.fields);
+                exitAggregateType();
+            }
+        }
+        else
+        {
+            encodeInterfaceBlockField(variable);
+        }
+    }
+}
+
+void BlockLayoutEncoder::encodeInterfaceBlockField(const InterfaceBlockField &field)
+{
+    int arrayStride;
+    int matrixStride;
+
+    ASSERT(field.fields.empty());
+    getBlockLayoutInfo(field.type, field.arraySize, field.isRowMajorMatrix, &arrayStride, &matrixStride);
+
+    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, field.isRowMajorMatrix);
+
+    if (mBlockInfoOut)
+    {
+        mBlockInfoOut->push_back(memberInfo);
+    }
+
+    advanceOffset(field.type, field.arraySize, field.isRowMajorMatrix, arrayStride, matrixStride);
+}
+
+void BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
+{
+    int arrayStride;
+    int matrixStride;
+
+    getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
+
+    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
+
+    if (mBlockInfoOut)
+    {
+        mBlockInfoOut->push_back(memberInfo);
+    }
+
+    advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
+}
+
+void BlockLayoutEncoder::nextRegister()
+{
+    mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
+}
+
+Std140BlockEncoder::Std140BlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
+    : BlockLayoutEncoder(blockInfoOut)
+{
+}
+
+void Std140BlockEncoder::enterAggregateType()
+{
+    nextRegister();
+}
+
+void Std140BlockEncoder::exitAggregateType()
+{
+    nextRegister();
+}
+
+void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
+{
+    // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
+    ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
+
+    size_t baseAlignment = 0;
+    int matrixStride = 0;
+    int arrayStride = 0;
+
+    if (gl::IsMatrixType(type))
+    {
+        baseAlignment = ComponentsPerRegister;
+        matrixStride = ComponentsPerRegister;
+
+        if (arraySize > 0)
+        {
+            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+            arrayStride = ComponentsPerRegister * numRegisters;
+        }
+    }
+    else if (arraySize > 0)
+    {
+        baseAlignment = ComponentsPerRegister;
+        arrayStride = ComponentsPerRegister;
+    }
+    else
+    {
+        const int numComponents = gl::UniformComponentCount(type);
+        baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
+    }
+
+    mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
+
+    *matrixStrideOut = matrixStride;
+    *arrayStrideOut = arrayStride;
+}
+
+void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
+{
+    if (arraySize > 0)
+    {
+        mCurrentOffset += arrayStride * arraySize;
+    }
+    else if (gl::IsMatrixType(type))
+    {
+        ASSERT(matrixStride == ComponentsPerRegister);
+        const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+        mCurrentOffset += ComponentsPerRegister * numRegisters;
+    }
+    else
+    {
+        mCurrentOffset += gl::UniformComponentCount(type);
+    }
+}
+
+HLSLBlockEncoder::HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut)
+    : BlockLayoutEncoder(blockInfoOut)
+{
+}
+
+void HLSLBlockEncoder::enterAggregateType()
+{
+    nextRegister();
+}
+
+void HLSLBlockEncoder::exitAggregateType()
+{
+}
+
+void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
+{
+    // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
+    ASSERT(gl::UniformComponentSize(gl::UniformComponentType(type)) == BytesPerComponent);
+
+    int matrixStride = 0;
+    int arrayStride = 0;
+
+    if (gl::IsMatrixType(type))
+    {
+        nextRegister();
+        matrixStride = ComponentsPerRegister;
+
+        if (arraySize > 0)
+        {
+            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+            arrayStride = ComponentsPerRegister * numRegisters;
+        }
+    }
+    else if (arraySize > 0)
+    {
+        nextRegister();
+        arrayStride = ComponentsPerRegister;
+    }
+    else
+    {
+        int numComponents = gl::UniformComponentCount(type);
+        if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister)
+        {
+            nextRegister();
+        }
+    }
+
+    *matrixStrideOut = matrixStride;
+    *arrayStrideOut = arrayStride;
+}
+
+void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
+{
+    if (arraySize > 0)
+    {
+        mCurrentOffset += arrayStride * (arraySize - 1);
+    }
+
+    if (gl::IsMatrixType(type))
+    {
+        ASSERT(matrixStride == ComponentsPerRegister);
+        const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
+        const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
+        mCurrentOffset += ComponentsPerRegister * (numRegisters - 1);
+        mCurrentOffset += numComponents;
+    }
+    else
+    {
+        mCurrentOffset += gl::UniformComponentCount(type);
+    }
+}
+
+void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable, HLSLBlockEncoder *encoder, const std::vector<gl::BlockMemberInfo> &blockInfo)
+{
+    // because this method computes offsets (element indexes) instead of any total sizes,
+    // we can ignore the array size of the variable
+
+    if (variable->isStruct())
+    {
+        encoder->enterAggregateType();
+
+        for (size_t fieldIndex = 0; fieldIndex < variable->fields.size(); fieldIndex++)
+        {
+            HLSLVariableGetRegisterInfo(baseRegisterIndex, &variable->fields[fieldIndex], encoder, blockInfo);
+        }
+
+        encoder->exitAggregateType();
+    }
+    else
+    {
+        encoder->encodeType(variable->type, variable->arraySize, false);
+
+        const size_t registerBytes = (encoder->BytesPerComponent * encoder->ComponentsPerRegister);
+        variable->registerIndex = baseRegisterIndex + (blockInfo.back().offset / registerBytes);
+        variable->elementIndex = (blockInfo.back().offset % registerBytes) / sizeof(float);
+    }
+}
+
+void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, gl::Uniform *variable)
+{
+    std::vector<BlockMemberInfo> blockInfo;
+    HLSLBlockEncoder encoder(&blockInfo);
+    HLSLVariableGetRegisterInfo(baseRegisterIndex, variable, &encoder, blockInfo);
+}
+
+template <class ShaderVarType>
+void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder)
+{
+    if (variable.isStruct())
+    {
+        for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
+        {
+            encoder->enterAggregateType();
+
+            for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++)
+            {
+                HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder);
+            }
+
+            encoder->exitAggregateType();
+        }
+    }
+    else
+    {
+        // We operate only on varyings and uniforms, which do not have matrix layout qualifiers
+        encoder->encodeType(variable.type, variable.arraySize, false);
+    }
+}
+
+unsigned int HLSLVariableRegisterCount(const Varying &variable)
+{
+    HLSLBlockEncoder encoder(NULL);
+    HLSLVariableRegisterCount(variable, &encoder);
+
+    const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
+    return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
+}
+
+unsigned int HLSLVariableRegisterCount(const Uniform &variable)
+{
+    HLSLBlockEncoder encoder(NULL);
+    HLSLVariableRegisterCount(variable, &encoder);
+
+    const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
+    return static_cast<unsigned int>(rx::roundUp<size_t>(encoder.getBlockSize(), registerBytes) / registerBytes);
+}
+
+}
diff --git a/src/common/blocklayout.h b/src/common/blocklayout.h
new file mode 100644
index 0000000..68f855b
--- /dev/null
+++ b/src/common/blocklayout.h
@@ -0,0 +1,96 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// blocklayout.h:
+//   Methods and classes related to uniform layout and packing in GLSL and HLSL.
+//
+
+#ifndef COMMON_BLOCKLAYOUT_H_
+#define COMMON_BLOCKLAYOUT_H_
+
+#include <vector>
+#define GL_APICALL
+#include <GLES3/gl3.h>
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+
+struct ShaderVariable;
+struct InterfaceBlockField;
+struct BlockMemberInfo;
+struct Uniform;
+struct Varying;
+
+class BlockLayoutEncoder
+{
+  public:
+    BlockLayoutEncoder(std::vector<BlockMemberInfo> *blockInfoOut);
+
+    void encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields);
+    void encodeInterfaceBlockField(const InterfaceBlockField &field);
+    void encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
+    size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
+
+    static const size_t BytesPerComponent = 4u;
+    static const unsigned int ComponentsPerRegister = 4u;
+
+  protected:
+    size_t mCurrentOffset;
+
+    void nextRegister();
+
+    virtual void enterAggregateType() = 0;
+    virtual void exitAggregateType() = 0;
+    virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0;
+    virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0;
+
+  private:
+    std::vector<BlockMemberInfo> *mBlockInfoOut;
+};
+
+// Block layout according to the std140 block layout
+// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
+
+class Std140BlockEncoder : public BlockLayoutEncoder
+{
+  public:
+    Std140BlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut);
+
+  protected:
+    virtual void enterAggregateType();
+    virtual void exitAggregateType();
+    virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut);
+    virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride);
+};
+
+// Block layout packed according to the default D3D11 register packing rules
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
+
+class HLSLBlockEncoder : public BlockLayoutEncoder
+{
+  public:
+    HLSLBlockEncoder(std::vector<BlockMemberInfo> *blockInfoOut);
+
+    virtual void enterAggregateType();
+    virtual void exitAggregateType();
+
+  protected:
+    virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut);
+    virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride);
+};
+
+// This method assigns values to the variable's "registerIndex" and "elementIndex" fields.
+// "elementIndex" is only used for structures.
+void HLSLVariableGetRegisterInfo(unsigned int baseRegisterIndex, Uniform *variable);
+
+// This method returns the number of used registers for a ShaderVariable. It is dependent on the HLSLBlockEncoder
+// class to count the number of used registers in a struct (which are individually packed according to the same rules).
+unsigned int HLSLVariableRegisterCount(const Varying &variable);
+unsigned int HLSLVariableRegisterCount(const Uniform &variable);
+
+}
+
+#endif // COMMON_BLOCKLAYOUT_H_
diff --git a/src/common/shadervars.cpp b/src/common/shadervars.cpp
new file mode 100644
index 0000000..c9843dc
--- /dev/null
+++ b/src/common/shadervars.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// shadervars.cpp:
+//   Implementation for GL shader variable member functions.
+//
+
+#include "common/shadervars.h"
+
+namespace gl
+{
+
+ShaderVariable::ShaderVariable(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn)
+    : type(typeIn),
+      precision(precisionIn),
+      name(nameIn),
+      arraySize(arraySizeIn)
+{
+}
+
+Uniform::Uniform(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, unsigned int registerIndexIn, unsigned int elementIndexIn)
+    : ShaderVariable(typeIn, precisionIn, nameIn, arraySizeIn),
+      registerIndex(registerIndexIn),
+      elementIndex(elementIndexIn)
+{
+}
+
+Attribute::Attribute()
+    : ShaderVariable(GL_NONE, GL_NONE, "", 0),
+      location(-1)
+{
+}
+
+Attribute::Attribute(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, int locationIn)
+    : ShaderVariable(typeIn, precisionIn, nameIn, arraySizeIn),
+      location(locationIn)
+{
+}
+
+InterfaceBlockField::InterfaceBlockField(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, bool isRowMajorMatrix)
+    : ShaderVariable(typeIn, precisionIn, nameIn, arraySizeIn),
+      isRowMajorMatrix(isRowMajorMatrix)
+{
+}
+
+Varying::Varying(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, InterpolationType interpolationIn)
+    : ShaderVariable(typeIn, precisionIn, nameIn, arraySizeIn),
+      interpolation(interpolationIn),
+      registerIndex(GL_INVALID_INDEX),
+      elementIndex(GL_INVALID_INDEX)
+{
+}
+
+void Varying::resetRegisterAssignment()
+{
+    registerIndex = GL_INVALID_INDEX;
+    elementIndex = GL_INVALID_INDEX;
+}
+
+BlockMemberInfo::BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
+    : offset(offset),
+      arrayStride(arrayStride),
+      matrixStride(matrixStride),
+      isRowMajorMatrix(isRowMajorMatrix)
+{
+}
+
+const BlockMemberInfo BlockMemberInfo::defaultBlockInfo(-1, -1, -1, false);
+
+InterfaceBlock::InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex)
+    : name(name),
+      arraySize(arraySize),
+      layout(BLOCKLAYOUT_SHARED),
+      registerIndex(registerIndex),
+      isRowMajorLayout(false)
+{
+}
+
+}
diff --git a/src/common/shadervars.h b/src/common/shadervars.h
new file mode 100644
index 0000000..eba0141
--- /dev/null
+++ b/src/common/shadervars.h
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// shadervars.h:
+//  Types to represent GL variables (varyings, uniforms, etc)
+//
+
+#ifndef COMMON_SHADERVARIABLE_H_
+#define COMMON_SHADERVARIABLE_H_
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#define GL_APICALL
+#include <GLES3/gl3.h>
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+
+enum InterpolationType
+{
+    INTERPOLATION_SMOOTH,
+    INTERPOLATION_CENTROID,
+    INTERPOLATION_FLAT
+};
+
+struct ShaderVariable
+{
+    GLenum type;
+    GLenum precision;
+    std::string name;
+    unsigned int arraySize;
+
+    ShaderVariable(GLenum type, GLenum precision, const char *name, unsigned int arraySize);
+    bool isArray() const { return arraySize > 0; }
+    unsigned int elementCount() const { return std::max(1u, arraySize); }
+};
+
+struct Uniform : public ShaderVariable
+{
+    unsigned int registerIndex;
+    unsigned int elementIndex;     // For struct varyings
+    std::vector<Uniform> fields;
+
+    Uniform(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn,
+            unsigned int registerIndexIn, unsigned int elementIndexIn);
+
+    bool isStruct() const { return !fields.empty(); }
+};
+
+struct Attribute : public ShaderVariable
+{
+    int location;
+
+    Attribute();
+    Attribute(GLenum type, GLenum precision, const char *name, unsigned int arraySize, int location);
+};
+
+struct InterfaceBlockField : public ShaderVariable
+{
+    bool isRowMajorMatrix;
+    std::vector<InterfaceBlockField> fields;
+
+    InterfaceBlockField(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, bool isRowMajorMatrix);
+
+    bool isStruct() const { return !fields.empty(); }
+};
+
+struct Varying : public ShaderVariable
+{
+    InterpolationType interpolation;
+    std::vector<Varying> fields;
+    unsigned int registerIndex;    // Assigned during link
+    unsigned int elementIndex;     // First register element for varyings, assigned during link
+    std::string structName;
+
+    Varying(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn, InterpolationType interpolationIn);
+
+    bool isStruct() const { return !fields.empty(); }
+    bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; }
+
+    void resetRegisterAssignment();
+};
+
+struct BlockMemberInfo
+{
+    BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix);
+
+    int offset;
+    int arrayStride;
+    int matrixStride;
+    bool isRowMajorMatrix;
+
+    static const BlockMemberInfo defaultBlockInfo;
+};
+
+typedef std::vector<BlockMemberInfo> BlockMemberInfoArray;
+
+enum BlockLayoutType
+{
+    BLOCKLAYOUT_STANDARD,
+    BLOCKLAYOUT_PACKED,
+    BLOCKLAYOUT_SHARED
+};
+
+struct InterfaceBlock
+{
+    InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex);
+
+    std::string name;
+    unsigned int arraySize;
+    size_t dataSize;
+    BlockLayoutType layout;
+    bool isRowMajorLayout;
+    std::vector<InterfaceBlockField> fields;
+    std::vector<BlockMemberInfo> blockInfo;
+
+    unsigned int registerIndex;
+};
+
+}
+
+#endif // COMMON_SHADERVARIABLE_H_