1// 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. 5// 6#include <sstream> 7#include <string> 8#include <vector> 9#include "angle_gl.h" 10#include "gtest/gtest.h" 11#include "GLSLANG/ShaderLang.h" 12 13#define SHADER(Src) #Src 14 15class ExpressionLimitTest : public testing::Test { 16protected: 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; 22 23 virtual void SetUp() 24 { 25 memset(&resources, 0, sizeof(resources)); 26 27 GenerateResources(&resources); 28 } 29 30 // Set up the per compile resources 31 void GenerateResources(ShBuiltInResources* resources) 32 { 33 ShInitBuiltInResources(resources); 34 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; 43 44 resources->OES_standard_derivatives = 0; 45 resources->OES_EGL_image_external = 0; 46 47 resources->MaxExpressionComplexity = kMaxExpressionComplexity; 48 resources->MaxCallStackDepth = kMaxCallStackDepth; 49 } 50 51 void GenerateLongExpression(int length, std::stringstream* ss) 52 { 53 for (int ii = 0; ii < length; ++ii) { 54 *ss << "+ vec4(" << ii << ")"; 55 } 56 } 57 58 std::string GenerateShaderWithLongExpression(int length) 59 { 60 static const char* shaderStart = SHADER( 61 precision mediump float; 62 uniform vec4 u_color; 63 void main() 64 { 65 gl_FragColor = u_color 66 ); 67 68 std::stringstream ss; 69 ss << shaderStart; 70 GenerateLongExpression(length, &ss); 71 ss << "; }"; 72 73 return ss.str(); 74 } 75 76 std::string GenerateShaderWithUnusedLongExpression(int length) 77 { 78 static const char* shaderStart = SHADER( 79 precision mediump float; 80 uniform vec4 u_color; 81 void main() 82 { 83 gl_FragColor = u_color; 84 } 85 vec4 someFunction() { 86 return u_color 87 ); 88 89 std::stringstream ss; 90 91 ss << shaderStart; 92 GenerateLongExpression(length, &ss); 93 ss << "; }"; 94 95 return ss.str(); 96 } 97 98 void GenerateDeepFunctionStack(int length, std::stringstream* ss) 99 { 100 static const char* shaderStart = SHADER( 101 precision mediump float; 102 uniform vec4 u_color; 103 vec4 function0() { 104 return u_color; 105 } 106 ); 107 108 *ss << shaderStart; 109 for (int ii = 0; ii < length; ++ii) { 110 *ss << "vec4 function" << (ii + 1) << "() {\n" 111 << " return function" << ii << "();\n" 112 << "}\n"; 113 } 114 } 115 116 std::string GenerateShaderWithDeepFunctionStack(int length) 117 { 118 std::stringstream ss; 119 120 GenerateDeepFunctionStack(length, &ss); 121 122 ss << "void main() {\n" 123 << " gl_FragColor = function" << length << "();\n" 124 << "}"; 125 126 return ss.str(); 127 } 128 129 std::string GenerateShaderWithUnusedDeepFunctionStack(int length) 130 { 131 std::stringstream ss; 132 133 GenerateDeepFunctionStack(length, &ss); 134 135 ss << "void main() {\n" 136 << " gl_FragColor = vec4(0,0,0,0);\n" 137 << "}"; 138 139 140 return ss.str(); 141 } 142 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, 147 const char* source, 148 int compileOptions, 149 const char* expected_error) { 150 bool success = ShCompile(compiler, &source, 1, compileOptions) != 0; 151 if (success) { 152 success = !expected_error; 153 } else { 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); 159 delete [] buffer; 160 if (expected_error) 161 success = log.find(expected_error) != std::string::npos; 162 163 EXPECT_TRUE(success) << log << "\n----shader----\n" << source; 164 } 165 return success; 166 } 167 168 ShBuiltInResources resources; 169}; 170 171const char* ExpressionLimitTest::kExpressionTooComplex = 172 "Expression too complex"; 173const char* ExpressionLimitTest::kCallStackTooDeep = 174 "call stack too deep"; 175const char* ExpressionLimitTest::kHasRecursion = 176 "Function recursion detected"; 177 178TEST_F(ExpressionLimitTest, ExpressionComplexity) 179{ 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; 185 186 // Test expression under the limit passes. 187 EXPECT_TRUE(CheckShaderCompilation( 188 vertexCompiler, 189 GenerateShaderWithLongExpression( 190 kMaxExpressionComplexity - 10).c_str(), 191 compileOptions, NULL)); 192 // Test expression over the limit fails. 193 EXPECT_TRUE(CheckShaderCompilation( 194 vertexCompiler, 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( 200 vertexCompiler, 201 GenerateShaderWithLongExpression( 202 kMaxExpressionComplexity + 10).c_str(), 203 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL)); 204 ShDestruct(vertexCompiler); 205} 206 207TEST_F(ExpressionLimitTest, UnusedExpressionComplexity) 208{ 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; 214 215 // Test expression under the limit passes. 216 EXPECT_TRUE(CheckShaderCompilation( 217 vertexCompiler, 218 GenerateShaderWithUnusedLongExpression( 219 kMaxExpressionComplexity - 10).c_str(), 220 compileOptions, NULL)); 221 // Test expression over the limit fails. 222 EXPECT_TRUE(CheckShaderCompilation( 223 vertexCompiler, 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( 229 vertexCompiler, 230 GenerateShaderWithUnusedLongExpression( 231 kMaxExpressionComplexity + 10).c_str(), 232 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL)); 233 ShDestruct(vertexCompiler); 234} 235 236TEST_F(ExpressionLimitTest, CallStackDepth) 237{ 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; 243 244 // Test call stack under the limit passes. 245 EXPECT_TRUE(CheckShaderCompilation( 246 vertexCompiler, 247 GenerateShaderWithDeepFunctionStack( 248 kMaxCallStackDepth - 10).c_str(), 249 compileOptions, NULL)); 250 // Test call stack over the limit fails. 251 EXPECT_TRUE(CheckShaderCompilation( 252 vertexCompiler, 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( 258 vertexCompiler, 259 GenerateShaderWithDeepFunctionStack( 260 kMaxCallStackDepth + 10).c_str(), 261 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL)); 262 ShDestruct(vertexCompiler); 263} 264 265TEST_F(ExpressionLimitTest, UnusedCallStackDepth) 266{ 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; 272 273 // Test call stack under the limit passes. 274 EXPECT_TRUE(CheckShaderCompilation( 275 vertexCompiler, 276 GenerateShaderWithUnusedDeepFunctionStack( 277 kMaxCallStackDepth - 10).c_str(), 278 compileOptions, NULL)); 279 // Test call stack over the limit fails. 280 EXPECT_TRUE(CheckShaderCompilation( 281 vertexCompiler, 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( 287 vertexCompiler, 288 GenerateShaderWithUnusedDeepFunctionStack( 289 kMaxCallStackDepth + 10).c_str(), 290 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL)); 291 ShDestruct(vertexCompiler); 292} 293 294TEST_F(ExpressionLimitTest, Recursion) 295{ 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; 301 302 static const char* shaderWithRecursion0 = SHADER( 303 precision mediump float; 304 uniform vec4 u_color; 305 vec4 someFunc() { 306 return someFunc(); 307 } 308 309 void main() { 310 gl_FragColor = u_color * someFunc(); 311 } 312 ); 313 314 static const char* shaderWithRecursion1 = SHADER( 315 precision mediump float; 316 uniform vec4 u_color; 317 318 vec4 someFunc(); 319 320 vec4 someFunc1() { 321 return someFunc(); 322 } 323 324 vec4 someFunc() { 325 return someFunc1(); 326 } 327 328 void main() { 329 gl_FragColor = u_color * someFunc(); 330 } 331 ); 332 333 static const char* shaderWithRecursion2 = SHADER( 334 precision mediump float; 335 uniform vec4 u_color; 336 vec4 someFunc() { 337 if (u_color.x > 0.5) { 338 return someFunc(); 339 } else { 340 return vec4(1); 341 } 342 } 343 344 void main() { 345 gl_FragColor = someFunc(); 346 } 347 ); 348 349 static const char* shaderWithRecursion3 = SHADER( 350 precision mediump float; 351 uniform vec4 u_color; 352 vec4 someFunc() { 353 if (u_color.x > 0.5) { 354 return vec4(1); 355 } else { 356 return someFunc(); 357 } 358 } 359 360 void main() { 361 gl_FragColor = someFunc(); 362 } 363 ); 364 365 static const char* shaderWithRecursion4 = SHADER( 366 precision mediump float; 367 uniform vec4 u_color; 368 vec4 someFunc() { 369 return (u_color.x > 0.5) ? vec4(1) : someFunc(); 370 } 371 372 void main() { 373 gl_FragColor = someFunc(); 374 } 375 ); 376 377 static const char* shaderWithRecursion5 = SHADER( 378 precision mediump float; 379 uniform vec4 u_color; 380 vec4 someFunc() { 381 return (u_color.x > 0.5) ? someFunc() : vec4(1); 382 } 383 384 void main() { 385 gl_FragColor = someFunc(); 386 } 387 ); 388 389 static const char* shaderWithRecursion6 = SHADER( 390 precision mediump float; 391 uniform vec4 u_color; 392 vec4 someFunc() { 393 return someFunc(); 394 } 395 396 void main() { 397 gl_FragColor = u_color; 398 } 399 ); 400 401 static const char* shaderWithNoRecursion = SHADER( 402 precision mediump float; 403 uniform vec4 u_color; 404 405 vec3 rgb(int r, int g, int b) { 406 return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0); 407 } 408 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); 413 414 void main() { 415 gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0); 416 } 417 ); 418 419 static const char* shaderWithRecursion7 = SHADER( 420 precision mediump float; 421 uniform vec4 u_color; 422 423 vec4 function2() { 424 return u_color; 425 } 426 427 vec4 function1() { 428 vec4 a = function2(); 429 vec4 b = function1(); 430 return a + b; 431 } 432 433 void main() { 434 gl_FragColor = function1(); 435 } 436 ); 437 438 static const char* shaderWithRecursion8 = SHADER( 439 precision mediump float; 440 uniform vec4 u_color; 441 442 vec4 function1(); 443 444 vec4 function3() { 445 return function1(); 446 } 447 448 vec4 function2() { 449 return function3(); 450 } 451 452 vec4 function1() { 453 return function2(); 454 } 455 456 void main() { 457 gl_FragColor = function1(); 458 } 459 ); 460 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)); 500 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); 510} 511 512