2 // Copyright (c) 2002-2013 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.
10 #include "gtest/gtest.h"
11 #include "GLSLANG/ShaderLang.h"
13 #define SHADER(Src) #Src
15 class ExpressionLimitTest : public testing::Test {
17 static const int kMaxExpressionComplexity = 16;
18 static const int kMaxCallStackDepth = 16;
19 static const char* kExpressionTooComplex;
20 static const char* kCallStackTooDeep;
21 static const char* kHasRecursion;
25 memset(&resources, 0, sizeof(resources));
27 GenerateResources(&resources);
30 // Set up the per compile resources
31 void GenerateResources(ShBuiltInResources* resources)
33 ShInitBuiltInResources(resources);
35 resources->MaxVertexAttribs = 8;
36 resources->MaxVertexUniformVectors = 128;
37 resources->MaxVaryingVectors = 8;
38 resources->MaxVertexTextureImageUnits = 0;
39 resources->MaxCombinedTextureImageUnits = 8;
40 resources->MaxTextureImageUnits = 8;
41 resources->MaxFragmentUniformVectors = 16;
42 resources->MaxDrawBuffers = 1;
44 resources->OES_standard_derivatives = 0;
45 resources->OES_EGL_image_external = 0;
47 resources->MaxExpressionComplexity = kMaxExpressionComplexity;
48 resources->MaxCallStackDepth = kMaxCallStackDepth;
51 void GenerateLongExpression(int length, std::stringstream* ss)
53 for (int ii = 0; ii < length; ++ii) {
54 *ss << "+ vec4(" << ii << ")";
58 std::string GenerateShaderWithLongExpression(int length)
60 static const char* shaderStart = SHADER(
61 precision mediump float;
65 gl_FragColor = u_color
70 GenerateLongExpression(length, &ss);
76 std::string GenerateShaderWithUnusedLongExpression(int length)
78 static const char* shaderStart = SHADER(
79 precision mediump float;
83 gl_FragColor = u_color;
92 GenerateLongExpression(length, &ss);
98 void GenerateDeepFunctionStack(int length, std::stringstream* ss)
100 static const char* shaderStart = SHADER(
101 precision mediump float;
102 uniform vec4 u_color;
109 for (int ii = 0; ii < length; ++ii) {
110 *ss << "vec4 function" << (ii + 1) << "() {\n"
111 << " return function" << ii << "();\n"
116 std::string GenerateShaderWithDeepFunctionStack(int length)
118 std::stringstream ss;
120 GenerateDeepFunctionStack(length, &ss);
122 ss << "void main() {\n"
123 << " gl_FragColor = function" << length << "();\n"
129 std::string GenerateShaderWithUnusedDeepFunctionStack(int length)
131 std::stringstream ss;
133 GenerateDeepFunctionStack(length, &ss);
135 ss << "void main() {\n"
136 << " gl_FragColor = vec4(0,0,0,0);\n"
143 // Compiles a shader and if there's an error checks for a specific
144 // substring in the error log. This way we know the error is specific
145 // to the issue we are testing.
146 bool CheckShaderCompilation(ShHandle compiler,
149 const char* expected_error) {
150 bool success = ShCompile(compiler, &source, 1, compileOptions) != 0;
152 success = !expected_error;
154 size_t bufferLen = 0;
155 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen);
156 char* buffer(new char [bufferLen]);
157 ShGetInfoLog(compiler, buffer);
158 std::string log(buffer, buffer + bufferLen);
161 success = log.find(expected_error) != std::string::npos;
163 EXPECT_TRUE(success) << log << "\n----shader----\n" << source;
168 ShBuiltInResources resources;
171 const char* ExpressionLimitTest::kExpressionTooComplex =
172 "Expression too complex";
173 const char* ExpressionLimitTest::kCallStackTooDeep =
174 "call stack too deep";
175 const char* ExpressionLimitTest::kHasRecursion =
176 "Function recursion detected";
178 TEST_F(ExpressionLimitTest, ExpressionComplexity)
180 ShShaderSpec spec = SH_WEBGL_SPEC;
181 ShShaderOutput output = SH_ESSL_OUTPUT;
182 ShHandle vertexCompiler = ShConstructCompiler(
183 GL_FRAGMENT_SHADER, spec, output, &resources);
184 int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
186 // Test expression under the limit passes.
187 EXPECT_TRUE(CheckShaderCompilation(
189 GenerateShaderWithLongExpression(
190 kMaxExpressionComplexity - 10).c_str(),
191 compileOptions, NULL));
192 // Test expression over the limit fails.
193 EXPECT_TRUE(CheckShaderCompilation(
195 GenerateShaderWithLongExpression(
196 kMaxExpressionComplexity + 10).c_str(),
197 compileOptions, kExpressionTooComplex));
198 // Test expression over the limit without a limit does not fail.
199 EXPECT_TRUE(CheckShaderCompilation(
201 GenerateShaderWithLongExpression(
202 kMaxExpressionComplexity + 10).c_str(),
203 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
204 ShDestruct(vertexCompiler);
207 TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)
209 ShShaderSpec spec = SH_WEBGL_SPEC;
210 ShShaderOutput output = SH_ESSL_OUTPUT;
211 ShHandle vertexCompiler = ShConstructCompiler(
212 GL_FRAGMENT_SHADER, spec, output, &resources);
213 int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
215 // Test expression under the limit passes.
216 EXPECT_TRUE(CheckShaderCompilation(
218 GenerateShaderWithUnusedLongExpression(
219 kMaxExpressionComplexity - 10).c_str(),
220 compileOptions, NULL));
221 // Test expression over the limit fails.
222 EXPECT_TRUE(CheckShaderCompilation(
224 GenerateShaderWithUnusedLongExpression(
225 kMaxExpressionComplexity + 10).c_str(),
226 compileOptions, kExpressionTooComplex));
227 // Test expression over the limit without a limit does not fail.
228 EXPECT_TRUE(CheckShaderCompilation(
230 GenerateShaderWithUnusedLongExpression(
231 kMaxExpressionComplexity + 10).c_str(),
232 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
233 ShDestruct(vertexCompiler);
236 TEST_F(ExpressionLimitTest, CallStackDepth)
238 ShShaderSpec spec = SH_WEBGL_SPEC;
239 ShShaderOutput output = SH_ESSL_OUTPUT;
240 ShHandle vertexCompiler = ShConstructCompiler(
241 GL_FRAGMENT_SHADER, spec, output, &resources);
242 int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
244 // Test call stack under the limit passes.
245 EXPECT_TRUE(CheckShaderCompilation(
247 GenerateShaderWithDeepFunctionStack(
248 kMaxCallStackDepth - 10).c_str(),
249 compileOptions, NULL));
250 // Test call stack over the limit fails.
251 EXPECT_TRUE(CheckShaderCompilation(
253 GenerateShaderWithDeepFunctionStack(
254 kMaxCallStackDepth + 10).c_str(),
255 compileOptions, kCallStackTooDeep));
256 // Test call stack over the limit without limit does not fail.
257 EXPECT_TRUE(CheckShaderCompilation(
259 GenerateShaderWithDeepFunctionStack(
260 kMaxCallStackDepth + 10).c_str(),
261 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
262 ShDestruct(vertexCompiler);
265 TEST_F(ExpressionLimitTest, UnusedCallStackDepth)
267 ShShaderSpec spec = SH_WEBGL_SPEC;
268 ShShaderOutput output = SH_ESSL_OUTPUT;
269 ShHandle vertexCompiler = ShConstructCompiler(
270 GL_FRAGMENT_SHADER, spec, output, &resources);
271 int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
273 // Test call stack under the limit passes.
274 EXPECT_TRUE(CheckShaderCompilation(
276 GenerateShaderWithUnusedDeepFunctionStack(
277 kMaxCallStackDepth - 10).c_str(),
278 compileOptions, NULL));
279 // Test call stack over the limit fails.
280 EXPECT_TRUE(CheckShaderCompilation(
282 GenerateShaderWithUnusedDeepFunctionStack(
283 kMaxCallStackDepth + 10).c_str(),
284 compileOptions, kCallStackTooDeep));
285 // Test call stack over the limit without limit does not fail.
286 EXPECT_TRUE(CheckShaderCompilation(
288 GenerateShaderWithUnusedDeepFunctionStack(
289 kMaxCallStackDepth + 10).c_str(),
290 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
291 ShDestruct(vertexCompiler);
294 TEST_F(ExpressionLimitTest, Recursion)
296 ShShaderSpec spec = SH_WEBGL_SPEC;
297 ShShaderOutput output = SH_ESSL_OUTPUT;
298 ShHandle vertexCompiler = ShConstructCompiler(
299 GL_FRAGMENT_SHADER, spec, output, &resources);
300 int compileOptions = 0;
302 static const char* shaderWithRecursion0 = SHADER(
303 precision mediump float;
304 uniform vec4 u_color;
310 gl_FragColor = u_color * someFunc();
314 static const char* shaderWithRecursion1 = SHADER(
315 precision mediump float;
316 uniform vec4 u_color;
329 gl_FragColor = u_color * someFunc();
333 static const char* shaderWithRecursion2 = SHADER(
334 precision mediump float;
335 uniform vec4 u_color;
337 if (u_color.x > 0.5) {
345 gl_FragColor = someFunc();
349 static const char* shaderWithRecursion3 = SHADER(
350 precision mediump float;
351 uniform vec4 u_color;
353 if (u_color.x > 0.5) {
361 gl_FragColor = someFunc();
365 static const char* shaderWithRecursion4 = SHADER(
366 precision mediump float;
367 uniform vec4 u_color;
369 return (u_color.x > 0.5) ? vec4(1) : someFunc();
373 gl_FragColor = someFunc();
377 static const char* shaderWithRecursion5 = SHADER(
378 precision mediump float;
379 uniform vec4 u_color;
381 return (u_color.x > 0.5) ? someFunc() : vec4(1);
385 gl_FragColor = someFunc();
389 static const char* shaderWithRecursion6 = SHADER(
390 precision mediump float;
391 uniform vec4 u_color;
397 gl_FragColor = u_color;
401 static const char* shaderWithNoRecursion = SHADER(
402 precision mediump float;
403 uniform vec4 u_color;
405 vec3 rgb(int r, int g, int b) {
406 return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
409 // these external calls used to incorrectly trigger
410 // recursion detection.
411 vec3 hairColor0 = rgb(151, 200, 234);
412 vec3 faceColor2 = rgb(183, 148, 133);
415 gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);
419 static const char* shaderWithRecursion7 = SHADER(
420 precision mediump float;
421 uniform vec4 u_color;
428 vec4 a = function2();
429 vec4 b = function1();
434 gl_FragColor = function1();
438 static const char* shaderWithRecursion8 = SHADER(
439 precision mediump float;
440 uniform vec4 u_color;
457 gl_FragColor = function1();
461 // Check simple recursions fails.
462 EXPECT_TRUE(CheckShaderCompilation(
463 vertexCompiler, shaderWithRecursion0,
464 compileOptions, kHasRecursion));
465 // Check simple recursions fails.
466 EXPECT_TRUE(CheckShaderCompilation(
467 vertexCompiler, shaderWithRecursion1,
468 compileOptions, kHasRecursion));
469 // Check if recursions fails.
470 EXPECT_TRUE(CheckShaderCompilation(
471 vertexCompiler, shaderWithRecursion2,
472 compileOptions, kHasRecursion));
473 // Check if recursions fails.
474 EXPECT_TRUE(CheckShaderCompilation(
475 vertexCompiler, shaderWithRecursion3,
476 compileOptions, kHasRecursion));
477 // Check ternary recursions fails.
478 EXPECT_TRUE(CheckShaderCompilation(
479 vertexCompiler, shaderWithRecursion4,
480 compileOptions, kHasRecursion));
481 // Check ternary recursions fails.
482 EXPECT_TRUE(CheckShaderCompilation(
483 vertexCompiler, shaderWithRecursion5,
484 compileOptions, kHasRecursion));
485 // Check unused recursions passes.
486 EXPECT_TRUE(CheckShaderCompilation(
487 vertexCompiler, shaderWithRecursion6,
488 compileOptions, NULL));
489 EXPECT_TRUE(CheckShaderCompilation(
490 vertexCompiler, shaderWithRecursion7,
491 compileOptions, kHasRecursion));
492 EXPECT_TRUE(CheckShaderCompilation(
493 vertexCompiler, shaderWithRecursion8,
494 compileOptions, kHasRecursion));
495 // Check unused recursions fails if limiting call stack
496 // since we check all paths.
497 EXPECT_TRUE(CheckShaderCompilation(
498 vertexCompiler, shaderWithRecursion6,
499 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));
501 // Check unused recursions passes.
502 EXPECT_TRUE(CheckShaderCompilation(
503 vertexCompiler, shaderWithNoRecursion,
504 compileOptions, NULL));
505 // Check unused recursions passes if limiting call stack.
506 EXPECT_TRUE(CheckShaderCompilation(
507 vertexCompiler, shaderWithNoRecursion,
508 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, NULL));
509 ShDestruct(vertexCompiler);