--- 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)
new file mode 100644
--- /dev/null
+++ b/gfx/angle/angle-1317.patch
@@ -0,0 +1,732 @@
+# 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));
++}
++
--- 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();
--- 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
--- 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;
--- 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.
--- 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.
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;
+}
+
+
+
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_
--- 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)
--- 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:
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));
+}
+