Source/WebCore: [WebGL] Implement ANGLE_instanced_arrays
[WebKit-https.git] / LayoutTests / fast / canvas / webgl / angle-instanced-arrays.html
1 <!--
2 /*
3 ** Copyright (c) 2013 The Khronos Group Inc.
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining a
6 ** copy of this software and/or associated documentation files (the
7 ** "Materials"), to deal in the Materials without restriction, including
8 ** without limitation the rights to use, copy, modify, merge, publish,
9 ** distribute, sublicense, and/or sell copies of the Materials, and to
10 ** permit persons to whom the Materials are furnished to do so, subject to
11 ** the following conditions:
12 **
13 ** The above copyright notice and this permission notice shall be included
14 ** in all copies or substantial portions of the Materials.
15 **
16 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
23 */
24 -->
25
26 <!DOCTYPE html>
27 <html>
28 <head>
29 <meta charset="utf-8">
30 <title>WebGL ANGLE_instanced_arrays Conformance Tests</title>
31 <script src="resources/desktop-gl-constants.js" type="text/javascript"></script>
32 <script src="../../../resources/js-test-pre.js"></script>
33 <script src="resources/webgl-test.js"> </script>
34 <script src="resources/webgl-test-utils.js"></script>
35 </head>
36 <body>
37 <div id="description"></div>
38 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
39 <div id="console"></div>
40 <!-- Shaders for testing instanced draws -->
41 <script id="outputVertexShader" type="x-shader/x-vertex">
42 attribute vec4 aPosition;
43 attribute vec2 aOffset;
44 attribute vec4 aColor;
45 varying vec4 vColor;
46 void main() {
47     vColor = aColor;
48     gl_Position = aPosition + vec4(aOffset, 0.0, 0.0);
49 }
50 </script>
51
52 <script id="outputFragmentShader" type="x-shader/x-fragment">
53 precision mediump float;
54 varying vec4 vColor;
55 void main() {
56     gl_FragColor = vColor;
57 }
58 </script>
59
60 <script>
61 "use strict";
62 description("This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available.");
63
64 debug("");
65
66 var wtu = WebGLTestUtils;
67 var canvas = document.getElementById("canvas");
68 var gl = wtu.create3DContext(canvas);
69 var ext = null;
70
71 var positionLoc = 0;
72 var offsetLoc = 2;
73 var colorLoc = 3;
74 var program;
75
76 if (!gl) {
77     testFailed("WebGL context does not exist");
78 } else {
79     testPassed("WebGL context exists");
80
81     runDivisorTestDisabled();
82
83     // Query the extension and store globally so shouldBe can access it
84     ext = wtu.getExtensionWithKnownPrefixes(gl, "ANGLE_instanced_arrays");
85     if (!ext) {
86         testPassed("No ANGLE_instanced_arrays support -- this is legal");
87
88         runSupportedTest(false);
89     } else {
90         testPassed("Successfully enabled ANGLE_instanced_arrays extension");
91
92         runSupportedTest(true);
93
94         runDivisorTestEnabled();
95         runUniqueObjectTest();
96
97         setupCanvas();
98         runOutputTests();
99         finishTest();
100     }
101 }
102
103 function runSupportedTest(extensionEnabled) {
104     var supported = gl.getSupportedExtensions();
105     if (supported.indexOf("ANGLE_instanced_arrays") >= 0) {
106         if (extensionEnabled) {
107             testPassed("ANGLE_instanced_arrays listed as supported and getExtension succeeded");
108         } else {
109             testFailed("ANGLE_instanced_arrays listed as supported but getExtension failed");
110         }
111     } else {
112         if (extensionEnabled) {
113             testFailed("ANGLE_instanced_arrays not listed as supported but getExtension succeeded");
114         } else {
115             testPassed("ANGLE_instanced_arrays not listed as supported and getExtension failed -- this is legal");
116         }
117     }
118 }
119
120 function runDivisorTestDisabled() {
121     debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled");
122     
123     var VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
124
125     gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
126     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should not be queryable if extension is disabled");
127 }
128
129 function runDivisorTestEnabled() {
130     debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled");
131
132     shouldBe("ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "0x88FE");
133
134     var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
135
136     for (var i = 0; i < max_vertex_attribs; ++i) {
137         var queried_value = gl.getVertexAttrib(i, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
138         if(queried_value == 0){
139             testPassed("Vertex attribute " + i + " must has a default divisor of 0");
140         }
141         else{
142             testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value);
143         }
144     }
145
146     ext.vertexAttribDivisorANGLE(max_vertex_attribs, 2);
147     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisorANGLE index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value");
148
149     ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 2);
150     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisorANGLE index set less than MAX_VERTEX_ATTRIBS should succeed");
151
152     var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
153     if(queried_value == 2){
154         testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE matches expecation");
155     }
156     else{
157         testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should be: 2, returned value was: " + queried_value);
158     }
159 }
160
161 function setupCanvas() {
162     canvas.width = 50; canvas.height = 50;
163     gl.viewport(0, 0, canvas.width, canvas.height);
164     gl.clearColor(0, 0, 0, 0);
165
166     program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]);
167 }
168
169 function runOutputTests() {
170     var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
171     var instanceCount = 4;
172
173     debug("Testing various draws for valid built-in function behavior");
174
175     var offsets = new Float32Array([
176         -1.0,  1.0,
177          1.0,  1.0,
178         -1.0, -1.0,
179          1.0, -1.0,
180     ]);
181     var offsetBuffer = gl.createBuffer();
182     gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
183     gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
184     gl.enableVertexAttribArray(offsetLoc);
185     gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0);
186     ext.vertexAttribDivisorANGLE(offsetLoc, 1);
187
188     var colors = new Float32Array([
189         1.0, 0.0, 0.0, 1.0, // Red
190         0.0, 1.0, 0.0, 1.0, // Green
191         0.0, 0.0, 1.0, 1.0, // Blue
192         1.0, 1.0, 0.0, 1.0, // Yellow
193     ]);
194     var colorBuffer = gl.createBuffer();
195     gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
196     gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
197     gl.enableVertexAttribArray(colorLoc);
198     gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
199     ext.vertexAttribDivisorANGLE(colorLoc, 1);
200
201     // Draw 1: Draw Non-indexed instances
202     debug("Testing drawArraysInstancedANGLE");
203     gl.clear(gl.COLOR_BUFFER_BIT);
204     wtu.setupUnitQuad(gl, 0);
205
206     // Test drawArraysInstancedANGLE error conditions
207     ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
208     wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
209     wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
210     wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
211     wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
212
213     ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, -1);
214     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a primcount less than 0");
215
216     ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, -1, instanceCount);
217     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a count less than 0");
218
219     ext.vertexAttribDivisorANGLE(positionLoc, 1);
220     ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
221     wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstancedANGLE");
222     ext.vertexAttribDivisorANGLE(positionLoc, 0);
223
224     ext.drawArraysInstancedANGLE(gl.POINTS, 0, 6, instanceCount);
225     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with POINTS should succeed");
226     ext.drawArraysInstancedANGLE(gl.LINES, 0, 6, instanceCount);
227     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINES should succeed");
228     ext.drawArraysInstancedANGLE(gl.LINE_LIST, 0, 6, instanceCount);
229     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINE_LIST should return succeed");
230     ext.drawArraysInstancedANGLE(gl.TRIANGLE_LIST, 0, 6, instanceCount);
231     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with TRIANGLE_LIST should succeed");
232
233     ext.drawArraysInstancedANGLE(desktopGL['QUAD_STRIP'], 0, 6, instanceCount);
234     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
235     ext.drawArraysInstancedANGLE(desktopGL['QUADS'], 0, 6, instanceCount);
236     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUADS should return INVALID_ENUM");
237     ext.drawArraysInstancedANGLE(desktopGL['POLYGON'], 0, 6, instanceCount);
238     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with POLYGON should return INVALID_ENUM");
239
240     // Draw 2: Draw indexed instances
241     debug("Testing drawElementsInstancedANGLE");
242     gl.clear(gl.COLOR_BUFFER_BIT);
243     wtu.setupIndexedQuad(gl, 1, 0);
244     ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
245     wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
246     wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
247     wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
248     wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
249
250     // Test drawElementsInstancedANGLE error conditions
251     ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1);
252     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a primcount less than 0");
253
254     ext.drawElementsInstancedANGLE(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount);
255     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a count less than 0");
256
257     ext.vertexAttribDivisorANGLE(positionLoc, 1);
258     ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
259     wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstancedANGLE");
260     ext.vertexAttribDivisorANGLE(positionLoc, 0);
261
262     ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount);
263     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed");
264
265     ext.drawElementsInstancedANGLE(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
266     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with POINTS should succeed");
267     ext.drawElementsInstancedANGLE(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
268     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINES should succeed");
269     ext.drawElementsInstancedANGLE(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
270     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINE_LIST should return succeed");
271     ext.drawElementsInstancedANGLE(gl.TRIANGLE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
272     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with TRIANGLE_LIST should succeed");
273
274     ext.drawElementsInstancedANGLE(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
275     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
276     ext.drawElementsInstancedANGLE(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
277     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUADS should return INVALID_ENUM");
278     ext.drawElementsInstancedANGLE(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
279     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with POLYGON should return INVALID_ENUM");
280 }
281
282 function runUniqueObjectTest()
283 {
284     debug("Testing that getExtension() returns the same object each time");
285     gl.getExtension("ANGLE_instanced_arrays").myProperty = 2;
286     gc();
287     shouldBe('gl.getExtension("ANGLE_instanced_arrays").myProperty', '2');
288 }
289
290 debug("");
291 var successfullyParsed = true;
292
293 </script>
294 <script src="../../../resources/js-test-post.js"></script>
295
296 </body>
297 </html>