1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // VaryingPacking_unittest.cpp:
7 // Tests for ANGLE's internal varying packing algorithm.
8 //
9
10 #include <gtest/gtest.h>
11 // 'None' is defined as 'struct None {};' in
12 // third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.
13 // But 'None' is also define as a numberic constant 0L in <X11/X.h>.
14 // So we need to include gtest first to avoid such conflict.
15
16 #include "libANGLE/Program.h"
17 #include "libANGLE/VaryingPacking.h"
18
19 using namespace gl;
20
21 namespace
22 {
23
24 class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
25 {
26 protected:
VaryingPackingTest()27 VaryingPackingTest() {}
28
testVaryingPacking(GLint maxVaryings,PackMode packMode,const std::vector<sh::ShaderVariable> & shVaryings)29 bool testVaryingPacking(GLint maxVaryings,
30 PackMode packMode,
31 const std::vector<sh::ShaderVariable> &shVaryings)
32 {
33 ProgramMergedVaryings mergedVaryings;
34 for (const sh::ShaderVariable &shVarying : shVaryings)
35 {
36 ProgramVaryingRef ref;
37 ref.frontShader = &shVarying;
38 ref.backShader = &shVarying;
39 ref.frontShaderStage = ShaderType::Vertex;
40 ref.backShaderStage = ShaderType::Fragment;
41 mergedVaryings.push_back(ref);
42 }
43
44 InfoLog infoLog;
45 std::vector<std::string> transformFeedbackVaryings;
46
47 VaryingPacking varyingPacking;
48 return varyingPacking.collectAndPackUserVaryings(
49 infoLog, maxVaryings, packMode, ShaderType::Vertex, ShaderType::Fragment,
50 mergedVaryings, transformFeedbackVaryings, false);
51 }
52
53 // Uses the "relaxed" ANGLE packing mode.
packVaryings(GLint maxVaryings,const std::vector<sh::ShaderVariable> & shVaryings)54 bool packVaryings(GLint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
55 {
56 return testVaryingPacking(maxVaryings, PackMode::ANGLE_RELAXED, shVaryings);
57 }
58
59 // Uses the stricter WebGL style packing rules.
packVaryingsStrict(GLint maxVaryings,const std::vector<sh::ShaderVariable> & shVaryings)60 bool packVaryingsStrict(GLint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
61 {
62 return testVaryingPacking(maxVaryings, PackMode::WEBGL_STRICT, shVaryings);
63 }
64
65 const int kMaxVaryings = GetParam();
66 };
67
MakeVaryings(GLenum type,size_t count,size_t arraySize)68 std::vector<sh::ShaderVariable> MakeVaryings(GLenum type, size_t count, size_t arraySize)
69 {
70 std::vector<sh::ShaderVariable> varyings;
71
72 for (size_t index = 0; index < count; ++index)
73 {
74 std::stringstream strstr;
75 strstr << type << index;
76
77 sh::ShaderVariable varying;
78 varying.type = type;
79 varying.precision = GL_MEDIUM_FLOAT;
80 varying.name = strstr.str();
81 varying.mappedName = strstr.str();
82 if (arraySize > 0)
83 {
84 varying.arraySizes.push_back(static_cast<unsigned int>(arraySize));
85 }
86 varying.staticUse = true;
87 varying.interpolation = sh::INTERPOLATION_FLAT;
88 varying.isInvariant = false;
89
90 varyings.push_back(varying);
91 }
92
93 return varyings;
94 }
95
AddVaryings(std::vector<sh::ShaderVariable> * varyings,GLenum type,size_t count,size_t arraySize)96 void AddVaryings(std::vector<sh::ShaderVariable> *varyings,
97 GLenum type,
98 size_t count,
99 size_t arraySize)
100 {
101 const auto &newVaryings = MakeVaryings(type, count, arraySize);
102 varyings->insert(varyings->end(), newVaryings.begin(), newVaryings.end());
103 }
104
105 // Test that a single varying can't overflow the packing.
TEST_P(VaryingPackingTest,OneVaryingLargerThanMax)106 TEST_P(VaryingPackingTest, OneVaryingLargerThanMax)
107 {
108 ASSERT_FALSE(packVaryings(1, MakeVaryings(GL_FLOAT_MAT4, 1, 0)));
109 }
110
111 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec3)112 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3)
113 {
114 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings + 1, 0)));
115 }
116
117 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec3Array)118 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3Array)
119 {
120 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2 + 1, 2)));
121 }
122
123 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxVaryingVec3AndOneVec2)124 TEST_P(VaryingPackingTest, MaxVaryingVec3AndOneVec2)
125 {
126 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings, 0);
127 AddVaryings(&varyings, GL_FLOAT_VEC2, 1, 0);
128 ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
129 }
130
131 // This should work since two vec2s are packed in a single register.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec2)132 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec2)
133 {
134 ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings + 1, 0)));
135 }
136
137 // Same for this one as above.
TEST_P(VaryingPackingTest,TwiceMaxVaryingVec2)138 TEST_P(VaryingPackingTest, TwiceMaxVaryingVec2)
139 {
140 ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2, 0)));
141 }
142
143 // This should not work since it overflows available varying space.
TEST_P(VaryingPackingTest,TooManyVaryingVec2)144 TEST_P(VaryingPackingTest, TooManyVaryingVec2)
145 {
146 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2 + 1, 0)));
147 }
148
149 // This should work according to the example GL packing rules - the float varyings are slotted
150 // into the end of the vec3 varying arrays.
TEST_P(VaryingPackingTest,MaxVaryingVec3ArrayAndFloatArrays)151 TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndFloatArrays)
152 {
153 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
154 AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2, 2);
155 ASSERT_TRUE(packVaryings(kMaxVaryings, varyings));
156 }
157
158 // This should not work - it has one too many float arrays.
TEST_P(VaryingPackingTest,MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)159 TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
160 {
161 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
162 AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2 + 1, 2);
163 ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
164 }
165
166 // WebGL should fail to pack max+1 vec2 arrays, unlike our more relaxed packing.
TEST_P(VaryingPackingTest,MaxPlusOneMat2VaryingsFailsWebGL)167 TEST_P(VaryingPackingTest, MaxPlusOneMat2VaryingsFailsWebGL)
168 {
169 auto varyings = MakeVaryings(GL_FLOAT_MAT2, kMaxVaryings / 2 + 1, 0);
170 ASSERT_FALSE(packVaryingsStrict(kMaxVaryings, varyings));
171 }
172
173 // Makes separate tests for different values of kMaxVaryings.
174 INSTANTIATE_TEST_SUITE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8));
175
176 } // anonymous namespace
177