https://github.com/mozilla/gecko-dev
Raw File
Tip revision: af98e8295f9aeda69892a1b2ce03030f70c9528b authored by ffxbld on 19 December 2012, 15:26:47 UTC
Added FENNEC_18_0b5_RELEASE FENNEC_18_0b5_BUILD1 tag(s) for changeset 39f7775e4fb0. DONTBUILD CLOSED TREE a=release
Tip revision: af98e82
angle-1317.patch
# HG changeset patch
# Parent ef5d80327785b28df0bd778acc86f4987ba5a678

diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -71,16 +71,17 @@ CPPSRCS = \
         ForLoopUnroll.cpp \
         MapLongVariableNames.cpp \
         spooky.cpp \
         BuiltInFunctionEmulator.cpp \
         Input.cpp \
         Lexer.cpp \
         Preprocessor.cpp \
         Token.cpp \
+        VariablePacker.cpp \
         $(NULL)
 
 # flex/yacc generated files
 CPPSRCS += \
         glslang_lex.cpp \
         glslang_tab.cpp \
         $(NULL)
 
diff --git a/gfx/angle/include/GLSLANG/ShaderLang.h b/gfx/angle/include/GLSLANG/ShaderLang.h
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -137,17 +137,20 @@ typedef enum {
   SH_TIMING_RESTRICTIONS = 0x0200,
     
   // This flag prints the dependency graph that is used to enforce timing
   // restrictions on fragment shaders.
   // This flag only has an effect if all of the following are true:
   // - The shader spec is SH_WEBGL_SPEC.
   // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
   // - The shader type is SH_FRAGMENT_SHADER.
-  SH_DEPENDENCY_GRAPH = 0x0400
+  SH_DEPENDENCY_GRAPH = 0x0400,
+
+  // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
+  SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
 } ShCompileOptions;
 
 //
 // Driver must call this first, once, before doing any other
 // compiler operations.
 // If the function succeeds, the return value is nonzero, else zero.
 //
 COMPILER_EXPORT int ShInitialize();
diff --git a/gfx/angle/src/compiler/Compiler.cpp b/gfx/angle/src/compiler/Compiler.cpp
--- a/gfx/angle/src/compiler/Compiler.cpp
+++ b/gfx/angle/src/compiler/Compiler.cpp
@@ -9,16 +9,17 @@
 #include "compiler/ForLoopUnroll.h"
 #include "compiler/Initialize.h"
 #include "compiler/InitializeParseContext.h"
 #include "compiler/MapLongVariableNames.h"
 #include "compiler/ParseHelper.h"
 #include "compiler/RenameFunction.h"
 #include "compiler/ShHandle.h"
 #include "compiler/ValidateLimitations.h"
+#include "compiler/VariablePacker.h"
 #include "compiler/depgraph/DependencyGraph.h"
 #include "compiler/depgraph/DependencyGraphOutput.h"
 #include "compiler/timing/RestrictFragmentShaderTiming.h"
 #include "compiler/timing/RestrictVertexShaderTiming.h"
 
 bool isWebGLBasedSpec(ShShaderSpec spec)
 {
      return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
@@ -108,16 +109,19 @@ TCompiler::TCompiler(ShShaderType type, 
 TCompiler::~TCompiler()
 {
     ASSERT(longNameMap);
     longNameMap->Release();
 }
 
 bool TCompiler::Init(const ShBuiltInResources& resources)
 {
+    maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
+        resources.MaxVertexUniformVectors :
+        resources.MaxFragmentUniformVectors;
     TScopedPoolAllocator scopedAlloc(&allocator, false);
 
     // Generate built-in symbol table.
     if (!InitBuiltInSymbolTable(resources))
         return false;
     InitExtensionBehavior(resources, extensionBehavior);
 
     return true;
@@ -187,18 +191,25 @@ bool TCompiler::compile(const char* cons
             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
 
         // Call mapLongVariableNames() before collectAttribsUniforms() so in
         // collectAttribsUniforms() we already have the mapped symbol names and
         // we could composite mapped and original variable names.
         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
             mapLongVariableNames(root);
 
-        if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
+        if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
             collectAttribsUniforms(root);
+            if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
+                success = enforcePackingRestrictions();
+                if (!success) {
+                    infoSink.info.message(EPrefixError, "too many uniforms");
+                }
+            }
+        }
 
         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
             intermediate.outputTree(root);
 
         if (success && (compileOptions & SH_OBJECT_CODE))
             translate(root);
     }
 
@@ -305,16 +316,22 @@ bool TCompiler::enforceVertexShaderTimin
 }
 
 void TCompiler::collectAttribsUniforms(TIntermNode* root)
 {
     CollectAttribsUniforms collect(attribs, uniforms);
     root->traverse(&collect);
 }
 
+bool TCompiler::enforcePackingRestrictions()
+{
+    VariablePacker packer;
+    return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
+}
+
 void TCompiler::mapLongVariableNames(TIntermNode* root)
 {
     ASSERT(longNameMap);
     MapLongVariableNames map(longNameMap);
     root->traverse(&map);
 }
 
 int TCompiler::getMappedNameMaxLength() const
diff --git a/gfx/angle/src/compiler/ShHandle.h b/gfx/angle/src/compiler/ShHandle.h
--- a/gfx/angle/src/compiler/ShHandle.h
+++ b/gfx/angle/src/compiler/ShHandle.h
@@ -83,32 +83,37 @@ protected:
     // functionality mandated in GLSL 1.0 spec Appendix A.
     bool validateLimitations(TIntermNode* root);
     // Collect info for all attribs and uniforms.
     void collectAttribsUniforms(TIntermNode* root);
     // Map long variable names into shorter ones.
     void mapLongVariableNames(TIntermNode* root);
     // Translate to object code.
     virtual void translate(TIntermNode* root) = 0;
+    // Returns true if, after applying the packing rules in the GLSL 1.017 spec
+    // Appendix A, section 7, the shader does not use too many uniforms.
+    bool enforcePackingRestrictions();
     // Returns true if the shader passes the restrictions that aim to prevent timing attacks.
     bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
     // Returns true if the shader does not use samplers.
     bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
     // Returns true if the shader does not use sampler dependent values to affect control 
     // flow or in operations whose time can depend on the input values.
     bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
     // Get built-in extensions with default behavior.
     const TExtensionBehavior& getExtensionBehavior() const;
 
     const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
 
 private:
     ShShaderType shaderType;
     ShShaderSpec shaderSpec;
 
+    int maxUniformVectors;
+
     // Built-in symbol table for the given language, spec, and resources.
     // It is preserved from compile-to-compile.
     TSymbolTable symbolTable;
     // Built-in extensions with default behavior.
     TExtensionBehavior extensionBehavior;
 
     BuiltInFunctionEmulator builtInFunctionEmulator;
 
diff --git a/gfx/angle/src/compiler/VariableInfo.cpp b/gfx/angle/src/compiler/VariableInfo.cpp
--- a/gfx/angle/src/compiler/VariableInfo.cpp
+++ b/gfx/angle/src/compiler/VariableInfo.cpp
@@ -133,16 +133,26 @@ void getUserDefinedVariableInfo(const TT
         const TType* fieldType = (*structure)[i].type;
         getVariableInfo(*fieldType,
                         name + "." + fieldType->getFieldName(),
                         mappedName + "." + fieldType->getFieldName(),
                         infoList);
     }
 }
 
+TVariableInfo::TVariableInfo()
+{
+}
+
+TVariableInfo::TVariableInfo(ShDataType type, int size)
+    : type(type),
+      size(size)
+{
+}
+
 CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs,
                                                TVariableInfoList& uniforms)
     : mAttribs(attribs),
       mUniforms(uniforms)
 {
 }
 
 // We are only interested in attribute and uniform variable declaration.
diff --git a/gfx/angle/src/compiler/VariableInfo.h b/gfx/angle/src/compiler/VariableInfo.h
--- a/gfx/angle/src/compiler/VariableInfo.h
+++ b/gfx/angle/src/compiler/VariableInfo.h
@@ -8,16 +8,19 @@
 #define COMPILER_VARIABLE_INFO_H_
 
 #include "GLSLANG/ShaderLang.h"
 #include "compiler/intermediate.h"
 
 // Provides information about a variable.
 // It is currently being used to store info about active attribs and uniforms.
 struct TVariableInfo {
+    TVariableInfo(ShDataType type, int size);
+    TVariableInfo();
+
     TPersistString name;
     TPersistString mappedName;
     ShDataType type;
     int size;
 };
 typedef std::vector<TVariableInfo> TVariableInfoList;
 
 // Traverses intermediate tree to collect all attributes and uniforms.
diff --git a/gfx/angle/src/compiler/VariablePacker.cpp b/gfx/angle/src/compiler/VariablePacker.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/VariablePacker.cpp
@@ -0,0 +1,297 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+#include "compiler/VariablePacker.h"
+
+#include <algorithm>
+#include "compiler/ShHandle.h"
+
+namespace {
+int GetSortOrder(ShDataType type)
+{
+    switch (type) {
+        case SH_FLOAT_MAT4:
+            return 0;
+        case SH_FLOAT_MAT2:
+            return 1;
+        case SH_FLOAT_VEC4:
+        case SH_INT_VEC4:
+        case SH_BOOL_VEC4:
+            return 2;
+        case SH_FLOAT_MAT3:
+            return 3;
+        case SH_FLOAT_VEC3:
+        case SH_INT_VEC3:
+        case SH_BOOL_VEC3:
+            return 4;
+        case SH_FLOAT_VEC2:
+        case SH_INT_VEC2:
+        case SH_BOOL_VEC2:
+            return 5;
+        case SH_FLOAT:
+        case SH_INT:
+        case SH_BOOL:
+        case SH_SAMPLER_2D:
+        case SH_SAMPLER_CUBE:
+        case SH_SAMPLER_EXTERNAL_OES:
+        case SH_SAMPLER_2D_RECT_ARB:
+            return 6;
+        default:
+            ASSERT(false);
+            return 7;
+    }
+}
+}    // namespace
+
+int VariablePacker::GetNumComponentsPerRow(ShDataType type)
+{
+    switch (type) {
+        case SH_FLOAT_MAT4:
+        case SH_FLOAT_MAT2:
+        case SH_FLOAT_VEC4:
+        case SH_INT_VEC4:
+        case SH_BOOL_VEC4:
+            return 4;
+        case SH_FLOAT_MAT3:
+        case SH_FLOAT_VEC3:
+        case SH_INT_VEC3:
+        case SH_BOOL_VEC3:
+            return 3;
+        case SH_FLOAT_VEC2:
+        case SH_INT_VEC2:
+        case SH_BOOL_VEC2:
+            return 2;
+        case SH_FLOAT:
+        case SH_INT:
+        case SH_BOOL:
+        case SH_SAMPLER_2D:
+        case SH_SAMPLER_CUBE:
+        case SH_SAMPLER_EXTERNAL_OES:
+        case SH_SAMPLER_2D_RECT_ARB:
+            return 1;
+        default:
+            ASSERT(false);
+            return 5;
+    }
+}
+
+int VariablePacker::GetNumRows(ShDataType type)
+{
+    switch (type) {
+        case SH_FLOAT_MAT4:
+            return 4;
+        case SH_FLOAT_MAT3:
+            return 3;
+        case SH_FLOAT_MAT2:
+            return 1;
+        case SH_FLOAT_VEC4:
+        case SH_INT_VEC4:
+        case SH_BOOL_VEC4:
+        case SH_FLOAT_VEC3:
+        case SH_INT_VEC3:
+        case SH_BOOL_VEC3:
+        case SH_FLOAT_VEC2:
+        case SH_INT_VEC2:
+        case SH_BOOL_VEC2:
+        case SH_FLOAT:
+        case SH_INT:
+        case SH_BOOL:
+        case SH_SAMPLER_2D:
+        case SH_SAMPLER_CUBE:
+        case SH_SAMPLER_EXTERNAL_OES:
+        case SH_SAMPLER_2D_RECT_ARB:
+            return 1;
+        default:
+            ASSERT(false);
+            return 100000;
+    }
+}
+
+struct TVariableInfoComparer {
+    bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const
+    {
+        int lhsSortOrder = GetSortOrder(lhs.type);
+        int rhsSortOrder = GetSortOrder(rhs.type);
+        if (lhsSortOrder != rhsSortOrder) {
+            return lhsSortOrder < rhsSortOrder;
+        }
+        // Sort by largest first.
+        return lhs.size > rhs.size;
+    }
+};
+
+unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
+{
+    return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
+                    kColumnMask) >> column;
+}
+
+void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
+{
+    unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
+    for (int r = 0; r < numRows; ++r) {
+        int row = topRow + r;
+        ASSERT((rows_[row] & columnFlags) == 0);
+        rows_[row] |= columnFlags;
+    }
+}
+
+bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
+{
+    ASSERT(destRow);
+
+    for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
+         ++topNonFullRow_) {
+    }
+
+    for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
+         --bottomNonFullRow_) {
+    }
+
+    if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
+        return false;
+    }
+
+    unsigned columnFlags = makeColumnFlags(column, 1);
+    int topGoodRow = 0;
+    int smallestGoodTop = -1;
+    int smallestGoodSize = maxRows_ + 1;
+    int bottomRow = bottomNonFullRow_ + 1;
+    bool found = false;
+    for (int row = topNonFullRow_; row <= bottomRow; ++row) {
+        bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
+        if (rowEmpty) {
+            if (!found) {
+                topGoodRow = row;
+                found = true;
+            }
+        } else {
+            if (found) {
+                int size = row - topGoodRow;
+                if (size >= numRows && size < smallestGoodSize) {
+                    smallestGoodSize = size;
+                    smallestGoodTop = topGoodRow;
+                }
+            }
+            found = false;
+        }
+    }
+    if (smallestGoodTop < 0) {
+        return false;
+    }
+
+    *destRow = smallestGoodTop;
+    if (destSize) {
+        *destSize = smallestGoodSize;
+    }
+    return true;
+}
+
+bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables)
+{
+    ASSERT(maxVectors > 0);
+    maxRows_ = maxVectors;
+    topNonFullRow_ = 0;
+    bottomNonFullRow_ = maxRows_ - 1;
+    TVariableInfoList variables(in_variables);
+
+    // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
+    // order by type, then by size of array, largest first.
+    std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
+    rows_.clear();
+    rows_.resize(maxVectors, 0);
+
+    // Packs the 4 column variables.
+    size_t ii = 0;
+    for (; ii < variables.size(); ++ii) {
+        const TVariableInfo& variable = variables[ii];
+        if (GetNumComponentsPerRow(variable.type) != 4) {
+            break;
+        }
+        topNonFullRow_ += GetNumRows(variable.type) * variable.size;
+    }
+
+    if (topNonFullRow_ > maxRows_) {
+        return false;
+    }
+
+    // Packs the 3 column variables.
+    int num3ColumnRows = 0;
+    for (; ii < variables.size(); ++ii) {
+        const TVariableInfo& variable = variables[ii];
+        if (GetNumComponentsPerRow(variable.type) != 3) {
+            break;
+        }
+        num3ColumnRows += GetNumRows(variable.type) * variable.size;
+    }
+
+    if (topNonFullRow_ + num3ColumnRows > maxRows_) {
+        return false;
+    }
+
+    fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
+
+    // Packs the 2 column variables.
+    int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
+    int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
+    int rowsAvailableInColumns01 = twoColumnRowsAvailable;
+    int rowsAvailableInColumns23 = twoColumnRowsAvailable;
+    for (; ii < variables.size(); ++ii) {
+        const TVariableInfo& variable = variables[ii];
+        if (GetNumComponentsPerRow(variable.type) != 2) {
+            break;
+        }
+        int numRows = GetNumRows(variable.type) * variable.size;
+        if (numRows <= rowsAvailableInColumns01) {
+            rowsAvailableInColumns01 -= numRows;
+        } else if (numRows <= rowsAvailableInColumns23) {
+            rowsAvailableInColumns23 -= numRows;
+        } else {
+            return false;
+        }
+    }
+
+    int numRowsUsedInColumns01 =
+        twoColumnRowsAvailable - rowsAvailableInColumns01;
+    int numRowsUsedInColumns23 =
+        twoColumnRowsAvailable - rowsAvailableInColumns23;
+    fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
+    fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
+                2, 2);
+
+    // Packs the 1 column variables.
+    for (; ii < variables.size(); ++ii) {
+        const TVariableInfo& variable = variables[ii];
+        ASSERT(1 == GetNumComponentsPerRow(variable.type));
+        int numRows = GetNumRows(variable.type) * variable.size;
+        int smallestColumn = -1;
+        int smallestSize = maxRows_ + 1;
+        int topRow = -1;
+        for (int column = 0; column < kNumColumns; ++column) {
+            int row = 0;
+            int size = 0;
+            if (searchColumn(column, numRows, &row, &size)) {
+                if (size < smallestSize) {
+                    smallestSize = size;
+                    smallestColumn = column;
+                    topRow = row;
+                }
+            }
+        }
+
+        if (smallestColumn < 0) {
+            return false;
+        }
+
+        fillColumns(topRow, numRows, smallestColumn, 1);
+    }
+
+    ASSERT(variables.size() == ii);
+
+    return true;
+}
+
+
+
diff --git a/gfx/angle/src/compiler/VariablePacker.h b/gfx/angle/src/compiler/VariablePacker.h
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/VariablePacker.h
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+
+#ifndef _VARIABLEPACKER_INCLUDED_
+#define _VARIABLEPACKER_INCLUDED_
+
+#include <vector>
+#include "compiler/ShHandle.h"
+
+class VariablePacker {
+ public:
+    // Returns true if the passed in variables pack in maxVectors following
+    // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+    bool CheckVariablesWithinPackingLimits(
+        int maxVectors,
+        const TVariableInfoList& in_variables);
+
+    // Gets how many components in a row a data type takes.
+    static int GetNumComponentsPerRow(ShDataType type);
+
+    // Gets how many rows a data type takes.
+    static int GetNumRows(ShDataType type);
+
+ private:
+    static const int kNumColumns = 4;
+    static const unsigned kColumnMask = (1 << kNumColumns) - 1;
+
+    unsigned makeColumnFlags(int column, int numComponentsPerRow);
+    void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
+    bool searchColumn(int column, int numRows, int* destRow, int* destSize);
+
+    int topNonFullRow_;
+    int bottomNonFullRow_;
+    int maxRows_;
+    std::vector<unsigned> rows_;
+};
+
+#endif // _VARIABLEPACKER_INCLUDED_
diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -84,16 +84,17 @@ CPPSRCS = \
         ForLoopUnroll.cpp \
         MapLongVariableNames.cpp \
         spooky.cpp \
         BuiltInFunctionEmulator.cpp \
         Input.cpp \
         Lexer.cpp \
         Preprocessor.cpp \
         Token.cpp \
+        VariablePacker.cpp \
         $(NULL)
 
 # flex/yacc generated files
 CPPSRCS += \
         glslang_lex.cpp \
         glslang_tab.cpp \
         $(NULL)
 
diff --git a/gfx/angle/tests/build_tests.gyp b/gfx/angle/tests/build_tests.gyp
--- a/gfx/angle/tests/build_tests.gyp
+++ b/gfx/angle/tests/build_tests.gyp
@@ -58,16 +58,35 @@
         'preprocessor_tests/pragma_test.cpp',
         'preprocessor_tests/PreprocessorTest.cpp',
         'preprocessor_tests/PreprocessorTest.h',
         'preprocessor_tests/space_test.cpp',
         'preprocessor_tests/token_test.cpp',
         'preprocessor_tests/version_test.cpp',
       ],
     },
+    {
+      'target_name': 'compiler_tests',
+      'type': 'executable',
+      'dependencies': [
+        '../src/build_angle.gyp:translator_common',
+        'gtest',
+        'gmock',
+      ],
+      'include_dirs': [
+        '../include',
+        '../src',
+        '../third_party/googletest/include',
+        '../third_party/googlemock/include',
+      ],
+      'sources': [
+        '../third_party/googlemock/src/gmock_main.cc',
+        'compiler_tests/VariablePacker_test.cpp',
+      ],
+    },
   ],
 }
 
 # Local Variables:
 # tab-width:2
 # indent-tabs-mode:nil
 # End:
 # vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gfx/angle/tests/compiler_tests/VariablePacker_test.cpp b/gfx/angle/tests/compiler_tests/VariablePacker_test.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/angle/tests/compiler_tests/VariablePacker_test.cpp
@@ -0,0 +1,85 @@
+//
+// Copyright (c) 2002-2012 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.
+//
+#include "compiler/VariablePacker.h"
+#include "gtest/gtest.h"
+
+TEST(VariablePacking, Pack) {
+  VariablePacker packer;
+  TVariableInfoList vars;
+  const int kMaxRows = 16;
+  // test no vars.
+  EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+  ShDataType types[] = {
+    SH_FLOAT_MAT4,            // 0
+    SH_FLOAT_MAT2,            // 1
+    SH_FLOAT_VEC4,            // 2
+    SH_INT_VEC4,              // 3
+    SH_BOOL_VEC4,             // 4
+    SH_FLOAT_MAT3,            // 5
+    SH_FLOAT_VEC3,            // 6
+    SH_INT_VEC3,              // 7
+    SH_BOOL_VEC3,             // 8
+    SH_FLOAT_VEC2,            // 9
+    SH_INT_VEC2,              // 10
+    SH_BOOL_VEC2,             // 11
+    SH_FLOAT,                 // 12
+    SH_INT,                   // 13
+    SH_BOOL,                  // 14
+    SH_SAMPLER_2D,            // 15
+    SH_SAMPLER_CUBE,          // 16
+    SH_SAMPLER_EXTERNAL_OES,  // 17
+    SH_SAMPLER_2D_RECT_ARB,   // 18
+  };
+
+  for (size_t tt = 0; tt < sizeof(types) / sizeof(types[0]); ++tt) {
+    ShDataType type = types[tt];
+    int num_rows = VariablePacker::GetNumRows(type);
+    int num_components_per_row = VariablePacker::GetNumComponentsPerRow(type);
+    // Check 1 of the type.
+    vars.clear();
+    vars.push_back(TVariableInfo(type, 1));
+    EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+    // Check exactly the right amount of 1 type as an array.
+    int num_vars = kMaxRows / num_rows;
+    vars.clear();
+    vars.push_back(TVariableInfo(type, num_vars));
+    EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+    // test too many
+    vars.clear();
+    vars.push_back(TVariableInfo(type, num_vars + 1));
+    EXPECT_FALSE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+    // Check exactly the right amount of 1 type as individual vars.
+    num_vars = kMaxRows / num_rows *
+        ((num_components_per_row > 2) ? 1 : (4 / num_components_per_row));
+    vars.clear();
+    for (int ii = 0; ii < num_vars; ++ii) {
+      vars.push_back(TVariableInfo(type, 1));
+    }
+    EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+    // Check 1 too many.
+    vars.push_back(TVariableInfo( type, 1));
+    EXPECT_FALSE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+  }
+
+  // Test example from GLSL ES 3.0 spec chapter 11.
+  vars.clear();
+  vars.push_back(TVariableInfo(SH_FLOAT_VEC4, 1));
+  vars.push_back(TVariableInfo(SH_FLOAT_MAT3, 1));
+  vars.push_back(TVariableInfo(SH_FLOAT_MAT3, 1));
+  vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 6));
+  vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 4));
+  vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 1));
+  vars.push_back(TVariableInfo(SH_FLOAT, 3));
+  vars.push_back(TVariableInfo(SH_FLOAT, 2));
+  vars.push_back(TVariableInfo(SH_FLOAT, 1));
+  EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+}
+
back to top