Source code
Revision control
Copy as Markdown
Other Tools
<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>All valid constant expressions should be allowed in the initialization of const variables</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/>
<script src="../../../js/js-test-pre.js"></script>
<script src="../../../js/webgl-test-utils.js"></script>
<script src="../../../js/glsl-conformance-test.js"></script>
<script id="VertexTemplate" type="x-shader/x-vertex">
precision mediump float;
$(init)
void main() {
const $(constType) c = $(constantExpression);
gl_Position = vec4(float(c$(constTypeToScalar)));
}
</script>
<script id="FragmentTemplate" type="x-shader/x-fragment">
precision mediump float;
$(init)
void main() {
const $(constType) c = $(constantExpression);
gl_FragColor = vec4(float(c$(constTypeToScalar)));
}
</script>
</head>
<body onload="runTest()">
<div id="description"></div>
<div id="console"></div>
<script type="application/javascript">
"use strict";
description();
var wtu = WebGLTestUtils;
// ESSL 1.00 spec section 4.3.2.
// Initializers for const declarations must be a constant expression.
// ESSL 1.00 spec section 5.10.
// A constant expression is one of
// * a literal value (e.g., 5 or true)
// * a global or local variable qualified as const excluding function parameters
// * an expression formed by an operator on operands that are constant expressions, including getting
// an element of a constant vector or a constant matrix, or a field of a constant structure
// * a constructor whose arguments are all constant expressions
// * a built-in function call whose arguments are all constant expressions, with the exception of the
// texture lookup functions.
var binaryOpsGenTypeRValuesToGenType = [
'+',
'-',
'*',
'/'
];
var binaryOpsScalarsToBool = [
'<',
'>',
'<=',
'>='
];
var binaryOpsRValuesToBool = [
'==',
'!='
];
var binaryOpsBoolsToBool = [
'&&',
'^^',
'||'
];
var builtInsGenTypeToGenType = [
'radians',
'degrees',
'sin',
'cos',
'tan',
'asin',
'acos',
'atan',
'exp',
'log',
'exp2',
'log2',
'sqrt',
'inversesqrt',
'abs',
'sign',
'floor',
'ceil',
'fract'
];
var builtIns2VecToBvec = [
'lessThan',
'lessThanEqual',
'greaterThan',
'greaterThanEqual',
'equal',
'notEqual'
];
var builtIns2GenTypeToGenType = [
'atan',
'pow',
'mod',
'min',
'max',
'step'
];
var runTest = function() {
var vsTemplate = document.getElementById('VertexTemplate').text;
var fsTemplate = document.getElementById('FragmentTemplate').text;
var tests = [];
var i;
var op;
var builtIn;
var pushTest = function(constType, constantExpression, expectSuccess, opt_init) {
if (opt_init === undefined) {
opt_init = '';
}
var constTypeToScalar = '';
if (constType.substring(0, 3) == 'vec' || constType.substring(1, 4) == 'vec') {
constTypeToScalar = '.x';
} else if (constType.substring(0, 3) == 'mat') {
constTypeToScalar = '[0].x';
} else if (constType == 'my_struct') {
constTypeToScalar = '.field';
}
var vs = wtu.replaceParams(vsTemplate, {constType: constType, constantExpression: constantExpression, constTypeToScalar: constTypeToScalar, init: opt_init});
var fs = wtu.replaceParams(fsTemplate, {constType: constType, constantExpression: constantExpression, constTypeToScalar: constTypeToScalar, init: opt_init});
tests.push({
vShaderSource: vs,
vShaderSuccess: expectSuccess,
linkSuccess: expectSuccess,
passMsg: "Assigning " + constantExpression + " to a const in a vertex shader should " + (expectSuccess ? "compile." : "fail compilation.")
});
tests.push({
fShaderSource: fs,
fShaderSuccess: expectSuccess,
linkSuccess: expectSuccess,
passMsg: "Assigning " + constantExpression + " to a const in a fragment shader should " + (expectSuccess ? "compile." : "fail compilation.")
});
}
// Handle some one of a kind cases first
pushTest('float', 'vec4(0.5).x', true);
pushTest('float', 'vec4(0.5)[0]', true);
pushTest('float', 'true ? 0.5 : 0.2', true);
pushTest('my_struct', 'my_struct(0.5, 0.2)', true, 'struct my_struct { float field; float field2; };');
pushTest('float', '(0.2, 0.5)', true);
pushTest('float', 'clamp(0.2, 0.3, 0.4)', true);
pushTest('float', 'mix(0.2, 0.3, 0.4)', true);
pushTest('float', 'smoothstep(0.2, 0.3, 0.4)', true);
pushTest('float', 'length(vec4(0.5))', true);
pushTest('float', 'distance(vec4(0.5), vec4(0.2))', true);
pushTest('float', 'dot(vec4(0.5), vec4(0.2))', true);
pushTest('vec3', 'cross(vec3(0.5), vec3(0.2))', true);
pushTest('vec4', 'normalize(vec4(0.5))', true);
pushTest('vec4', 'faceforward(vec4(0.2), vec4(0.3), vec4(0.4))', true);
pushTest('vec4', 'reflect(vec4(0.2), vec4(0.5))', true);
pushTest('vec4', 'refract(vec4(0.2), vec4(0.3), 0.4)', true);
pushTest('mat4', 'matrixCompMult(mat4(0.2), mat4(0.5))', true);
// Handle built-in constructors
for (i = 2; i <= 4; ++i) {
var vecType = 'vec' + i;
pushTest(vecType, vecType + '(0.5)', true);
pushTest('i' + vecType, 'i' + vecType + '(1)', true);
pushTest('b' + vecType, 'b' + vecType + '(true)', true);
pushTest('mat' + i, 'mat' + i + '(0.5)', true);
}
// Handle ops
for (i = 0; i < binaryOpsGenTypeRValuesToGenType.length; ++i) {
var op = binaryOpsGenTypeRValuesToGenType[i];
pushTest('float', '0.2 ' + op + ' 0.5', true);
pushTest('vec4', 'vec4(0.2) ' + op + ' vec4(0.5)', true);
pushTest('mat4', 'mat4(0.2) ' + op + ' mat4(0.5)', true);
}
for (i = 0; i < binaryOpsScalarsToBool.length; ++i) {
var op = binaryOpsScalarsToBool[i];
pushTest('bool', '0.2 ' + op + ' 0.5', true);
}
for (i = 0; i < binaryOpsRValuesToBool.length; ++i) {
var op = binaryOpsRValuesToBool[i];
pushTest('bool', '0.2 ' + op + ' 0.5', true);
pushTest('bool', 'vec4(0.2) ' + op + ' vec4(0.5)', true);
}
for (i = 0; i < binaryOpsBoolsToBool.length; ++i) {
var op = binaryOpsBoolsToBool[i];
pushTest('bool', 'false ' + op + ' true', true);
}
// Handle allowed built-ins
for (i = 0; i < builtInsGenTypeToGenType.length; ++i) {
builtIn = builtInsGenTypeToGenType[i];
pushTest('float', builtIn + '(0.5)', true);
pushTest('vec4', builtIn + '(vec4(0.5))', true);
}
for (i = 0; i < builtIns2VecToBvec.length; ++i) {
builtIn = builtIns2VecToBvec[i];
pushTest('bvec4', builtIn + '(vec4(0.2), vec4(0.5))', true);
}
for (i = 0; i < builtIns2GenTypeToGenType.length; ++i) {
builtIn = builtIns2GenTypeToGenType[i];
pushTest('float', builtIn + '(0.2, 0.5)', true);
pushTest('vec4', builtIn + '(vec4(0.2), vec4(0.5))', true);
}
// Include some expressions with a constant variable reference
pushTest('float', 'cc', true, 'const float cc = 0.5;');
pushTest('float', 'cc + cc2', true, 'const float cc = 0.5; const float cc2 = 0.2;');
pushTest('float', 'sqrt(cc)', true, 'const float cc = 0.5;');
GLSLConformanceTester.runTests(tests);
}
var successfullyParsed = true;
</script>
</body>
</html>