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(const std::vector<sh::ShaderVariable> & shVaryings,VaryingPacking * varyingPacking)29 bool testVaryingPacking(const std::vector<sh::ShaderVariable> &shVaryings,
30 VaryingPacking *varyingPacking)
31 {
32 std::vector<PackedVarying> packedVaryings;
33 for (const sh::ShaderVariable &shVarying : shVaryings)
34 {
35 packedVaryings.push_back(PackedVarying(
36 VaryingInShaderRef(ShaderType::Vertex, &shVarying),
37 VaryingInShaderRef(ShaderType::Fragment, &shVarying), shVarying.interpolation));
38 }
39
40 InfoLog infoLog;
41 std::vector<std::string> transformFeedbackVaryings;
42
43 return varyingPacking->packUserVaryings(infoLog, packedVaryings);
44 }
45
46 // Uses the "relaxed" ANGLE packing mode.
packVaryings(GLuint maxVaryings,const std::vector<sh::ShaderVariable> & shVaryings)47 bool packVaryings(GLuint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
48 {
49 VaryingPacking varyingPacking(maxVaryings, PackMode::ANGLE_RELAXED);
50 return testVaryingPacking(shVaryings, &varyingPacking);
51 }
52
53 // Uses the stricter WebGL style packing rules.
packVaryingsStrict(GLuint maxVaryings,const std::vector<sh::ShaderVariable> & shVaryings)54 bool packVaryingsStrict(GLuint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
55 {
56 VaryingPacking varyingPacking(maxVaryings, PackMode::WEBGL_STRICT);
57 return testVaryingPacking(shVaryings, &varyingPacking);
58 }
59
60 const int kMaxVaryings = GetParam();
61 };
62
MakeVaryings(GLenum type,size_t count,size_t arraySize)63 std::vector<sh::ShaderVariable> MakeVaryings(GLenum type, size_t count, size_t arraySize)
64 {
65 std::vector<sh::ShaderVariable> varyings;
66
67 for (size_t index = 0; index < count; ++index)
68 {
69 std::stringstream strstr;
70 strstr << type << index;
71
72 sh::ShaderVariable varying;
73 varying.type = type;
74 varying.precision = GL_MEDIUM_FLOAT;
75 varying.name = strstr.str();
76 varying.mappedName = strstr.str();
77 if (arraySize > 0)
78 {
79 varying.arraySizes.push_back(static_cast<unsigned int>(arraySize));
80 }
81 varying.staticUse = true;
82 varying.interpolation = sh::INTERPOLATION_FLAT;
83 varying.isInvariant = false;
84
85 varyings.push_back(varying);
86 }
87
88 return varyings;
89 }
90
AddVaryings(std::vector<sh::ShaderVariable> * varyings,GLenum type,size_t count,size_t arraySize)91 void AddVaryings(std::vector<sh::ShaderVariable> *varyings,
92 GLenum type,
93 size_t count,
94 size_t arraySize)
95 {
96 const auto &newVaryings = MakeVaryings(type, count, arraySize);
97 varyings->insert(varyings->end(), newVaryings.begin(), newVaryings.end());
98 }
99
100 // Test that a single varying can't overflow the packing.
TEST_P(VaryingPackingTest,OneVaryingLargerThanMax)101 TEST_P(VaryingPackingTest, OneVaryingLargerThanMax)
102 {
103 ASSERT_FALSE(packVaryings(1, MakeVaryings(GL_FLOAT_MAT4, 1, 0)));
104 }
105
106 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec3)107 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3)
108 {
109 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings + 1, 0)));
110 }
111
112 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec3Array)113 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3Array)
114 {
115 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2 + 1, 2)));
116 }
117
118 // This will overflow the available varying space.
TEST_P(VaryingPackingTest,MaxVaryingVec3AndOneVec2)119 TEST_P(VaryingPackingTest, MaxVaryingVec3AndOneVec2)
120 {
121 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings, 0);
122 AddVaryings(&varyings, GL_FLOAT_VEC2, 1, 0);
123 ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
124 }
125
126 // This should work since two vec2s are packed in a single register.
TEST_P(VaryingPackingTest,MaxPlusOneVaryingVec2)127 TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec2)
128 {
129 ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings + 1, 0)));
130 }
131
132 // Same for this one as above.
TEST_P(VaryingPackingTest,TwiceMaxVaryingVec2)133 TEST_P(VaryingPackingTest, TwiceMaxVaryingVec2)
134 {
135 ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2, 0)));
136 }
137
138 // This should not work since it overflows available varying space.
TEST_P(VaryingPackingTest,TooManyVaryingVec2)139 TEST_P(VaryingPackingTest, TooManyVaryingVec2)
140 {
141 ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2 + 1, 0)));
142 }
143
144 // This should work according to the example GL packing rules - the float varyings are slotted
145 // into the end of the vec3 varying arrays.
TEST_P(VaryingPackingTest,MaxVaryingVec3ArrayAndFloatArrays)146 TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndFloatArrays)
147 {
148 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
149 AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2, 2);
150 ASSERT_TRUE(packVaryings(kMaxVaryings, varyings));
151 }
152
153 // This should not work - it has one too many float arrays.
TEST_P(VaryingPackingTest,MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)154 TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
155 {
156 std::vector<sh::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
157 AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2 + 1, 2);
158 ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
159 }
160
161 // WebGL should fail to pack max+1 vec2 arrays, unlike our more relaxed packing.
TEST_P(VaryingPackingTest,MaxPlusOneMat2VaryingsFailsWebGL)162 TEST_P(VaryingPackingTest, MaxPlusOneMat2VaryingsFailsWebGL)
163 {
164 auto varyings = MakeVaryings(GL_FLOAT_MAT2, kMaxVaryings / 2 + 1, 0);
165 ASSERT_FALSE(packVaryingsStrict(kMaxVaryings, varyings));
166 }
167
168 // Makes separate tests for different values of kMaxVaryings.
169 INSTANTIATE_TEST_SUITE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8));
170
171 } // anonymous namespace
172