// // Copyright 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // QualificationOrder_test.cpp: // OpenGL ES 3.1 removes the strict order of qualifiers imposed by the grammar. // This file contains tests for invalid order and usage of qualifiers. #include "tests/test_utils/ShaderCompileTreeTest.h" using namespace sh; class QualificationOrderFragmentShaderTest : public ShaderCompileTreeTest { public: QualificationOrderFragmentShaderTest() {} protected: void initResources(ShBuiltInResources *resources) override { resources->MaxDrawBuffers = (getShaderSpec() == SH_GLES2_SPEC) ? 1 : 8; } ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; } ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; } }; class QualificationOrderVertexShaderTest : public QualificationOrderFragmentShaderTest { public: QualificationOrderVertexShaderTest() {} protected: ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; } }; // Repeating centroid qualifier is invalid. TEST_F(QualificationOrderFragmentShaderTest, RepeatingCentroid) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "flat centroid centroid in float myValue;\n" "void main() {\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Repeating uniform storage qualifiers is invalid. TEST_F(QualificationOrderFragmentShaderTest, RepeatingUniforms) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "uniform uniform float myValue;\n" "void main() {\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Repeating varying storage qualifiers is invalid. TEST_F(QualificationOrderFragmentShaderTest, RepeatingVaryings) { const std::string &shaderString = "precision mediump float;\n" "varying varying vec4 myColor;\n" "void main() {\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Layout qualifier should be before the storage qualifiers. TEST_F(QualificationOrderFragmentShaderTest, WrongOrderQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "out layout(location=1) vec4 myColor;\n" "void main() {\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Centroid out is the correct order. Out centroid is incorrect. TEST_F(QualificationOrderVertexShaderTest, WrongOrderCentroidOut) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 uv;\n" "out centroid vec4 position;\n" "void main() {\n" "position = uv;\n" "gl_Position = uv;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Centroid in is the correct order. In centroid is incorrect. TEST_F(QualificationOrderFragmentShaderTest, WrongOrderCentroidIn) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in centroid vec4 colorIN;\n" "out vec4 colorOUT;\n" "void main() {\n" "colorOUT = colorIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Type cannot be before the storage qualifier. TEST_F(QualificationOrderFragmentShaderTest, WrongOrderTypeStorage) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "centroid in vec4 colorIN;\n" "vec4 out colorOUT;\n" "void main() {\n" "colorOUT = colorIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have two conflicting storage qualifiers. TEST_F(QualificationOrderFragmentShaderTest, RepeatingDifferentStorageQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "centroid in vec4 colorIN;\n" "uniform out vec4 colorOUT;\n" "void main() {\n" "colorOUT = colorIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have two different layout qualifiers. TEST_F(QualificationOrderFragmentShaderTest, RepeatingLayoutQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 colorIN;\n" "layout(location=0) layout(location=0) out vec4 colorOUT;\n" "void main() {\n" "colorOUT = colorIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have repeating invariant qualifiers. TEST_F(QualificationOrderFragmentShaderTest, RepeatingInvariantQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 colorIN;\n" "invariant invariant out vec4 colorOUT;\n" "void main() {\n" "colorOUT = colorIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have repeating storage qualifiers. TEST_F(QualificationOrderVertexShaderTest, RepeatingAttributes) { const std::string &shaderString = "precision mediump float;\n" "attribute attribute vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Wrong order for invariant varying. It should be 'invariant varying', not 'varying invariant'. TEST_F(QualificationOrderVertexShaderTest, VaryingInvariantWrongOrder) { const std::string &shaderString = "precision mediump float;\n" "attribute vec4 positionIN;\n" "varying invariant vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have repeating storage qualifiers. TEST_F(QualificationOrderVertexShaderTest, AttributeVaryingMix) { const std::string &shaderString = "precision mediump float;\n" "attribute varying vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have repeating storage qualifiers. TEST_F(QualificationOrderVertexShaderTest, VaryingAttributeMix) { const std::string &shaderString = "precision mediump float;\n" "varying attribute vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have repeating interpolation qualifiers. TEST_F(QualificationOrderVertexShaderTest, RepeatingInterpolationQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 positionIN;\n" "flat flat out vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Wrong order for the interpolation and storage qualifier. The correct order is interpolation // qualifier and then storage qualifier. TEST_F(QualificationOrderVertexShaderTest, WrongOrderInterpolationStorageQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 positionIN;\n" "out flat vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // The correct order is invariant, interpolation, storage. TEST_F(QualificationOrderVertexShaderTest, WrongOrderInvariantInterpolationStorageQualifiers) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 positionIN;\n" "flat invariant out vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // The invariant qualifer has to be before the storage qualifiers. TEST_F(QualificationOrderVertexShaderTest, WrongOrderInvariantNotFirst) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 positionIN;\n" "centroid out invariant vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // The precision qualifier is after the storage qualifiers. TEST_F(QualificationOrderVertexShaderTest, WrongOrderPrecision) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in vec4 positionIN;\n" "highp centroid out vec4 dataOUT;\n" "void main() {\n" "gl_Position = positionIN;\n" "dataOUT = 0.5 * dataOUT + vec4(0.5);\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have multiple declarations of the 'in' storage qualifier. TEST_F(QualificationOrderVertexShaderTest, RepeatingInQualifier) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "in in vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // A variable cannot have multiple declarations of the 'attribute' storage qualifier. TEST_F(QualificationOrderVertexShaderTest, RepeatingAttributeQualifier) { const std::string &shaderString = "precision mediump float;\n" "attribute attribute vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Vertex input cannot be qualified with invariant. TEST_F(QualificationOrderVertexShaderTest, InvariantVertexInput) { const std::string &shaderString = "precision mediump float;\n" "invariant attribute vec4 positionIN;\n" "void main() {\n" "gl_Position = positionIN;\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } } // Cannot have a function parameter with the invariant qualifier. TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersInvariant) { const std::string &shaderString = "precision lowp float;\n" "varying float value;\n" "float foo0 (invariant in float x) {\n" " return 2.0*x;\n" "}\n" "void main()\n" "{\n" " gl_FragColor = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Cannot have a function parameter with the attribute qualifier. TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersAttribute) { const std::string &shaderString = "precision lowp float;\n" "varying float value;\n" "float foo0 (attribute float x) {\n" " return 2.0*x;\n" "}\n" "void main()\n" "{\n" " gl_FragColor = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Cannot have a function parameter with the varying qualifier. TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersVarying) { const std::string &shaderString = "precision lowp float;\n" "varying float value;\n" "float foo0 (varying float x) {\n" " return 2.0*x;\n" "}\n" "void main()\n" "{\n" " gl_FragColor = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Cannot have a function parameter with the layout qualifier TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersLayout) { const std::string &shaderString = "#version 300 es\n" "precision lowp float;\n" "in float value;\n" "float foo0 (layout(location = 3) in float x) {\n" " return 2.0*x;\n" "}\n" "out vec4 colorOUT;\n" "void main()\n" "{\n" " colorOUT = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Cannot have a function parameter with the centroid qualifier TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersCentroidIn) { const std::string &shaderString = "#version 300 es\n" "precision lowp float;\n" "in float value;\n" "float foo0 (centroid in float x) {\n" " return 2.0*x;\n" "}\n" "out vec4 colorOUT;\n" "void main()\n" "{\n" " colorOUT = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Cannot have a function parameter with the flat qualifier TEST_F(QualificationOrderFragmentShaderTest, InvalidFunctionParametersFlatIn) { const std::string &shaderString = "#version 300 es\n" "precision lowp float;\n" "in float value;\n" "float foo0 (flat in float x) {\n" " return 2.0*x;\n" "}\n" "out vec4 colorOUT;\n" "void main()\n" "{\n" " colorOUT = vec4(foo0(value));\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure" << mInfoLog; } } // Output layout location qualifier can't appear more than once within a declaration. // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers. TEST_F(QualificationOrderFragmentShaderTest, TwoOutputLocations) { const std::string &shaderString = "#version 300 es\n" "precision mediump float;\n" "layout(location=1, location=2) out vec4 myColor;\n" "void main() {\n" "}\n"; if (compile(shaderString)) { FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; } }