1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
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');
63 es3fPrimitiveRestartTests.PrimitiveType = {
65 PRIMITIVE_LINE_STRIP: 1,
66 PRIMITIVE_LINE_LOOP: 2,
68 PRIMITIVE_TRIANGLE_STRIP: 4,
69 PRIMITIVE_TRIANGLE_FAN: 5,
70 PRIMITIVE_TRIANGLES: 6
76 es3fPrimitiveRestartTests.IndexType = {
77 INDEX_UNSIGNED_BYTE: 0,
78 INDEX_UNSIGNED_SHORT: 1,
85 es3fPrimitiveRestartTests.DrawFunction = {
86 FUNCTION_DRAW_ELEMENTS: 0,
87 FUNCTION_DRAW_ELEMENTS_INSTANCED: 1,
88 FUNCTION_DRAW_RANGE_ELEMENTS: 2
92 * es3fPrimitiveRestartTests.PrimitiveRestartCase class, inherits from TestCase class
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
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 = [];
122 es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
123 es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.constructor = es3fPrimitiveRestartTests.PrimitiveRestartCase;
126 * Draw with the appropriate GLES3 draw function.
127 * @param {number} startNdx
128 * @param {number} count
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;
137 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP:
138 primTypeGL = gl.LINE_STRIP;
140 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP:
141 primTypeGL = gl.LINE_LOOP;
143 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES:
144 primTypeGL = gl.LINES;
146 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP:
147 primTypeGL = gl.TRIANGLE_STRIP;
149 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN:
150 primTypeGL = gl.TRIANGLE_FAN;
152 case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES:
153 primTypeGL = gl.TRIANGLES;
160 /** @type {number} */ var indexTypeGL;
162 switch (this.m_indexType) {
163 case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
164 indexTypeGL = gl.UNSIGNED_BYTE;
166 case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
167 indexTypeGL = gl.UNSIGNED_SHORT;
169 case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
170 indexTypeGL = gl.UNSIGNED_INT;
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 :
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);
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)
206 //TODO: drawRangeElements -> check getIndexPtr usage
207 gl.drawRangeElements(primTypeGL, 0, max, count, indexTypeGL, 0);
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());
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 :
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);
248 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
254 * @param {number} index
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
271 * @param {number} indexNdx
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];
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;
306 * Pointer to the index value at index indexNdx.
307 * @param {number} indexNdx
308 * @return {Uint8Array|Uint16Array|Uint32Array}
310 es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getIndexPtr = function(indexNdx) {
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);
325 es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.init = function() {
326 // Clear errors from previous tests
329 // Create shader program.
331 /** @type {string} */ var vertShaderSource =
332 '#version 300 es\n' +
333 'in highp vec4 a_position;\n' +
337 ' gl_Position = a_position;\n';
339 if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS) {
340 vertShaderSource += ' gl_PointSize = 1.0;\n';
343 vertShaderSource += '}\n';
345 /** @type {string} */ var fragShaderSource =
346 '#version 300 es\n' +
347 'layout(location = 0) out mediump vec4 o_color;\n' +
351 ' o_color = vec4(1.0f);\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);
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 :
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);
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.
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++);
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);
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.
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++);
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);
446 } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP) {
447 // Generate a number of horizontal triangle strips of different lengths.
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++);
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);
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.
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++);
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);
507 } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES) {
508 // Generate a number of rows with (potentially incomplete) triangles.
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++);
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);
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);
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.
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);
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);
602 /** @type {boolean} */ var testOk = tcuImageCompare.pixelThresholdCompare('ComparisonResult', 'Image comparison result', referenceImg, resultImg, [0, 0, 0, 0]);
604 assertMsgOptions(testOk, '', true, false);
607 return tcuTestCase.IterateResult.STOP;
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' :
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' :
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' :
663 DE_ASSERT(functionName != null);
665 indexTypeGroup.addChild(new es3fPrimitiveRestartTests.PrimitiveRestartCase(functionName,
667 es3fPrimitiveRestartTests.PrimitiveType[primType],
668 es3fPrimitiveRestartTests.IndexType[indexType],
669 es3fPrimitiveRestartTests.DrawFunction[_function],
672 isDuplicateRestartCase));
681 es3fPrimitiveRestartTests.run = function(context, range) {
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);
697 es3fPrimitiveRestartTests.init();
699 state.setRange(range);
701 tcuTestCase.runTestCases();
704 testFailedOptions('Failed to es3fPrimitiveRestartTests.run tests', false);
705 tcuTestCase.runner.terminate();