Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fPrimitiveRestartTests.js
blobac0da2fe6646f3065f36af1a7339e725b518c70b
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
21 'use strict';
22 goog.provide('functional.gles3.es3fPrimitiveRestartTests');
23 goog.require('framework.common.tcuImageCompare');
24 goog.require('framework.common.tcuSurface');
25 goog.require('framework.common.tcuTestCase');
26 goog.require('framework.delibs.debase.deMath');
27 goog.require('framework.delibs.debase.deRandom');
28 goog.require('framework.delibs.debase.deString');
29 goog.require('framework.opengl.gluShaderProgram');
30 goog.require('framework.opengl.gluTextureUtil');
32 goog.scope(function() {
34 var es3fPrimitiveRestartTests = functional.gles3.es3fPrimitiveRestartTests;
35 var tcuTestCase = framework.common.tcuTestCase;
36 var gluShaderProgram = framework.opengl.gluShaderProgram;
37 var tcuSurface = framework.common.tcuSurface;
38 var deMath = framework.delibs.debase.deMath;
39 var deRandom = framework.delibs.debase.deRandom;
40 var deString = framework.delibs.debase.deString;
41 var tcuImageCompare = framework.common.tcuImageCompare;
42 var gluTextureUtil = framework.opengl.gluTextureUtil;
44     /** @type {WebGL2RenderingContext} */ var gl;
45     /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_RENDER_WIDTH = 256;
46     /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_RENDER_HEIGHT = 256;
48     /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE = 255;
49     /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT = 65535;
50     /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_INT = 4294967295;
52     /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE = es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE;
53     /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT = es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT;
54     /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT = es3fPrimitiveRestartTests.MAX_UNSIGNED_INT;
56     var DE_ASSERT = function(expression) {
57         if (!expression) throw new Error('Assert failed');
58     };
60     /**
61      * @enum
62      */
63     es3fPrimitiveRestartTests.PrimitiveType = {
64         PRIMITIVE_POINTS: 0,
65         PRIMITIVE_LINE_STRIP: 1,
66         PRIMITIVE_LINE_LOOP: 2,
67         PRIMITIVE_LINES: 3,
68         PRIMITIVE_TRIANGLE_STRIP: 4,
69         PRIMITIVE_TRIANGLE_FAN: 5,
70         PRIMITIVE_TRIANGLES: 6
71     };
73     /**
74      * @enum
75      */
76     es3fPrimitiveRestartTests.IndexType = {
77         INDEX_UNSIGNED_BYTE: 0,
78         INDEX_UNSIGNED_SHORT: 1,
79         INDEX_UNSIGNED_INT: 2
80     };
82     /**
83      * @enum
84      */
85     es3fPrimitiveRestartTests.DrawFunction = {
86         FUNCTION_DRAW_ELEMENTS: 0,
87         FUNCTION_DRAW_ELEMENTS_INSTANCED: 1,
88         FUNCTION_DRAW_RANGE_ELEMENTS: 2
89     };
91     /**
92     * es3fPrimitiveRestartTests.PrimitiveRestartCase class, inherits from TestCase class
93     * @constructor
94     * @extends {tcuTestCase.DeqpTest}
95     * @param {?string} name
96     * @param {string} description
97     * @param {es3fPrimitiveRestartTests.PrimitiveType} primType
98     * @param {es3fPrimitiveRestartTests.IndexType} indexType
99     * @param {es3fPrimitiveRestartTests.DrawFunction} _function
100     * @param {boolean} beginWithRestart
101     * @param {boolean} endWithRestart
102     * @param {boolean} duplicateRestarts
103     */
104     es3fPrimitiveRestartTests.PrimitiveRestartCase = function(name, description, primType, indexType, _function, beginWithRestart, endWithRestart, duplicateRestarts) {
105         tcuTestCase.DeqpTest.call(this, name, description);
106         /** @type {es3fPrimitiveRestartTests.PrimitiveType} */ this.m_primType = primType;
107         /** @type {es3fPrimitiveRestartTests.IndexType} */ this.m_indexType = indexType;
108         /** @type {es3fPrimitiveRestartTests.DrawFunction} */ this.m_function = _function;
109         /** @type {boolean} */ this.m_beginWithRestart = beginWithRestart; // Whether there will be restart indices at the beginning of the index array.
110         /** @type {boolean} */ this.m_endWithRestart = endWithRestart; // Whether there will be restart indices at the end of the index array.
111         /** @type {boolean} */ this.m_duplicateRestarts = duplicateRestarts; // Whether two consecutive restarts are used instead of one.
112         /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
114         // \note Only one of the following index vectors is used (according to m_indexType).
115         /** @type {Array<number>} */ this.m_indicesUB = []; //deUint8
116         /** @type {Array<number>} */ this.m_indicesUS = []; //deUint16
117         /** @type {Array<number>} */ this.m_indicesUI = []; //deUint32
119         /** @type {Array<number>} */ this.m_positions = [];
120     };
122     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
123     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.constructor = es3fPrimitiveRestartTests.PrimitiveRestartCase;
125     /**
126     * Draw with the appropriate GLES3 draw function.
127     * @param {number} startNdx
128     * @param {number} count
129     */
130     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.draw = function(startNdx, count) {
131         /** @type {number} */ var primTypeGL;
133         switch (this.m_primType) {
134             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS:
135                 primTypeGL = gl.POINTS;
136                 break;
137             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP:
138                 primTypeGL = gl.LINE_STRIP;
139                 break;
140             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP:
141                 primTypeGL = gl.LINE_LOOP;
142                 break;
143             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES:
144                 primTypeGL = gl.LINES;
145                 break;
146             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP:
147                 primTypeGL = gl.TRIANGLE_STRIP;
148                 break;
149             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN:
150                 primTypeGL = gl.TRIANGLE_FAN;
151                 break;
152             case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES:
153                 primTypeGL = gl.TRIANGLES;
154                 break;
155             default:
156                 DE_ASSERT(false);
157                 primTypeGL = 0;
158         }
160         /** @type {number} */ var indexTypeGL;
162         switch (this.m_indexType) {
163             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
164                 indexTypeGL = gl.UNSIGNED_BYTE;
165                 break;
166             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
167                 indexTypeGL = gl.UNSIGNED_SHORT;
168                 break;
169             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
170                 indexTypeGL = gl.UNSIGNED_INT;
171                 break;
172             default:
173                 DE_ASSERT(false);
174                 indexTypeGL = 0;
175         }
177         /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
178                                                    this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
179                                                    this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
180                                                    0;
182         DE_ASSERT(restartIndex != 0);
184         var indexGLBuffer = gl.createBuffer();
185         var bufferIndex = this.getIndexPtr(startNdx);
186         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexGLBuffer);
187         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferIndex, gl.STATIC_DRAW);
189         if (this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS) {
190             gl.drawElements(primTypeGL, count, indexTypeGL, 0);
191         } else if (this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED) {
192             gl.drawElementsInstanced(primTypeGL, count, indexTypeGL, 0, 1);
193         } else {
194             DE_ASSERT(this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_RANGE_ELEMENTS);
196             // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
198             /** @type {number} */ var max = 0;
200             /** @type {number} */ var numIndices = this.getNumIndices();
201             for (var i = 0; i < numIndices; i++) {
202                 /** @type {number} */ var index = this.getIndex(i);
203                 if (index != restartIndex && index > max)
204                     max = index;
205             }
206             //TODO: drawRangeElements -> check getIndexPtr usage
207             gl.drawRangeElements(primTypeGL, 0, max, count, indexTypeGL, 0);
208         }
209     };
211     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.renderWithRestart = function() {
212         // Primitive Restart is always on in WebGL2
213         //gl.enable(gl.PRIMITIVE_RESTART_FIXED_INDEX);
215         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
217         this.draw(0, this.getNumIndices());
218     };
220     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.renderWithoutRestart = function() {
221         /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
222                                                  this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
223                                                  this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
224                                                  0;
226         DE_ASSERT(restartIndex != 0);
227         // Primitive Restart is always on in WebGL2
228         //gl.disable(gl.PRIMITIVE_RESTART_FIXED_INDEX);
230         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
232         // Draw, emulating primitive restart.
234         /** @type {number} */ var numIndices = this.getNumIndices();
236         DE_ASSERT(numIndices >= 0);
238         /** @type {number} */ var indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
240         for (var indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) { // \note Goes one "too far" in order to detect end of array as well.
241             if (indexArrayNdx >= numIndices || this.getIndex(indexArrayNdx) == restartIndex) {// \note Handle end of array the same way as a restart index encounter.
242                 if (indexArrayStartNdx < numIndices) {
243                     // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
245                     this.draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
246                 }
248                 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
249             }
250         }
251     };
253     /**
254     * @param {number} index
255     */
256     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.addIndex = function(index) {
257         if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE) {
258             DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE));
259             this.m_indicesUB.push(index); // deUint8
260         } else if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT) {
261             DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT));
262             this.m_indicesUS.push(index); // deUint16
263         } else if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT) {
264             DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_INT));
265             this.m_indicesUI.push(index); // // deUint32
266         } else
267             DE_ASSERT(false);
268     };
270     /**
271     * @param {number} indexNdx
272     * @return {number}
273     */
274     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getIndex = function(indexNdx) {
275         switch (this.m_indexType) {
276             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
277                 return this.m_indicesUB[indexNdx]; //deUint32
278             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
279                 return this.m_indicesUS[indexNdx]; //deUint32
280             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
281                 return this.m_indicesUI[indexNdx];
282             default:
283                 DE_ASSERT(false);
284                 return 0;
285         }
286     };
288     /**
289     * @return {number}
290     */
291     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getNumIndices = function() {
292         switch (this.m_indexType) {
293             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
294                 return this.m_indicesUB.length;
295             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
296                 return this.m_indicesUS.length;
297             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
298                 return this.m_indicesUI.length;
299             default:
300                 DE_ASSERT(false);
301                 return 0;
302         }
303     };
305     /**
306     * Pointer to the index value at index indexNdx.
307     * @param {number} indexNdx
308     * @return {Uint8Array|Uint16Array|Uint32Array}
309     */
310     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getIndexPtr = function(indexNdx) {
311         //TODO: implement
312         switch (this.m_indexType) {
313             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
314                 return new Uint8Array(this.m_indicesUB).subarray(indexNdx);
315             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
316                 return new Uint16Array(this.m_indicesUS).subarray(indexNdx);
317             case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
318                 return new Uint32Array(this.m_indicesUI).subarray(indexNdx);
319             default:
320                 DE_ASSERT(false);
321                 return null;
322         }
323     };
325     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.init = function() {
326         // Clear errors from previous tests
327         gl.getError();
329         // Create shader program.
331         /** @type {string} */ var vertShaderSource =
332             '#version 300 es\n' +
333             'in highp vec4 a_position;\n' +
334             '\n' +
335             'void main()\n' +
336             ' {\n' +
337             ' gl_Position = a_position;\n';
339         if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS) {
340             vertShaderSource += ' gl_PointSize = 1.0;\n';
341         }
343         vertShaderSource += '}\n';
345         /** @type {string} */ var fragShaderSource =
346             '#version 300 es\n' +
347             'layout(location = 0) out mediump vec4 o_color;\n' +
348             '\n' +
349             'void main()\n' +
350             ' {\n' +
351             ' o_color = vec4(1.0f);\n' +
352             '}\n';
354         DE_ASSERT(!this.m_program);
356         this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertShaderSource, fragShaderSource));
358         if (!this.m_program.isOk()) {
359             //m_testCtx.getLog() << *this.m_program;
360             testFailedOptions('Failed to compile shader', true);
361         }
363         /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
364                                                  this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
365                                                  this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
366                                                  0;
368         DE_ASSERT(restartIndex != 0);
370         DE_ASSERT(this.getNumIndices() == 0);
372         // If testing a case with restart at beginning, add it there.
373         if (this.m_beginWithRestart) {
374             this.addIndex(restartIndex);
375             if (this.m_duplicateRestarts)
376                 this.addIndex(restartIndex);
377         }
379         // Generate vertex positions and indices depending on primitive type.
380         // \note At this point, restarts shall not be added to the start or the end of the index vector. Those are special cases, and are done above and after the following if-else chain, respectively.
381         /** @type {number} */ var curIndex;
382         /** @type {number} */ var numRows;
383         /** @type {number} */ var numCols;
384         /** @type {number} */ var fx;
385         /** @type {number} */ var fy;
386         /** @type {number} */ var centerY;
387         /** @type {number} */ var centerX;
388         /** @type {number} */ var numVertices;
389         /** @type {number} */ var numArcVertices;
390         /** @type {number} */ var numStrips;
392         if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS) {
393             // Generate rows with different numbers of points.
395             curIndex = 0;
396             numRows = 20;
398             for (var row = 0; row < numRows; row++) {
399                 for (var col = 0; col < row + 1; col++) {
400                     fx = -1.0 + 2.0 * (col + 0.5) / numRows;
401                     fy = -1.0 + 2.0 * (row + 0.5) / numRows;
403                     this.m_positions.push(fx);
404                     this.m_positions.push(fy);
406                     this.addIndex(curIndex++);
407                 }
409                 if (row < numRows - 1) { // Add a restart after all but last row.
410                     this.addIndex(restartIndex);
411                     if (this.m_duplicateRestarts)
412                         this.addIndex(restartIndex);
413                 }
414             }
415         } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP || this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP || this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES) {
416             // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
418             curIndex = 0;
419             numRows = 4;
420             numCols = 4;
422             for (var row = 0; row < numRows; row++) {
423                 centerY = -1.0 + 2.0 * (row + 0.5) / numRows;
425                 for (var col = 0; col < numCols; col++) {
426                     centerX = -1.0 + 2.0 * (col + 0.5) / numCols;
427                     numVertices = row * numCols + col + 1;
429                     for (var i = 0; i < numVertices; i++) {
430                         fx = centerX + 0.9 * Math.cos(i * 2.0 * Math.PI / numVertices) / numCols;
431                         fy = centerY + 0.9 * Math.sin(i * 2.0 * Math.PI / numVertices) / numRows;
433                         this.m_positions.push(fx);
434                         this.m_positions.push(fy);
436                         this.addIndex(curIndex++);
437                     }
439                     if (col < numCols - 1 || row < numRows - 1) {// Add a restart after all but last polygon.
440                         this.addIndex(restartIndex);
441                         if (this.m_duplicateRestarts)
442                             this.addIndex(restartIndex);
443                     }
444                 }
445             }
446         } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP) {
447             // Generate a number of horizontal triangle strips of different lengths.
449             curIndex = 0;
450             numStrips = 20;
452             for (var stripNdx = 0; stripNdx < numStrips; stripNdx++) {
453                 numVertices = stripNdx + 1;
455                 for (var i = 0; i < numVertices; i++) {
456                     fx = -0.9 + 1.8 * (i / 2 * 2) / numStrips;
457                     fy = -0.9 + 1.8 * (stripNdx + (i % 2 == 0 ? 0.0 : 0.8)) / numStrips;
459                     this.m_positions.push(fx);
460                     this.m_positions.push(fy);
462                     this.addIndex(curIndex++);
463                 }
465                 if (stripNdx < numStrips - 1) { // Add a restart after all but last strip.
466                     this.addIndex(restartIndex);
467                     if (this.m_duplicateRestarts)
468                         this.addIndex(restartIndex);
469                 }
470             }
471         } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN) {
472             // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
474             curIndex = 0;
475             numRows = 4;
476             numCols = 4;
478             for (var row = 0; row < numRows; row++) {
479                 centerY = -1.0 + 2.0 * (row + 0.5) / numRows;
481                 for (var col = 0; col < numCols; col++) {
482                     centerX = -1.0 + 2.0 * (col + 0.5) / numCols;
483                     numArcVertices = row * numCols + col;
485                     this.m_positions.push(centerX);
486                     this.m_positions.push(centerY);
488                     this.addIndex(curIndex++);
490                     for (var i = 0; i < numArcVertices; i++) {
491                         fx = centerX + 0.9 * Math.cos(i * 2.0 * Math.PI / numArcVertices) / numCols;
492                         fy = centerY + 0.9 * Math.sin(i * 2.0 * Math.PI / numArcVertices) / numRows;
494                         this.m_positions.push(fx);
495                         this.m_positions.push(fy);
497                         this.addIndex(curIndex++);
498                     }
500                     if (col < numCols - 1 || row < numRows - 1) { // Add a restart after all but last polygon.
501                         this.addIndex(restartIndex);
502                         if (this.m_duplicateRestarts)
503                             this.addIndex(restartIndex);
504                     }
505                 }
506             }
507         } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES) {
508             // Generate a number of rows with (potentially incomplete) triangles.
510             curIndex = 0;
511             numRows = 3 * 7;
513             for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
514                 numVertices = rowNdx + 1;
516                 for (var i = 0; i < numVertices; i++) {
517                     fx = -0.9 + 1.8 * ((i / 3) + (i % 3 == 2 ? 0.8 : 0.0)) * 3 / numRows;
518                     fy = -0.9 + 1.8 * (rowNdx + (i % 3 == 0 ? 0.0 : 0.8)) / numRows;
520                     this.m_positions.push(fx);
521                     this.m_positions.push(fy);
523                     this.addIndex(curIndex++);
524                 }
526                 if (rowNdx < numRows - 1) { // Add a restart after all but last row.
527                     this.addIndex(restartIndex);
528                     if (this.m_duplicateRestarts)
529                         this.addIndex(restartIndex);
530                 }
531             }
532         } else
533             DE_ASSERT(false);
535         // If testing a case with restart at end, add it there.
536         if (this.m_endWithRestart) {
537             this.addIndex(restartIndex);
538             if (this.m_duplicateRestarts)
539                 this.addIndex(restartIndex);
540         }
542         // Special case assertions.
544         /** @type {number} */ var numIndices = this.getNumIndices();
546         DE_ASSERT(numIndices > 0);
547         DE_ASSERT(this.m_beginWithRestart || this.getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case.
548         DE_ASSERT(this.m_endWithRestart || this.getIndex(numIndices - 1) != restartIndex); // We don't want restarts at end unless the case is a special case.
550         if (!this.m_duplicateRestarts)
551             for (var i = 1; i < numIndices; i++)
552                 DE_ASSERT(this.getIndex(i) != restartIndex || this.getIndex(i - 1) != restartIndex); // We don't want duplicate restarts unless the case is a special case.
554     };
556     es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.iterate = function() {
557         /** @type {number} */ var width = Math.min(gl.drawingBufferWidth, es3fPrimitiveRestartTests.MAX_RENDER_WIDTH);
558         /** @type {number} */ var height = Math.min(gl.drawingBufferHeight, es3fPrimitiveRestartTests.MAX_RENDER_HEIGHT);
560         /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
561         /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
563         /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
565         /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
566         /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
567         /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(width, height);
568         /** @type {tcuSurface.Surface} */ var resultImg = new tcuSurface.Surface(width, height);
570         gl.viewport(xOffset, yOffset, width, height);
571         gl.clearColor(0.0, 0.0, 0.0, 1.0);
573         var program = this.m_program.getProgram();
574         gl.useProgram(program);
576         // Setup position attribute.
578         /** @type {number} */ var loc = gl.getAttribLocation(program, 'a_position');
579         gl.enableVertexAttribArray(loc);
581         var locGlBuffer = gl.createBuffer();
582         var bufferLoc = new Float32Array(this.m_positions);
583         gl.bindBuffer(gl.ARRAY_BUFFER, locGlBuffer);
584         gl.bufferData(gl.ARRAY_BUFFER, bufferLoc, gl.STATIC_DRAW);
585         gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
587         // Render result.
588         this.renderWithRestart();
589         var resImg = resultImg.getAccess();
590         var resImgTransferFormat = gluTextureUtil.getTransferFormat(resImg.getFormat());
591         gl.readPixels(xOffset, yOffset, resImg.m_width, resImg.m_height, resImgTransferFormat.format, resImgTransferFormat.dataType, resultImg.m_pixels);
593         // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
594         this.renderWithoutRestart();
596         var refImg = referenceImg.getAccess();
597         var refImgTransferFormat = gluTextureUtil.getTransferFormat(refImg.getFormat());
599         gl.readPixels(xOffset, yOffset, refImg.m_width, refImg.m_height, refImgTransferFormat.format, refImgTransferFormat.dataType, referenceImg.m_pixels);
601         // Compare.
602         /** @type {boolean} */ var testOk = tcuImageCompare.pixelThresholdCompare('ComparisonResult', 'Image comparison result', referenceImg, resultImg, [0, 0, 0, 0]);
604         assertMsgOptions(testOk, '', true, false);
605         gl.useProgram(null);
607         return tcuTestCase.IterateResult.STOP;
608     };
610     es3fPrimitiveRestartTests.init = function() {
611         var testGroup = tcuTestCase.runner.testCases;
612         for (var isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++) {
613             for (var isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++) {
614                 for (var isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++) {
615                     /** @type {boolean} */ var isRestartBeginCase = isRestartBeginCaseI != 0;
616                     /** @type {boolean} */ var isRestartEndCase = isRestartEndCaseI != 0;
617                     /** @type {boolean} */ var isDuplicateRestartCase = isDuplicateRestartCaseI != 0;
619                     /** @type {string} */ var specialCaseGroupName = '';
621                     if (isRestartBeginCase) specialCaseGroupName = 'begin_restart';
622                     if (isRestartEndCase) specialCaseGroupName += (deString.deIsStringEmpty(specialCaseGroupName) ? '' : '_') + 'end_restart';
623                     if (isDuplicateRestartCase) specialCaseGroupName += (deString.deIsStringEmpty(specialCaseGroupName) ? '' : '_') + 'duplicate_restarts';
625                     if (deString.deIsStringEmpty(specialCaseGroupName))
626                         specialCaseGroupName = 'basic';
628                     /** @type {tcuTestCase.DeqpTest} */ var specialCaseGroup = tcuTestCase.newTest(specialCaseGroupName, '');
629                     testGroup.addChild(specialCaseGroup);
631                     for (var primType in es3fPrimitiveRestartTests.PrimitiveType) {
632                         /** @type {string} */ var primTypeName = es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS ? 'points' :
633                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP ? 'line_strip' :
634                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP ? 'line_loop' :
635                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES ? 'lines' :
636                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP ? 'triangle_strip' :
637                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN ? 'triangle_fan' :
638                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES ? 'triangles' :
639                                                                  '';
641                         DE_ASSERT(primTypeName != null);
643                         /** @type {tcuTestCase.DeqpTest} */ var primTypeGroup = tcuTestCase.newTest(primTypeName, '');
644                         specialCaseGroup.addChild(primTypeGroup);
646                         for (var indexType in es3fPrimitiveRestartTests.IndexType) {
647                             /** @type {string} */ var indexTypeName = es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? 'unsigned_byte' :
648                                                                       es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? 'unsigned_short' :
649                                                                       es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? 'unsigned_int' :
650                                                                       '';
652                             DE_ASSERT(indexTypeName != null);
654                             /** @type {tcuTestCase.DeqpTest} */ var indexTypeGroup = tcuTestCase.newTest(indexTypeName, '');
655                             primTypeGroup.addChild(indexTypeGroup);
657                             for (var _function in es3fPrimitiveRestartTests.DrawFunction) {
658                                 /** @type {?string} */ var functionName = es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS ? 'draw_elements' :
659                                                                          es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'draw_elements_instanced' :
660                                                                          es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_RANGE_ELEMENTS ? 'draw_range_elements' :
661                                                                          null;
663                                 DE_ASSERT(functionName != null);
665                                 indexTypeGroup.addChild(new es3fPrimitiveRestartTests.PrimitiveRestartCase(functionName,
666                                                                                  '',
667                                                                                  es3fPrimitiveRestartTests.PrimitiveType[primType],
668                                                                                  es3fPrimitiveRestartTests.IndexType[indexType],
669                                                                                  es3fPrimitiveRestartTests.DrawFunction[_function],
670                                                                                  isRestartBeginCase,
671                                                                                  isRestartEndCase,
672                                                                                  isDuplicateRestartCase));
673                             }
674                         }
675                     }
676                 }
677             }
678         }
679     };
681     es3fPrimitiveRestartTests.run = function(context, range) {
682         gl = context;
683         //Set up Test Root parameters
684         var testName = 'primitive_restart';
685         var testDescription = 'Primitive Restart Tests';
686         var state = tcuTestCase.runner;
688         state.testName = testName;
689         state.setRoot(tcuTestCase.newTest(testName, testDescription, null));
691         //Set up name and description of this test series.
692         setCurrentTestName(testName);
693         description(testDescription);
695         try {
696             //Create test cases
697             es3fPrimitiveRestartTests.init();
698             if (range)
699                 state.setRange(range);
700             //Run test cases
701             tcuTestCase.runTestCases();
702         }
703         catch (err) {
704             testFailedOptions('Failed to es3fPrimitiveRestartTests.run tests', false);
705             tcuTestCase.runner.terminate();
706         }
707     };