зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1450839 - Update with cherry-pick to fix timeouts in rgb10_a2 tests.
MozReview-Commit-ID: KbJmXtRxN25
This commit is contained in:
Родитель
58ba37ffae
Коммит
bef011bf99
|
@ -29,6 +29,7 @@
|
|||
<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/tests/gl-bindattriblocation-aliasing.js"></script>
|
||||
<title>bindAttribLocation with aliasing</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -50,39 +51,9 @@ var wtu = WebGLTestUtils;
|
|||
var canvas = document.getElementById("canvas");
|
||||
var gl = wtu.create3DContext(canvas, {antialias: false});
|
||||
var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
|
||||
var typeInfo = [
|
||||
{ type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
|
||||
{ type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
|
||||
{ type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
|
||||
{ type: 'vec4', asVec4: '$(var)' },
|
||||
];
|
||||
var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
||||
// Test all type combinations of a_1 and a_2.
|
||||
typeInfo.forEach(function(typeInfo1) {
|
||||
typeInfo.forEach(function(typeInfo2) {
|
||||
debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
|
||||
var replaceParams = {
|
||||
type_1: typeInfo1.type,
|
||||
type_2: typeInfo2.type,
|
||||
gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
|
||||
gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
|
||||
};
|
||||
var strVertexShader = wtu.replaceParams(wtu.getScript('vertexShader'), replaceParams);
|
||||
var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
|
||||
assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
|
||||
// Bind both a_1 and a_2 to the same position and verify the link fails.
|
||||
// Do so for all valid positions available.
|
||||
for (var l = 0; l < maxAttributes; l++) {
|
||||
var glProgram = gl.createProgram();
|
||||
gl.bindAttribLocation(glProgram, l, 'a_1');
|
||||
gl.bindAttribLocation(glProgram, l, 'a_2');
|
||||
gl.attachShader(glProgram, glVertexShader);
|
||||
gl.attachShader(glProgram, glFragmentShader);
|
||||
gl.linkProgram(glProgram);
|
||||
assertMsg(!gl.getProgramParameter(glProgram, gl.LINK_STATUS), "Link should fail when both types are aliased to location " + l);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
runBindAttribLocationAliasingTest(wtu, gl, glFragmentShader, wtu.getScript('vertexShader'));
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
buffer-bind-test.html
|
||||
buffer-data-and-buffer-sub-data.html
|
||||
--min-version 1.0.3 buffer-data-array-buffer-delete.html
|
||||
--min-version 1.0.4 buffer-data-dynamic-delay.html
|
||||
--min-version 1.0.4 buffer-uninitialized.html
|
||||
--min-version 1.0.2 element-array-buffer-delete-recreate.html
|
||||
index-validation-copies-indices.html
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
<!--
|
||||
/*
|
||||
** Copyright (c) 2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>bufferData with DYNAMIC_DRAW and delay between updating data</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>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" width="50" height="50"></canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
|
||||
<script id="vshader" type="x-shader/x-vertex">
|
||||
attribute vec2 a_position;
|
||||
attribute vec2 a_color;
|
||||
varying vec2 v_color;
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||
v_color = a_color;
|
||||
}
|
||||
</script>
|
||||
<script id="fshader" type="x-shader/x-fragment">
|
||||
precision mediump float;
|
||||
varying vec2 v_color;
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(v_color, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
description("Verifies that bufferData with DYNAMIC_DRAW updates the vertex attribute when there is a significant delay between updating the buffer.");
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext("canvas");
|
||||
var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_position", "a_color"]);
|
||||
|
||||
// Initialize position vertex attribute to draw a square covering the entire canvas.
|
||||
var positionBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
-1.0, 1.0,
|
||||
1.0, 1.0,
|
||||
-1.0, -1.0,
|
||||
1.0, -1.0
|
||||
]), gl.DYNAMIC_DRAW);
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
// Initialize color vertex attribute to red.
|
||||
var colorBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
1.0, 0.0,
|
||||
1.0, 0.0,
|
||||
1.0, 0.0,
|
||||
1.0, 0.0,
|
||||
]), gl.DYNAMIC_DRAW);
|
||||
gl.enableVertexAttribArray(1);
|
||||
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No error after setup");
|
||||
|
||||
// Fill the canvas with red
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No error after first drawArrays");
|
||||
|
||||
wtu.checkCanvasRect(gl, 0, 0, 50, 50, [255, 0, 0, 255], "Canvas should be red after the first drawArrays");
|
||||
|
||||
// With the buffer set to DYNAMIC_DRAW, Angle internally changes the storage type of the vertex attribute from DYNAMIC to DIRECT
|
||||
// if the buffer has not been updated after ~4-5 draw calls. When the buffer is eventually updated, the vertex attribute
|
||||
// is updated back to DYNAMIC, but there was a bug in Angle where the data is not marked as dirty. The result is that the
|
||||
// vertex data is not updated with the new buffer data. This test verifies that the vertex data is updated.
|
||||
var iteration = 0;
|
||||
function draw() {
|
||||
// Draw 10 times to ensure that the vertex attribute storage type is changed.
|
||||
if (iteration < 10) {
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 2);
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
else {
|
||||
// Update the buffer bound to the color vertex attribute to green and draw.
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
]), gl.DYNAMIC_DRAW);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No error after last drawArrays");
|
||||
|
||||
wtu.checkCanvasRect(gl, 0, 0, 50, 50, [0, 255, 0, 255], "Canvas should be green after 10 frames");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
iteration++;
|
||||
}
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -156,6 +156,8 @@ function testLosingAndRestoringContext()
|
|||
testLostContext(e);
|
||||
// restore the context after this event has exited.
|
||||
setTimeout(function() {
|
||||
shouldGenerateGLError(gl, gl.NO_ERROR, "WEBGL_lose_context.restoreContext()");
|
||||
// Calling restoreContext() twice should not cause error or crash
|
||||
shouldGenerateGLError(gl, gl.NO_ERROR, "WEBGL_lose_context.restoreContext()");
|
||||
// The context should still be lost. It will not get restored until the
|
||||
// webglrestorecontext event is fired.
|
||||
|
|
|
@ -111,7 +111,7 @@ function testStencilSettings(haveDepthBuffer, haveStencilBuffer, enableStencilTe
|
|||
debug("With depthbuffer=" + haveDepthBuffer +
|
||||
", stencilbuffer=" + haveStencilBuffer +
|
||||
", stencilTest=" + enableStencilTest +
|
||||
", expecting error=" + wtu.glEnumToString(errIfMismatch) +
|
||||
", expecting error=" + wtu.glEnumToString(gl, errIfMismatch) +
|
||||
" for mismatching mask or func settings.");
|
||||
|
||||
let rbo = null;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
--min-version 2.0.1 gl-bindAttribLocation-aliasing-inactive.html
|
||||
gl-vertex-attrib.html
|
||||
gl-vertex-attrib-i-render.html
|
||||
--min-version 2.0.1 gl-vertex-attrib-normalized-int.html
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<!--
|
||||
/*
|
||||
** Copyright (c) 2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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/tests/gl-bindattriblocation-aliasing.js"></script>
|
||||
<title>bindAttribLocation with aliasing - inactive attributes</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
|
||||
<script id="vertexShaderStaticallyUsedButInactive" type="text/something-not-javascript">#version 300 es
|
||||
precision mediump float;
|
||||
in $(type_1) a_1;
|
||||
in $(type_2) a_2;
|
||||
void main() {
|
||||
gl_Position = true ? $(gl_Position_1) : $(gl_Position_2);
|
||||
}
|
||||
</script>
|
||||
<script id="vertexShaderUnused" type="text/something-not-javascript">#version 300 es
|
||||
precision mediump float;
|
||||
in $(type_1) a_1;
|
||||
in $(type_2) a_2;
|
||||
void main() {
|
||||
gl_Position = vec4(0.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
description("This test verifies combinations of valid inactive attributes cannot be bound to the same location with bindAttribLocation. GLSL ES 3.00.6 section 12.46.");
|
||||
var wtu = WebGLTestUtils;
|
||||
var canvas = document.getElementById("canvas");
|
||||
var gl = wtu.create3DContext(canvas, {antialias: false}, 2);
|
||||
var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShaderESSL300, gl.FRAGMENT_SHADER);
|
||||
|
||||
debug("Testing with shader that has statically used but inactive attributes.");
|
||||
runBindAttribLocationAliasingTest(wtu, gl, glFragmentShader, wtu.getScript('vertexShaderStaticallyUsedButInactive'));
|
||||
|
||||
debug("");
|
||||
debug("Testing with shader that has entirely unused attributes.");
|
||||
runBindAttribLocationAliasingTest(wtu, gl, glFragmentShader, wtu.getScript('vertexShaderUnused'));
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -34,6 +34,7 @@ shader-with-invalid-characters.html
|
|||
shader-with-mis-matching-uniform-block.html
|
||||
short-circuiting-in-loop-condition.html
|
||||
--min-version 2.0.1 switch-case.html
|
||||
--min-version 2.0.1 texture-offset-non-constant-offset.html
|
||||
texture-offset-out-of-range.html
|
||||
--min-version 2.0.1 texture-offset-uniform-texture-coordinate.html
|
||||
--min-version 2.0.1 tricky-loop-conditions.html
|
||||
|
|
|
@ -202,6 +202,29 @@ void main()
|
|||
my_FragColor = vec4(0, 1, 0, 1);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderCaseInsideBlock" type="x-shader/x-fragment">#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
|
||||
uniform int u_zero;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Case statements must not be nested in blocks.
|
||||
// GLSL ES 3.00 spec is a bit vague on this but GLSL ES 3.10 section 6.2 is clearer.
|
||||
switch(u_zero)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
case 0:
|
||||
my_FragColor = vec4(1, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
my_FragColor = vec4(0, 1, 0, 1);
|
||||
}
|
||||
</script>
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
description();
|
||||
|
@ -262,6 +285,11 @@ GLSLConformanceTester.runTests([
|
|||
fShaderSuccess: true,
|
||||
linkSuccess: true,
|
||||
passMsg: 'Empty statement should count as a statement for the purposes of switch statement validation.'
|
||||
},
|
||||
{
|
||||
fShaderId: 'fshaderCaseInsideBlock',
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'Case statements must not be nested inside blocks.'
|
||||
}
|
||||
], 2);
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GLSL texture offset with non-constant offset test</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>
|
||||
<script id="fshaderTextureOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec2 u_texCoord;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureOffset(u_sampler, u_texCoord, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTextureProjOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec4 u_texCoord;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureProjOffset(u_sampler, u_texCoord, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTextureLodOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec2 u_texCoord;
|
||||
uniform float u_lod;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureLodOffset(u_sampler, u_texCoord, u_lod, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTextureProjLodOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec4 u_texCoord;
|
||||
uniform float u_lod;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureProjLodOffset(u_sampler, u_texCoord, u_lod, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTextureGradOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec2 u_texCoord;
|
||||
uniform vec2 u_dPdx;
|
||||
uniform vec2 u_dPdy;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureGradOffset(u_sampler, u_texCoord, u_dPdx, u_dPdy, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTextureProjGradOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec4 u_texCoord;
|
||||
uniform vec2 u_dPdx;
|
||||
uniform vec2 u_dPdy;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = textureProjGradOffset(u_sampler, u_texCoord, u_dPdx, u_dPdy, offset);
|
||||
}
|
||||
</script>
|
||||
<script id="fshaderTexelFetchOffset" type="x-shader/x-fragment">#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
out vec4 my_FragColor;
|
||||
uniform sampler2D u_sampler;
|
||||
uniform vec2 u_texCoord;
|
||||
uniform vec2 u_lod;
|
||||
|
||||
void main() {
|
||||
ivec2 offset = ivec2(0);
|
||||
my_FragColor = texelFetchOffset(u_sampler, ivec2(u_texCoord), int(u_lod), offset);
|
||||
}
|
||||
</script>
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
description("A non-constant offset is not valid in texture offset functions.");
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
|
||||
var shaderTextureOffsetSrc = wtu.getScript('fshaderTextureOffset');
|
||||
var shaderTextureLodOffsetSrc = wtu.getScript('fshaderTextureLodOffset');
|
||||
var shaderTextureGradOffsetSrc = wtu.getScript('fshaderTextureGradOffset');
|
||||
var shaderTextureProjOffsetSrc = wtu.getScript('fshaderTextureProjOffset');
|
||||
var shaderTextureProjLodOffsetSrc = wtu.getScript('fshaderTextureProjLodOffset');
|
||||
var shaderTextureProjGradOffsetSrc = wtu.getScript('fshaderTextureProjGradOffset');
|
||||
var shaderTexelFetchOffsetSrc = wtu.getScript('fshaderTexelFetchOffset');
|
||||
|
||||
var gl = wtu.create3DContext(undefined, undefined, 2);
|
||||
|
||||
if (!gl) {
|
||||
testFailed("Unable to initialize WebGL 2.0 context.");
|
||||
} else {
|
||||
GLSLConformanceTester.runTests([
|
||||
{
|
||||
fShaderSource: shaderTextureOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTextureLodOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureLodOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTextureGradOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureGradOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTextureProjOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureProjOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTextureProjLodOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureProjLodOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTextureProjGradOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'textureProjGradOffset with non-constant offset is invalid'
|
||||
},
|
||||
{
|
||||
fShaderSource: shaderTexelFetchOffsetSrc,
|
||||
fShaderSuccess: false,
|
||||
passMsg: 'texelFetchOffset with non-constant offset is invalid'
|
||||
}
|
||||
], 2);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,181 @@
|
|||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test clearBuffer with drawing</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>
|
||||
</head>
|
||||
<body onload="runTest()">
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<canvas id="canvas" width="64" height="64"> </canvas>
|
||||
<script>
|
||||
"use strict";
|
||||
description("This tests the operation of clearBuffer followed by a draw call.");
|
||||
|
||||
debug("Verifies that these combined with preserveDrawingBuffer's implicit clears work properly together.");
|
||||
debug("Regression test for <a href='http://crbug.com/828262'>Chromium bug 828262</a>.");
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
var canvas = document.getElementById("canvas");
|
||||
var gl;
|
||||
var testIndex = 0;
|
||||
var iterations = 0;
|
||||
var maxIterations = 10;
|
||||
var prog;
|
||||
var tests;
|
||||
var blackUint8 = [0, 0, 0, 255];
|
||||
var redFloat = [1.0, 0.0, 0.0, 0.0];
|
||||
var redUint8 = [255, 0, 0, 255];
|
||||
var greenFloat = [0.0, 1.0, 0.0, 0.0];
|
||||
var greenUint8 = [0, 255, 0, 255];
|
||||
|
||||
function verifyOnePixel(kind, x, y, readFormat, readType, arrayType, expectedColor) {
|
||||
var buffer = new arrayType(4);
|
||||
gl.readPixels(Math.floor(x), Math.floor(y), 1, 1, readFormat, readType, buffer);
|
||||
if (buffer[0] == expectedColor[0] &&
|
||||
buffer[1] == expectedColor[1] &&
|
||||
buffer[2] == expectedColor[2] &&
|
||||
buffer[3] == expectedColor[3]) {
|
||||
testPassed(kind + " succeeded");
|
||||
} else {
|
||||
testFailed(kind + " failed. Expected: " + expectedColor + ", got: " + buffer);
|
||||
}
|
||||
}
|
||||
|
||||
function testClearBufferAndDraw(test) {
|
||||
test['clear']();
|
||||
wtu.setFloatDrawColor(gl, greenFloat);
|
||||
wtu.drawUnitQuad(gl);
|
||||
// Back buffer has no alpha channel.
|
||||
let readFormat = gl.RGBA;
|
||||
let readType = gl.UNSIGNED_BYTE;
|
||||
verifyOnePixel("Clearing", 0, 0, readFormat, readType, Uint8Array, test['bgColor']);
|
||||
verifyOnePixel("Drawing", canvas.width / 2, canvas.height / 2,
|
||||
readFormat, readType, Uint8Array, test['drawColor']);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (testIndex >= tests.length) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let test = tests[testIndex];
|
||||
if (iterations == 0) {
|
||||
debug('');
|
||||
debug('Testing: ' + test['desc'])
|
||||
}
|
||||
testClearBufferAndDraw(test);
|
||||
|
||||
if (++iterations == maxIterations) {
|
||||
iterations = 0;
|
||||
++testIndex;
|
||||
}
|
||||
|
||||
wtu.waitForComposite(runNextTest);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
gl = wtu.create3DContext(canvas, { alpha:false }, 2);
|
||||
|
||||
if (!gl) {
|
||||
testFailed("context does not exist");
|
||||
return;
|
||||
} else {
|
||||
testPassed("context exists");
|
||||
}
|
||||
|
||||
prog = wtu.setupColorQuad(gl, 0, { scale: 0.5 });
|
||||
|
||||
tests = [
|
||||
{
|
||||
desc: 'Implicit clear',
|
||||
clear: function() {},
|
||||
bgColor: blackUint8,
|
||||
// The implicit clear clears depth to 1.0, and since the quad is
|
||||
// drawn at a depth of 0.0, it's always discarded.
|
||||
drawColor: blackUint8,
|
||||
},
|
||||
{
|
||||
desc: 'clearBufferfi only',
|
||||
clear: function() {
|
||||
gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 0.0, 0);
|
||||
},
|
||||
bgColor: blackUint8,
|
||||
drawColor: greenUint8,
|
||||
},
|
||||
{
|
||||
desc: 'clearBufferfv and clear',
|
||||
clear: function() {
|
||||
gl.clearBufferfv(gl.COLOR, 0, redFloat),
|
||||
gl.clearDepth(0.0);
|
||||
gl.clear(gl.DEPTH_BUFFER_BIT);
|
||||
},
|
||||
bgColor: redUint8,
|
||||
drawColor: greenUint8,
|
||||
},
|
||||
{
|
||||
desc: 'clearBuffer{fv} and {fi}',
|
||||
clear: function() {
|
||||
gl.clearBufferfv(gl.COLOR, 0, redFloat),
|
||||
gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 0.0, 0);
|
||||
},
|
||||
bgColor: redUint8,
|
||||
drawColor: greenUint8,
|
||||
},
|
||||
];
|
||||
|
||||
// Clear canvas to something other than black to start.
|
||||
gl.clearColor(0.0, 0.0, 1.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
// Unreal Engine's depth test is reversed from the
|
||||
// default. Including the clear of the depth buffer in this test
|
||||
// case highlights the rendering error more clearly, since neither
|
||||
// the background nor any rendered object show up.
|
||||
gl.depthFunc(gl.GEQUAL);
|
||||
|
||||
// Must run in a requestAnimationFrame loop to provoke implicit
|
||||
// clears of the canvas.
|
||||
wtu.waitForComposite(runNextTest);
|
||||
}
|
||||
|
||||
debug("");
|
||||
var successfullyParsed = true;
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -48,6 +48,7 @@ debug("Canvas.getContext");
|
|||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext("canvas", null, 2);
|
||||
var sync = null;
|
||||
var pixel = new Uint8Array(4);
|
||||
|
||||
if (!gl) {
|
||||
testFailed("context does not exist");
|
||||
|
@ -82,7 +83,12 @@ if (!gl) {
|
|||
requestAnimationFrame(runGetSyncParameterTest);
|
||||
}
|
||||
|
||||
var signaling_retry_ms = 1000;
|
||||
var numRetries = 20000;
|
||||
var iteration = 0;
|
||||
|
||||
function syncWithGLServer() {
|
||||
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
|
||||
}
|
||||
|
||||
function runGetSyncParameterTest() {
|
||||
debug("");
|
||||
|
@ -91,10 +97,9 @@ function runGetSyncParameterTest() {
|
|||
// Verify as best as possible that the implementation doesn't allow a sync
|
||||
// object to become signaled until returning control to the event loop, by
|
||||
// spin-looping for some time.
|
||||
var startTime = Date.now();
|
||||
while (Date.now() - startTime < signaling_retry_ms) {
|
||||
gl.flush();
|
||||
gl.finish();
|
||||
var iter = numRetries;
|
||||
while (--iter > 0) {
|
||||
syncWithGLServer();
|
||||
if (gl.getSyncParameter(sync, gl.SYNC_STATUS) == gl.SYNC_SIGNALED) {
|
||||
testFailed("Sync object was signaled too early");
|
||||
finishTest();
|
||||
|
@ -102,18 +107,14 @@ function runGetSyncParameterTest() {
|
|||
}
|
||||
}
|
||||
testPassed("Sync object wasn't signaled too early");
|
||||
startTimeOfFinish = Date.now();
|
||||
iteration = numRetries;
|
||||
requestAnimationFrame(finishSyncParameterTest);
|
||||
}
|
||||
|
||||
var startTimeOfFinish = 0;
|
||||
|
||||
function finishSyncParameterTest() {
|
||||
if (startTimeOfFinish == 0) {
|
||||
startTimeOfFinish = Date.now();
|
||||
}
|
||||
if (Date.now() - startTimeOfFinish > signaling_retry_ms) {
|
||||
testFailed("Sync object wasn't signaled in a reasonable timeframe (" + (Date.now() - startTimeOfFinish) + " ms)");
|
||||
if (--iteration == 0) {
|
||||
testFailed("Sync object wasn't signaled in a reasonable timeframe (" + numRetries + " iterations)");
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
@ -124,6 +125,7 @@ function finishSyncParameterTest() {
|
|||
return;
|
||||
}
|
||||
// Try again.
|
||||
syncWithGLServer();
|
||||
requestAnimationFrame(finishSyncParameterTest);
|
||||
}
|
||||
|
||||
|
@ -135,10 +137,9 @@ function runClientWaitSyncTest() {
|
|||
// Verify as best as possible that the implementation doesn't allow
|
||||
// clientWaitSync to return CONDITION_SATISFIED or ALREADY_SIGNALED until
|
||||
// returning control to the event loop, by spin-looping for some time.
|
||||
var startTime = Date.now();
|
||||
while (Date.now() - startTime < signaling_retry_ms) {
|
||||
gl.flush();
|
||||
gl.finish();
|
||||
var iter = numRetries;
|
||||
while (--iter > 0) {
|
||||
syncWithGLServer();
|
||||
var res = gl.clientWaitSync(sync, 0, 0);
|
||||
if (res == gl.CONDITION_SATISFIED || res == gl.ALREADY_SIGNALED) {
|
||||
testFailed("clientWaitSync completed successfully too early");
|
||||
|
@ -147,16 +148,13 @@ function runClientWaitSyncTest() {
|
|||
}
|
||||
}
|
||||
testPassed("clientWaitSync didn't complete successfully too early");
|
||||
startTimeOfFinish = 0;
|
||||
iteration = numRetries;
|
||||
requestAnimationFrame(finishClientWaitSyncTest);
|
||||
}
|
||||
|
||||
function finishClientWaitSyncTest() {
|
||||
if (startTimeOfFinish == 0) {
|
||||
startTimeOfFinish = Date.now();
|
||||
}
|
||||
if (Date.now() - startTimeOfFinish > signaling_retry_ms) {
|
||||
testFailed("clientWaitSync didn't complete in a reasonable timeframe");
|
||||
if (--iteration == 0) {
|
||||
testFailed("clientWaitSync didn't complete in a reasonable timeframe (" + numRetries + " iterations)");
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
@ -168,6 +166,7 @@ function finishClientWaitSyncTest() {
|
|||
return;
|
||||
}
|
||||
// Try again.
|
||||
syncWithGLServer();
|
||||
requestAnimationFrame(finishClientWaitSyncTest);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
** Copyright (c) 2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var runBindAttribLocationAliasingTest = function(wtu, gl, glFragmentShader, vertexShaderTemplate) {
|
||||
var typeInfo = [
|
||||
{ type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
|
||||
{ type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
|
||||
{ type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
|
||||
{ type: 'vec4', asVec4: '$(var)' },
|
||||
];
|
||||
var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
||||
// Test all type combinations of a_1 and a_2.
|
||||
typeInfo.forEach(function(typeInfo1) {
|
||||
typeInfo.forEach(function(typeInfo2) {
|
||||
debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
|
||||
var replaceParams = {
|
||||
type_1: typeInfo1.type,
|
||||
type_2: typeInfo2.type,
|
||||
gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
|
||||
gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
|
||||
};
|
||||
var strVertexShader = wtu.replaceParams(vertexShaderTemplate, replaceParams);
|
||||
var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
|
||||
assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
|
||||
// Bind both a_1 and a_2 to the same position and verify the link fails.
|
||||
// Do so for all valid positions available.
|
||||
for (var l = 0; l < maxAttributes; l++) {
|
||||
var glProgram = gl.createProgram();
|
||||
gl.bindAttribLocation(glProgram, l, 'a_1');
|
||||
gl.bindAttribLocation(glProgram, l, 'a_2');
|
||||
gl.attachShader(glProgram, glVertexShader);
|
||||
gl.attachShader(glProgram, glFragmentShader);
|
||||
gl.linkProgram(glProgram);
|
||||
var linkStatus = gl.getProgramParameter(glProgram, gl.LINK_STATUS);
|
||||
assertMsg(!linkStatus, "Link should fail when both attributes are aliased to location " + l);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
|
@ -57,6 +57,10 @@ var loggingOff = function() {
|
|||
* @return {string} The enum as a string.
|
||||
*/
|
||||
var glEnumToString = function(gl, value) {
|
||||
// Avoid returning "NO_ERROR" if the arguments are totally wrong.
|
||||
if (gl.NO_ERROR === undefined || value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
// Optimization for the most common enum:
|
||||
if (value === gl.NO_ERROR) {
|
||||
return "NO_ERROR";
|
||||
|
@ -190,6 +194,19 @@ var simpleColorFragmentShader = [
|
|||
' gl_FragData[0] = u_color;',
|
||||
'}'].join('\n');
|
||||
|
||||
/**
|
||||
* A fragment shader for a uniform color.
|
||||
* @type {string}
|
||||
*/
|
||||
var simpleColorFragmentShaderESSL300 = [
|
||||
'#version 300 es',
|
||||
'precision mediump float;',
|
||||
'out vec4 out_color;',
|
||||
'uniform vec4 u_color;',
|
||||
'void main() {',
|
||||
' out_color = u_color;',
|
||||
'}'].join('\n');
|
||||
|
||||
/**
|
||||
* A vertex shader for vertex colors.
|
||||
* @type {string}
|
||||
|
@ -441,16 +458,18 @@ var setupSimpleColorProgram = function(gl, opt_positionLocation) {
|
|||
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||
* @param {number} opt_positionLocation The attrib location for position.
|
||||
* @param {number} opt_texcoordLocation The attrib location for texture coords.
|
||||
* @param {!Object} various options. See setupQuad for details.
|
||||
* @return {!Array.<WebGLBuffer>} The buffer objects that were
|
||||
* created.
|
||||
*/
|
||||
var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) {
|
||||
return setupUnitQuadWithTexCoords(gl, [ 0.0, 0.0 ], [ 1.0, 1.0 ],
|
||||
opt_positionLocation, opt_texcoordLocation);
|
||||
var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation, options) {
|
||||
return setupQuadWithTexCoords(gl, [ 0.0, 0.0 ], [ 1.0, 1.0 ],
|
||||
opt_positionLocation, opt_texcoordLocation,
|
||||
options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates buffers for a textured unit quad with specified lower left
|
||||
* Creates buffers for a textured quad with specified lower left
|
||||
* and upper right texture coordinates, and attaches them to vertex
|
||||
* attribs.
|
||||
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||
|
@ -458,18 +477,25 @@ var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) {
|
|||
* @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
|
||||
* @param {number} opt_positionLocation The attrib location for position.
|
||||
* @param {number} opt_texcoordLocation The attrib location for texture coords.
|
||||
* @param {!Object} various options. See setupQuad for details.
|
||||
* @return {!Array.<WebGLBuffer>} The buffer objects that were
|
||||
* created.
|
||||
*/
|
||||
var setupUnitQuadWithTexCoords = function(
|
||||
var setupQuadWithTexCoords = function(
|
||||
gl, lowerLeftTexCoords, upperRightTexCoords,
|
||||
opt_positionLocation, opt_texcoordLocation) {
|
||||
return setupQuad(gl, {
|
||||
opt_positionLocation, opt_texcoordLocation, options) {
|
||||
var defaultOptions = {
|
||||
positionLocation: opt_positionLocation || 0,
|
||||
texcoordLocation: opt_texcoordLocation || 1,
|
||||
lowerLeftTexCoords: lowerLeftTexCoords,
|
||||
upperRightTexCoords: upperRightTexCoords
|
||||
});
|
||||
};
|
||||
if (options) {
|
||||
for (var prop in options) {
|
||||
defaultOptions[prop] = options[prop]
|
||||
}
|
||||
}
|
||||
return setupQuad(gl, defaultOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -477,7 +503,7 @@ var setupUnitQuadWithTexCoords = function(
|
|||
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||
* @param {!Object} options
|
||||
*
|
||||
* scale: scale to multiple unit quad values by. default 1.0.
|
||||
* scale: scale to multiply unit quad values by. default 1.0.
|
||||
* positionLocation: attribute location for position.
|
||||
* texcoordLocation: attribute location for texcoords.
|
||||
* If this does not exist no texture coords are created.
|
||||
|
@ -535,13 +561,14 @@ var setupQuad = function(gl, options) {
|
|||
* position. Default = 0.
|
||||
* @param {number} opt_texcoordLocation The attrib location for
|
||||
* texture coords. Default = 1.
|
||||
* @param {!Object} various options. See setupQuad for details.
|
||||
* @return {!WebGLProgram}
|
||||
*/
|
||||
var setupTexturedQuad = function(
|
||||
gl, opt_positionLocation, opt_texcoordLocation) {
|
||||
gl, opt_positionLocation, opt_texcoordLocation, options) {
|
||||
var program = setupSimpleTextureProgram(
|
||||
gl, opt_positionLocation, opt_texcoordLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation, options);
|
||||
return program;
|
||||
};
|
||||
|
||||
|
@ -549,12 +576,13 @@ var setupTexturedQuad = function(
|
|||
* Creates a program and buffers for rendering a color quad.
|
||||
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
|
||||
* @param {number} opt_positionLocation The attrib location for position.
|
||||
* @param {!Object} various options. See setupQuad for details.
|
||||
* @return {!WebGLProgram}
|
||||
*/
|
||||
var setupColorQuad = function(gl, opt_positionLocation) {
|
||||
var setupColorQuad = function(gl, opt_positionLocation, options) {
|
||||
opt_positionLocation = opt_positionLocation || 0;
|
||||
var program = setupSimpleColorProgram(gl, opt_positionLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation, 0, options);
|
||||
return program;
|
||||
};
|
||||
|
||||
|
@ -573,8 +601,8 @@ var setupTexturedQuadWithTexCoords = function(
|
|||
opt_positionLocation, opt_texcoordLocation) {
|
||||
var program = setupSimpleTextureProgram(
|
||||
gl, opt_positionLocation, opt_texcoordLocation);
|
||||
setupUnitQuadWithTexCoords(gl, lowerLeftTexCoords, upperRightTexCoords,
|
||||
opt_positionLocation, opt_texcoordLocation);
|
||||
setupQuadWithTexCoords(gl, lowerLeftTexCoords, upperRightTexCoords,
|
||||
opt_positionLocation, opt_texcoordLocation);
|
||||
return program;
|
||||
};
|
||||
|
||||
|
@ -592,7 +620,7 @@ var setupTexturedQuadWithCubeMap = function(
|
|||
gl, opt_positionLocation, opt_texcoordLocation) {
|
||||
var program = setupSimpleCubeMapTextureProgram(
|
||||
gl, opt_positionLocation, opt_texcoordLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation);
|
||||
setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation, undefined);
|
||||
return program;
|
||||
};
|
||||
|
||||
|
@ -953,13 +981,16 @@ var drawUnitQuad = function(gl) {
|
|||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
};
|
||||
|
||||
var noopProgram = null;
|
||||
var dummyProgram = null;
|
||||
var dummySetProgramAndDrawNothing = function(gl) {
|
||||
if (!noopProgram) {
|
||||
noopProgram = setupProgram(gl, ["void main() {}", "void main() {}"], [], []);
|
||||
if (!dummyProgram) {
|
||||
dummyProgram = setupProgram(gl, [
|
||||
"void main() { gl_Position = vec4(0.0); }",
|
||||
"void main() { gl_FragColor = vec4(0.0); }"
|
||||
], [], []);
|
||||
}
|
||||
gl.useProgram(noopProgram);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 0);
|
||||
gl.useProgram(dummyProgram);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1891,11 +1922,6 @@ var loadShader = function(
|
|||
|
||||
// Load the shader source
|
||||
gl.shaderSource(shader, shaderSource);
|
||||
var err = gl.getError();
|
||||
if (err != gl.NO_ERROR) {
|
||||
errFn("*** Error loading shader '" + shader + "':" + glEnumToString(gl, err));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compile the shader
|
||||
gl.compileShader(shader);
|
||||
|
@ -3176,6 +3202,7 @@ var API = {
|
|||
setupProgram: setupProgram,
|
||||
setupTransformFeedbackProgram: setupTransformFeedbackProgram,
|
||||
setupQuad: setupQuad,
|
||||
setupQuadWithTexCoords: setupQuadWithTexCoords,
|
||||
setupIndexedQuad: setupIndexedQuad,
|
||||
setupIndexedQuadWithOptions: setupIndexedQuadWithOptions,
|
||||
setupSimpleColorProgram: setupSimpleColorProgram,
|
||||
|
@ -3187,7 +3214,6 @@ var API = {
|
|||
setupTexturedQuadWithTexCoords: setupTexturedQuadWithTexCoords,
|
||||
setupTexturedQuadWithCubeMap: setupTexturedQuadWithCubeMap,
|
||||
setupUnitQuad: setupUnitQuad,
|
||||
setupUnitQuadWithTexCoords: setupUnitQuadWithTexCoords,
|
||||
setFloatDrawColor: setFloatDrawColor,
|
||||
setUByteDrawColor: setUByteDrawColor,
|
||||
startPlayingAndWaitForVideo: startPlayingAndWaitForVideo,
|
||||
|
@ -3221,6 +3247,7 @@ Object.defineProperties(API, {
|
|||
noTexCoordTextureVertexShader: { value: noTexCoordTextureVertexShader, writable: false },
|
||||
simpleTextureVertexShader: { value: simpleTextureVertexShader, writable: false },
|
||||
simpleColorFragmentShader: { value: simpleColorFragmentShader, writable: false },
|
||||
simpleColorFragmentShaderESSL300: { value: simpleColorFragmentShaderESSL300, writable: false },
|
||||
simpleVertexShader: { value: simpleVertexShader, writable: false },
|
||||
simpleTextureFragmentShader: { value: simpleTextureFragmentShader, writable: false },
|
||||
simpleCubeMapTextureFragmentShader: { value: simpleCubeMapTextureFragmentShader, writable: false },
|
||||
|
|
|
@ -241,7 +241,7 @@ function start() {
|
|||
this.totalSkipped = 0;
|
||||
this.totalFailed = 0;
|
||||
this.testIndex = testIndex;
|
||||
this.startTime = 0;
|
||||
this.startTime = new Date();
|
||||
this.totalTime = 0;
|
||||
var that = this;
|
||||
|
||||
|
@ -305,15 +305,17 @@ function start() {
|
|||
var result = "timeout";
|
||||
var css = "timeout";
|
||||
} else if (success) {
|
||||
if(skipped) {
|
||||
++this.totalSkipped;
|
||||
} else {
|
||||
++this.totalSuccessful;
|
||||
}
|
||||
++this.totalSuccessful;
|
||||
// don't report success.
|
||||
return;
|
||||
} else {
|
||||
++this.totalFailed;
|
||||
if (skipped) {
|
||||
// Skipped tests are counted as both skips and failures (because we
|
||||
// don't want to accidentally accept a conformance submission with
|
||||
// skipped tests).
|
||||
++this.totalSkipped;
|
||||
}
|
||||
var result = "failed";
|
||||
var css = "fail";
|
||||
}
|
||||
|
@ -411,6 +413,18 @@ function start() {
|
|||
}
|
||||
};
|
||||
|
||||
Page.prototype.toJSON = function() {
|
||||
return {
|
||||
'subtests': this.totalTests,
|
||||
'successful': this.totalSuccessful,
|
||||
'skipped': this.totalSkipped,
|
||||
'failed': this.totalFailed,
|
||||
'timedOut': this.totalTimeouts,
|
||||
'totalTime': this.totalTime,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var Folder = function(reporter, folder, depth, opt_name) {
|
||||
this.reporter = reporter;
|
||||
this.depth = depth;
|
||||
|
@ -728,7 +742,7 @@ function start() {
|
|||
this.root = new Folder(this, null, 0, "all");
|
||||
this.resultElem.appendChild(this.root.elem);
|
||||
this.callbacks = { };
|
||||
this.startTime = 0;
|
||||
this.startTime = new Date();
|
||||
|
||||
if (ctx) {
|
||||
this.contextInfo["VENDOR"] = ctx.getParameter(ctx.VENDOR);
|
||||
|
@ -815,35 +829,60 @@ function start() {
|
|||
Reporter.prototype.displayFinalResults = function(msg, success) {
|
||||
if (success) {
|
||||
var totalTests = 0;
|
||||
var totalSuccessful = 0;
|
||||
var totalTimeouts = 0;
|
||||
var totalSkipped = 0;
|
||||
var totalFailed = 0;
|
||||
var testsSucceeded = 0;
|
||||
var testsFailed = 0;
|
||||
var testsSkipped = 0;
|
||||
var testsTimedOut = 0;
|
||||
|
||||
var subtestsHit = 0;
|
||||
var subtestsSucceeded = 0;
|
||||
var subtestsTimedOut = 0;
|
||||
var subtestsSkipped = 0;
|
||||
var subtestsFailed = 0;
|
||||
|
||||
var totalTime = Date.now() - this.startTime;
|
||||
|
||||
for (var url in this.pagesByURL) {
|
||||
var page = this.pagesByURL[url];
|
||||
totalTests += page.totalTests;
|
||||
totalSuccessful += page.totalSuccessful;
|
||||
totalTimeouts += page.totalTimeouts;
|
||||
totalSkipped += page.totalSkipped;
|
||||
totalFailed += page.totalFailed;
|
||||
totalTests += 1;
|
||||
if (page.totalSkipped) {
|
||||
testsSkipped += 1;
|
||||
}
|
||||
if (page.totalFailed) {
|
||||
testsFailed += 1;
|
||||
} else if (page.totalTimeouts) {
|
||||
testsTimedOut += 1;
|
||||
} else if (page.totalSuccessful) {
|
||||
if (page.totalSuccessful != page.totalTests)
|
||||
throw successes_not_equal_total;
|
||||
testsSucceeded += 1;
|
||||
}
|
||||
|
||||
subtestsHit += page.totalTests;
|
||||
subtestsSucceeded += page.totalSuccessful;
|
||||
subtestsTimedOut += page.totalTimeouts;
|
||||
subtestsSkipped += page.totalSkipped;
|
||||
subtestsFailed += page.totalFailed;
|
||||
}
|
||||
var passedMsg = 'Passed ' + totalSuccessful + '/' + totalTests + ' (' + (totalSuccessful * 100.0 / totalTests).toFixed(2) + '%)';
|
||||
var timeout = '';
|
||||
if (totalTimeouts > 0) {
|
||||
timeout = ', ' + totalTimeouts + ' timed out';
|
||||
|
||||
function ratio_str(x, y, name) {
|
||||
return x + '/' + y + ' ' + name + ' (' + (x / y * 100).toFixed(2) + '%)';
|
||||
}
|
||||
var testsSucceededRatio = ratio_str(testsSucceeded, totalTests, 'tests');
|
||||
var passedMsg = 'Passed ' + testsSucceededRatio + ', ' +
|
||||
ratio_str(subtestsSucceeded, subtestsHit, 'subtests');
|
||||
var skippedMsg = '';
|
||||
if (totalSkipped > 0) {
|
||||
skippedMsg = ' Skipped ' + totalSkipped + '/' + totalTests + ' (' + (totalSkipped * 100.0 / totalTests).toFixed(2) + '%)';
|
||||
if (testsSkipped > 0) {
|
||||
skippedMsg = ' Skipped ' + ratio_str(testsSkipped, totalTests, 'tests');
|
||||
}
|
||||
var failedMsg = '';
|
||||
if (totalFailed > 0) {
|
||||
failedMsg = ' Failed ' + totalFailed + '/' + totalTests + ' (' + (totalFailed * 100.0 / totalTests).toFixed(2) + '%)';
|
||||
if (testsFailed > 0) {
|
||||
failedMsg = ' Failed ' + ratio_str(testsFailed, totalTests, 'tests') + ', ' +
|
||||
ratio_str(subtestsFailed, subtestsHit, 'subtests');
|
||||
}
|
||||
var timeoutMsg = '';
|
||||
if (totalTimeouts > 0) {
|
||||
timeoutMsg = ' Timeout ' + totalTimeouts + '/' + totalTests + ' (' + (totalTimeouts * 100.0 / totalTests).toFixed(2) + '%)';
|
||||
if (testsTimedOut > 0) {
|
||||
timeoutMsg = ' Timeout ' + ratio_str(testsTimedOut, totalTests, 'tests');
|
||||
}
|
||||
var msg = passedMsg + skippedMsg + failedMsg + timeoutMsg;
|
||||
this.fullResultsNode.textContent = msg;
|
||||
|
@ -852,6 +891,7 @@ function start() {
|
|||
var tx = "";
|
||||
tx += "WebGL Conformance Test Results\n";
|
||||
tx += "Version " + OPTIONS.version + "\n";
|
||||
tx += "Generated on: " + (new Date()).toString() + "\n";
|
||||
tx += "\n";
|
||||
tx += "-------------------\n\n";
|
||||
tx += "User Agent: " + (navigator.userAgent ? navigator.userAgent : "(navigator.userAgent is null)") + "\n";
|
||||
|
@ -861,47 +901,67 @@ function start() {
|
|||
tx += "Unmasked VENDOR: " + this.contextInfo["UNMASKED_VENDOR"] + "\n";
|
||||
tx += "Unmasked RENDERER: " + this.contextInfo["UNMASKED_RENDERER"] + "\n";
|
||||
tx += "WebGL R/G/B/A/Depth/Stencil bits (default config): " + this.contextInfo["RED_BITS"] + "/" + this.contextInfo["GREEN_BITS"] + "/" + this.contextInfo["BLUE_BITS"] + "/" + this.contextInfo["ALPHA_BITS"] + "/" + this.contextInfo["DEPTH_BITS"] + "/" + this.contextInfo["STENCIL_BITS"] + "\n";
|
||||
tx += "\n";
|
||||
tx += "-------------------\n\n";
|
||||
tx += "Test Summary (" + totalTests + " total tests):\n";
|
||||
tx += "Tests ran in " + (totalTime / 1000.0).toFixed(2) + " seconds\n";
|
||||
tx += "Tests PASSED: " + totalSuccessful + "\n";
|
||||
tx += "Tests FAILED: " + (totalTests - totalSuccessful - totalSkipped) + "\n";
|
||||
tx += "Tests TIMED OUT: " + totalTimeouts + "\n";
|
||||
tx += "Tests SKIPPED: " + totalSkipped + "\n";
|
||||
tx += "\n";
|
||||
tx += "-------------------\n\n";
|
||||
if (totalSuccessful < totalTests) {
|
||||
tx += "Failures:\n\n";
|
||||
for (var url in this.pagesByURL) {
|
||||
var page = this.pagesByURL[url];
|
||||
var pageTotalFail = page.totalTests - page.totalSuccessful - page.totalSkipped;
|
||||
if (!(page.totalTests == 0 && page.totalTimeouts == 0) &&
|
||||
pageTotalFail > 0)
|
||||
{
|
||||
tx += url + ": " + pageTotalFail + " tests failed";
|
||||
if (page.totalTimeouts)
|
||||
tx += " (" + page.totalTimeouts + " timed out)";
|
||||
tx += "\n";
|
||||
}
|
||||
}
|
||||
tx += "\n-------------------\n\n";
|
||||
|
||||
var result;
|
||||
if (totalTests && testsSucceeded == totalTests) {
|
||||
result = 'PASS';
|
||||
} else {
|
||||
tx += "All tests PASSED\n\n";
|
||||
result = 'FAIL';
|
||||
}
|
||||
tx += "\n";
|
||||
tx += "-------------------\n\n";
|
||||
tx += "Complete Test Results (total / pass / fail / timeout / skipped):\n\n";
|
||||
tx += "Test Summary: " + result + " (" + totalTests + " tests):\n";
|
||||
tx += subtestsHit + " subtests ran in " + (totalTime / 1000.0).toFixed(2) + " seconds\n";
|
||||
function record(what, tests, subtests) {
|
||||
tx += what + ": " + tests + " tests, " + subtests + " subtests\n";
|
||||
}
|
||||
record('PASSED', testsSucceeded, subtestsSucceeded);
|
||||
record('NOT PASSED', totalTests - testsSucceeded, subtestsHit - subtestsSucceeded);
|
||||
|
||||
record('FAILED', testsFailed, subtestsFailed);
|
||||
record('TIMED OUT', testsTimedOut, subtestsTimedOut);
|
||||
record('SKIPPED', testsSkipped, subtestsSkipped);
|
||||
|
||||
tx += "\n-------------------\n\n";
|
||||
|
||||
const failureLines = [];
|
||||
const timeoutLines = [];
|
||||
const resultLines = [];
|
||||
|
||||
for (var url in this.pagesByURL) {
|
||||
var page = this.pagesByURL[url];
|
||||
var pageTotalFail = page.totalTests - page.totalSuccessful - page.totalSkipped;
|
||||
if (!(page.totalTests == 0 && page.totalTimeouts == 0)) {
|
||||
tx += url + ": " + page.totalTests + " / " +
|
||||
page.totalSuccessful + " / " + pageTotalFail + " / " + page.totalTimeouts + " / " + page.totalSkipped + "\n";
|
||||
resultLines.push(' "' + url + '":' + JSON.stringify(page.toJSON()));
|
||||
|
||||
if (page.totalFailed) {
|
||||
failureLines.push(' "' + url + '",');
|
||||
}
|
||||
if (page.totalTimeouts) {
|
||||
timeoutLines.push(' "' + url + '",');
|
||||
}
|
||||
}
|
||||
tx += "\n";
|
||||
tx += "-------------------\n\n";
|
||||
tx += "Generated on: " + (new Date()).toString() + "\n";
|
||||
|
||||
const lines = [].concat(
|
||||
[
|
||||
'{',
|
||||
' "failures": [',
|
||||
],
|
||||
failureLines,
|
||||
[
|
||||
' ],',
|
||||
' "timeouts": [',
|
||||
],
|
||||
timeoutLines,
|
||||
[
|
||||
' ],',
|
||||
' "results": {',
|
||||
],
|
||||
resultLines,
|
||||
[
|
||||
' },',
|
||||
'}',
|
||||
]
|
||||
);
|
||||
|
||||
tx += lines.join('\n');
|
||||
|
||||
var r = document.getElementById("testResultsAsText");
|
||||
while (r.firstChild) r.removeChild(r.firstChild);
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
commit bce0801d759def1b8c75b049150049aaadc7a6ff
|
||||
Author: Jeff Gilbert <jdashg@gmail.com>
|
||||
Date: Fri Apr 6 19:52:35 2018 -0700
|
||||
|
||||
wtu.loadShader's gl.shaderSource should be treated as infallible.
|
||||
|
||||
Cherries picked
|
||||
================================================================================
|
||||
Merge base
|
||||
|
||||
commit e899c531173da8ba956df8de6dd74fb7d9b1fa9c
|
||||
Author: Patrick To <patrto@microsoft.com>
|
||||
Date: Fri Mar 30 13:18:38 2018 -0700
|
||||
commit fefa32a950127f6e01a5cdd1536d639a949cd82b
|
||||
Author: Olli Etuaho <olli.etuaho@gmail.com>
|
||||
Date: Fri Apr 6 20:00:43 2018 +0300
|
||||
|
||||
Add unpack flip y test for depth textures (#2609)
|
||||
Add a test for having a case statement inside a block (#2630)
|
||||
|
||||
This was not being validated correctly by ANGLE until recently, though
|
||||
this would not cause issues if the native drivers were working
|
||||
correctly.
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!-- GENERATED FILE, DO NOT EDIT -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>
|
||||
Mochitest wrapper for WebGL Conformance Test Suite tests
|
||||
</title>
|
||||
<link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/>
|
||||
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src='../mochi-single.html?checkout/conformance2/attribs/gl-bindAttribLocation-aliasing-inactive.html?webglVersion=2'></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- GENERATED FILE, DO NOT EDIT -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>
|
||||
Mochitest wrapper for WebGL Conformance Test Suite tests
|
||||
</title>
|
||||
<link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/>
|
||||
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src='../mochi-single.html?checkout/conformance2/glsl3/texture-offset-non-constant-offset.html?webglVersion=2'></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- GENERATED FILE, DO NOT EDIT -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>
|
||||
Mochitest wrapper for WebGL Conformance Test Suite tests
|
||||
</title>
|
||||
<link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/>
|
||||
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src='../mochi-single.html?checkout/conformance/buffers/buffer-data-dynamic-delay.html?webglVersion=2'></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- GENERATED FILE, DO NOT EDIT -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>
|
||||
Mochitest wrapper for WebGL Conformance Test Suite tests
|
||||
</title>
|
||||
<link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/>
|
||||
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src='../mochi-single.html?checkout/conformance/buffers/buffer-data-dynamic-delay.html'></iframe>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче