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)
151 bool success = ShCompile(compiler, &source, 1, compileOptions) != 0;
154 success = !expected_error;
158 std::string log = ShGetInfoLog(compiler);
160 success = log.find(expected_error) != std::string::npos;
162 EXPECT_TRUE(success) << log << "\n----shader----\n" << source;
167 ShBuiltInResources resources;
170 const char* ExpressionLimitTest::kExpressionTooComplex =
171 "Expression too complex";
172 const char* ExpressionLimitTest::kCallStackTooDeep =
173 "call stack too deep";
174 const char* ExpressionLimitTest::kHasRecursion =
175 "Function recursion detected";
177 TEST_F(ExpressionLimitTest, ExpressionComplexity)
179 ShShaderSpec spec = SH_WEBGL_SPEC;
180 ShShaderOutput output = SH_ESSL_OUTPUT;
181 ShHandle vertexCompiler = ShConstructCompiler(
182 GL_FRAGMENT_SHADER, spec, output, &resources);
183 int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
185 // Test expression under the limit passes.
186 EXPECT_TRUE(CheckShaderCompilation(
188 GenerateShaderWithLongExpression(
189 kMaxExpressionComplexity - 10).c_str(),
190 compileOptions, NULL));
191 // Test expression over the limit fails.
192 EXPECT_TRUE(CheckShaderCompilation(
194 GenerateShaderWithLongExpression(
195 kMaxExpressionComplexity + 10).c_str(),
196 compileOptions, kExpressionTooComplex));
197 // Test expression over the limit without a limit does not fail.
198 EXPECT_TRUE(CheckShaderCompilation(
200 GenerateShaderWithLongExpression(
201 kMaxExpressionComplexity + 10).c_str(),
202 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
203 ShDestruct(vertexCompiler);
206 TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)
208 ShShaderSpec spec = SH_WEBGL_SPEC;
209 ShShaderOutput output = SH_ESSL_OUTPUT;
210 ShHandle vertexCompiler = ShConstructCompiler(
211 GL_FRAGMENT_SHADER, spec, output, &resources);
212 int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
214 // Test expression under the limit passes.
215 EXPECT_TRUE(CheckShaderCompilation(
217 GenerateShaderWithUnusedLongExpression(
218 kMaxExpressionComplexity - 10).c_str(),
219 compileOptions, NULL));
220 // Test expression over the limit fails.
221 EXPECT_TRUE(CheckShaderCompilation(
223 GenerateShaderWithUnusedLongExpression(
224 kMaxExpressionComplexity + 10).c_str(),
225 compileOptions, kExpressionTooComplex));
226 // Test expression over the limit without a limit does not fail.
227 EXPECT_TRUE(CheckShaderCompilation(
229 GenerateShaderWithUnusedLongExpression(
230 kMaxExpressionComplexity + 10).c_str(),
231 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
232 ShDestruct(vertexCompiler);
235 TEST_F(ExpressionLimitTest, CallStackDepth)
237 ShShaderSpec spec = SH_WEBGL_SPEC;
238 ShShaderOutput output = SH_ESSL_OUTPUT;
239 ShHandle vertexCompiler = ShConstructCompiler(
240 GL_FRAGMENT_SHADER, spec, output, &resources);
241 int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
243 // Test call stack under the limit passes.
244 EXPECT_TRUE(CheckShaderCompilation(
246 GenerateShaderWithDeepFunctionStack(
247 kMaxCallStackDepth - 10).c_str(),
248 compileOptions, NULL));
249 // Test call stack over the limit fails.
250 EXPECT_TRUE(CheckShaderCompilation(
252 GenerateShaderWithDeepFunctionStack(
253 kMaxCallStackDepth + 10).c_str(),
254 compileOptions, kCallStackTooDeep));
255 // Test call stack over the limit without limit does not fail.
256 EXPECT_TRUE(CheckShaderCompilation(
258 GenerateShaderWithDeepFunctionStack(
259 kMaxCallStackDepth + 10).c_str(),
260 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
261 ShDestruct(vertexCompiler);
264 TEST_F(ExpressionLimitTest, UnusedCallStackDepth)
266 ShShaderSpec spec = SH_WEBGL_SPEC;
267 ShShaderOutput output = SH_ESSL_OUTPUT;
268 ShHandle vertexCompiler = ShConstructCompiler(
269 GL_FRAGMENT_SHADER, spec, output, &resources);
270 int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
272 // Test call stack under the limit passes.
273 EXPECT_TRUE(CheckShaderCompilation(
275 GenerateShaderWithUnusedDeepFunctionStack(
276 kMaxCallStackDepth - 10).c_str(),
277 compileOptions, NULL));
278 // Test call stack over the limit fails.
279 EXPECT_TRUE(CheckShaderCompilation(
281 GenerateShaderWithUnusedDeepFunctionStack(
282 kMaxCallStackDepth + 10).c_str(),
283 compileOptions, kCallStackTooDeep));
284 // Test call stack over the limit without limit does not fail.
285 EXPECT_TRUE(CheckShaderCompilation(
287 GenerateShaderWithUnusedDeepFunctionStack(
288 kMaxCallStackDepth + 10).c_str(),
289 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
290 ShDestruct(vertexCompiler);
293 TEST_F(ExpressionLimitTest, Recursion)
295 ShShaderSpec spec = SH_WEBGL_SPEC;
296 ShShaderOutput output = SH_ESSL_OUTPUT;
297 ShHandle vertexCompiler = ShConstructCompiler(
298 GL_FRAGMENT_SHADER, spec, output, &resources);
299 int compileOptions = 0;
301 static const char* shaderWithRecursion0 = SHADER(
302 precision mediump float;
303 uniform vec4 u_color;
309 gl_FragColor = u_color * someFunc();
313 static const char* shaderWithRecursion1 = SHADER(
314 precision mediump float;
315 uniform vec4 u_color;
328 gl_FragColor = u_color * someFunc();
332 static const char* shaderWithRecursion2 = SHADER(
333 precision mediump float;
334 uniform vec4 u_color;
336 if (u_color.x > 0.5) {
344 gl_FragColor = someFunc();
348 static const char* shaderWithRecursion3 = SHADER(
349 precision mediump float;
350 uniform vec4 u_color;
352 if (u_color.x > 0.5) {
360 gl_FragColor = someFunc();
364 static const char* shaderWithRecursion4 = SHADER(
365 precision mediump float;
366 uniform vec4 u_color;
368 return (u_color.x > 0.5) ? vec4(1) : someFunc();
372 gl_FragColor = someFunc();
376 static const char* shaderWithRecursion5 = SHADER(
377 precision mediump float;
378 uniform vec4 u_color;
380 return (u_color.x > 0.5) ? someFunc() : vec4(1);
384 gl_FragColor = someFunc();
388 static const char* shaderWithRecursion6 = SHADER(
389 precision mediump float;
390 uniform vec4 u_color;
396 gl_FragColor = u_color;
400 static const char* shaderWithNoRecursion = SHADER(
401 precision mediump float;
402 uniform vec4 u_color;
404 vec3 rgb(int r, int g, int b) {
405 return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
408 // these external calls used to incorrectly trigger
409 // recursion detection.
410 vec3 hairColor0 = rgb(151, 200, 234);
411 vec3 faceColor2 = rgb(183, 148, 133);
414 gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);
418 static const char* shaderWithRecursion7 = SHADER(
419 precision mediump float;
420 uniform vec4 u_color;
427 vec4 a = function2();
428 vec4 b = function1();
433 gl_FragColor = function1();
437 static const char* shaderWithRecursion8 = SHADER(
438 precision mediump float;
439 uniform vec4 u_color;
456 gl_FragColor = function1();
460 // Check simple recursions fails.
461 EXPECT_TRUE(CheckShaderCompilation(
462 vertexCompiler, shaderWithRecursion0,
463 compileOptions, kHasRecursion));
464 // Check simple recursions fails.
465 EXPECT_TRUE(CheckShaderCompilation(
466 vertexCompiler, shaderWithRecursion1,
467 compileOptions, kHasRecursion));
468 // Check if recursions fails.
469 EXPECT_TRUE(CheckShaderCompilation(
470 vertexCompiler, shaderWithRecursion2,
471 compileOptions, kHasRecursion));
472 // Check if recursions fails.
473 EXPECT_TRUE(CheckShaderCompilation(
474 vertexCompiler, shaderWithRecursion3,
475 compileOptions, kHasRecursion));
476 // Check ternary recursions fails.
477 EXPECT_TRUE(CheckShaderCompilation(
478 vertexCompiler, shaderWithRecursion4,
479 compileOptions, kHasRecursion));
480 // Check ternary recursions fails.
481 EXPECT_TRUE(CheckShaderCompilation(
482 vertexCompiler, shaderWithRecursion5,
483 compileOptions, kHasRecursion));
484 // Check unused recursions passes.
485 EXPECT_TRUE(CheckShaderCompilation(
486 vertexCompiler, shaderWithRecursion6,
487 compileOptions, NULL));
488 EXPECT_TRUE(CheckShaderCompilation(
489 vertexCompiler, shaderWithRecursion7,
490 compileOptions, kHasRecursion));
491 EXPECT_TRUE(CheckShaderCompilation(
492 vertexCompiler, shaderWithRecursion8,
493 compileOptions, kHasRecursion));
494 // Check unused recursions fails if limiting call stack
495 // since we check all paths.
496 EXPECT_TRUE(CheckShaderCompilation(
497 vertexCompiler, shaderWithRecursion6,
498 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));
500 // Check unused recursions passes.
501 EXPECT_TRUE(CheckShaderCompilation(
502 vertexCompiler, shaderWithNoRecursion,
503 compileOptions, NULL));
504 // Check unused recursions passes if limiting call stack.
505 EXPECT_TRUE(CheckShaderCompilation(
506 vertexCompiler, shaderWithNoRecursion,
507 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, NULL));
508 ShDestruct(vertexCompiler);