Skip to content

Commit

Permalink
Don't generate INVALID_VALUE in shaderSource. (KhronosGroup#3206)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdashg authored Jan 27, 2021
1 parent 2cc826a commit 7a38f9b
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 152 deletions.
254 changes: 116 additions & 138 deletions sdk/tests/conformance/glsl/bugs/character-set.html
Original file line number Diff line number Diff line change
@@ -1,138 +1,116 @@
<!--
Copyright (c) 2020 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>Character Set</title>
<link rel="stylesheet" href="../../../resources/js-test-style.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>
</head>
<body>

<script id="fs-invalid-0" type="x-shader/x-fragment">
precision mediump float;
$
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
</script>

<script id="fs-invalid-1" type="x-shader/x-fragment">
precision mediump float;
一些注释
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
</script>

<script id="fs-invalid-2" type="x-shader/x-fragment">
precision mediump float;
#if defined(NOT_DEFINED_FOO)
一些注释
#endif
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
</script>

<script id="fs-comment-valid" type="x-shader/x-fragment">
precision mediump float;
// some comment: asdf1234~!@#$%^&*()-=[];',./{}:"?><_+
// some comment: 一些注释 (╯‵□′)╯︵┻━┻
// some comment: \\\\\\\\\
// some comment: \n\\r\n
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
</script>

<script id="fs-cleared-by-preprocessing-valid" type="x-shader/x-fragment">
precision mediump float;
#if defined(GL_GOOGLE_cpp_style_line_directive)
#line 9 "foo.txt"
#endif
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
</script>

<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="2" height="2"> </canvas>
<script>
"use strict";
// See http://crbug.com/1108588 for original failing case.
// Check "OpenGL Registry The OpenGL ES Shading Language"
// Section 3.2 Character Sets For more info
description("This test checks character set validation for glsl.");

debug("");
debug("Canvas.getContext");

let wtu = WebGLTestUtils;
let gl = wtu.create3DContext("canvas");
let consoleDiv = document.getElementById("console");
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");

debug("");
debug("Checking shader character set validation and compilation");

runTest();
}

function testShaderSource(shaderId, expected, msg) {
let shaderSource = document.getElementById(shaderId).text;
if (!quietMode()) {
wtu.addShaderSource(consoleDiv, "test fragment shader", shaderSource);
}

let shader = gl.createShader(gl.FRAGMENT_SHADER);
if (shader == null) {
testFailed("*** Error: unable to create shader '" + shaderSource + "'");
return;
}

gl.shaderSource(shader, shaderSource);
wtu.glErrorShouldBe(gl, expected, msg);
}

function runTest() {

testShaderSource('fs-invalid-0', gl.INVALID_VALUE, 'Unallowed characters detected');
testShaderSource('fs-invalid-1', gl.INVALID_VALUE, 'Unallowed characters detected');
testShaderSource('fs-invalid-2', gl.INVALID_VALUE, 'Non ASCII characters detected that would be cleared by preprocessing step is still invalid');

GLSLConformanceTester.runTests([
{
fShaderId: 'fs-comment-valid',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Unallowed characters and UTF-8 characters in comment are valid'
},
{
fShaderId: 'fs-cleared-by-preprocessing-valid',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Unsupported shader extensions (with invalid ASCII characters) cleared by preprocessing step is valid'
},
]);
}

debug("");
var successfullyParsed = true;

</script>
<script src="../../../js/js-test-post.js"></script>

</body>
</html>
<!--
Copyright (c) 2020 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>Character Set</title>
<link rel="stylesheet" href="../../../resources/js-test-style.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>
</head>
<body>

<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="2" height="2"> </canvas>
<script>
"use strict";
// See http://crbug.com/1108588 for original failing case.
// Check "OpenGL Registry The OpenGL ES Shading Language"
// Section 3.2 Character Sets For more info
description("This test checks character set validation for glsl.");

debug("");
debug("Canvas.getContext");

let wtu = WebGLTestUtils;
let gl = wtu.create3DContext("canvas");
let consoleDiv = document.getElementById("console");
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");

debug("");
debug("Checking shader character set validation and compilation");

runTest();
}

function testShaderSource(shaderSource, msg) {
if (!quietMode()) {
wtu.addShaderSource(consoleDiv, "test fragment shader", shaderSource);
}

let shader = gl.createShader(gl.FRAGMENT_SHADER);
if (shader == null) {
testFailed("*** Error: unable to create shader '" + shaderSource + "'");
return;
}

gl.shaderSource(shader, shaderSource);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, msg);
}

function MUST(ifTruthy) {
return ifTruthy ? 'MUST' : 'MUST NOT';
}

function runTest() {

const BAD_STRINGS = [
'$',
'"',
'一些注释',
'#line 42 "foo.glsl"',
];
const TESTS = [
['in identifier', s => s, false],
['in comment', s => `// ${s}`, true, true],
['in ifdef-out', s => `#if 0 \n${s} \n#endif`, true],
['in ifdef-out #preproc', s => `#if 0 \n#${s} \n#endif`, true],
['in #preproc', s => `#${s}`, false],
];

const glsl_tests = [];

for (const s of BAD_STRINGS) {
for (const [where, template, validCompile] of TESTS) {
const st = template(s);
const src = `
precision mediump float;
${st}
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}`.trim();

testShaderSource(src, `shaderSource allows Out-of-charset string '${s}' ${where} until compilation.`);

glsl_tests.push(
{
fShaderSource: src,
fShaderSuccess: validCompile,
linkSuccess: validCompile,
passMsg: `Out-of-charset string '${s}' ${where} ${MUST(validCompile)} compile.`
}
);
}
}

GLSLConformanceTester.runTests(glsl_tests);
}

debug("");
var successfullyParsed = true;

</script>
<script src="../../../js/js-test-post.js"></script>

</body>
</html>
41 changes: 27 additions & 14 deletions specs/latest/1.0/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4078,25 +4078,38 @@ <h3><a name="MAX_GLSL_TOKEN_SIZE">Maximum GLSL Token Size</a></h3>
</p>

<h3><a name="CHARACTERS_OUTSIDE_VALID_SET">Characters Outside the GLSL Source Character Set</a></h3>

<p>
The GLSL ES spec <a href="#refsGLES20GLSL">[GLES20GLSL]</a> defines the source character set for
the OpenGL ES shading language to be ISO/IEC 646:1991, commonly called ASCII <a href="#refsASCII">[ASCII]</a>.
If a string containing a character not in this set is passed to any of the shader-related entry
points <code>bindAttribLocation</code>, <code>getAttribLocation</code>, <code>getUniformLocation</code>,
or <code>shaderSource</code>, an <code>INVALID_VALUE</code> error will be generated. The exception is
that any character allowed in an HTML DOMString <a href="#refsDOMSTRING">[DOMSTRING]</a> may be used
in GLSL comments. Such use must not generate an error.
WebGL supports passing any HTML DOMString <a href="#refsDOMSTRING">[DOMSTRING]</a> to <code>shaderSource</code> without error.
However during shader compilation, after GLSL preprocessing and comment stripping, all remaining characters MUST be within the character set of <a href="#refsGLES20GLSL">[GLES20GLSL]</a>.
Otherwise, the shader MUST fail to compile.
</p>

<div class="note">
<p>
In particular, this allows for:
<ul>
<li>Non-ASCII unicode in comments
<pre>// &#20320;&#22909;</pre>
<li>Invalid characters in preprocessor-eliminated blocks
<pre>#ifdef __cplusplus
#line 42 "foo.glsl"
#endif</pre>
(The double-quote character is <em>outside</em> the GLSL character set, but since it is removed by preprocessing, this is allowed in shader sources)
</ul>
</p>
<div class="note rationale">
<p>
Some GLSL implementations disallow characters outside the ASCII range, even in comments. The
WebGL implementation needs to prevent errors in such cases. The recommended technique is to
preprocess the GLSL string, removing all comments, but maintaining the line numbering for
debugging purposes by inserting newline characters as needed.
The GLSL ES spec <a href="#refsGLES20GLSL">[GLES20GLSL]</a> defines the source character set for the OpenGL ES shading language as a subset of ISO/IEC 646:1991, commonly called ASCII <a href="#refsASCII">[ASCII]</a>.
Some GLSL implementations disallow any characters outside the ASCII range, even in comments.
While browsers MUST correctly handle preprocessing the full DOMString character set, WebGL implementations generally must ensure that the shader source sent to a GLSL driver only contains ASCII for safety.
Implementations SHOULD preserve line numbers for debugging purposes, potentially by inserting blank lines as needed.
</p>
</div>
<p>
If a string containing a character <em>not</em> in this set is passed to any of the other shader-related entry points
<code>bindAttribLocation</code>,
<code>getAttribLocation</code>,
or <code>getUniformLocation</code>,
an <code>INVALID_VALUE</code> error will be generated.
</p>

<h3><a name="MAX_STRUCT_NESTING">Maximum Nesting of Structures in GLSL Shaders</a></h3>

Expand Down

0 comments on commit 7a38f9b

Please sign in to comment.