Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fTransformFeedbackTests.js
blob5beae6985d53aab8b108a2b648ebb3768af8394d
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.es3fTransformFeedbackTests');
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.gluDrawUtil');
30 goog.require('framework.opengl.gluShaderProgram');
31 goog.require('framework.opengl.gluShaderUtil');
32 goog.require('framework.opengl.gluVarType');
33 goog.require('framework.opengl.gluVarTypeUtil');
35 goog.scope(function() {
37     var es3fTransformFeedbackTests = functional.gles3.es3fTransformFeedbackTests;
38     var gluShaderUtil = framework.opengl.gluShaderUtil;
39     var gluDrawUtil = framework.opengl.gluDrawUtil;
40     var gluVarType = framework.opengl.gluVarType;
41     var gluVarTypeUtil = framework.opengl.gluVarTypeUtil;
42     var gluShaderProgram = framework.opengl.gluShaderProgram;
43     var deRandom = framework.delibs.debase.deRandom;
44     var deMath = framework.delibs.debase.deMath;
45     var deString = framework.delibs.debase.deString;
46     var tcuTestCase = framework.common.tcuTestCase;
47     var tcuSurface = framework.common.tcuSurface;
48     var tcuImageCompare = framework.common.tcuImageCompare;
50     /** @type {WebGL2RenderingContext} */ var gl;
52     var setParentClass = function(child, parent) {
53         child.prototype = Object.create(parent.prototype);
54         child.prototype.constructor = child;
55     };
57     /**
58      * @enum
59      */
60     es3fTransformFeedbackTests.State = {
61         DRAW: 0,
62         VERIFY: 1,
63         FINISH: 2
64     };
66     /* Maximum time to wait for query result (in seconds) */
67     /** @const */ es3fTransformFeedbackTests.MAX_VERIFY_WAIT = 5;
69     /** @const @type {number} */ es3fTransformFeedbackTests.VIEWPORT_WIDTH = 128;
70     /** @const @type {number} */ es3fTransformFeedbackTests.VIEWPORT_HEIGHT = 128;
71     /** @const @type {number} */ es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER = 2;
73     /**
74      * Enums for es3fTransformFeedbackTests.interpolation
75      * @enum {number}
76      */
77     es3fTransformFeedbackTests.interpolation = {
78         SMOOTH: 0,
79         FLAT: 1,
80         CENTROID: 2
82     };
84     /**
85      * Returns es3fTransformFeedbackTests.interpolation name: smooth, flat or centroid
86      * @param {number} interpol es3fTransformFeedbackTests.interpolation enum value
87      * @return {string}
88      */
89     es3fTransformFeedbackTests.getInterpolationName = function(interpol) {
91         switch (interpol) {
92         case es3fTransformFeedbackTests.interpolation.SMOOTH: return 'smooth';
93         case es3fTransformFeedbackTests.interpolation.FLAT: return 'flat';
94         case es3fTransformFeedbackTests.interpolation.CENTROID: return 'centroid';
95         default:
96             throw new Error('Unrecognized es3fTransformFeedbackTests.interpolation name ' + interpol);
97        }
99     };
101     /**
102      * @struct
103      * @param {string} name
104      * @param {gluVarType.VarType} type
105      * @param {number} interpolation
106      * @constructor
107      */
108     es3fTransformFeedbackTests.Varying = function(name, type, interpolation) {
109         this.name = name;
110         this.type = type;
111         this.interpolation = interpolation;
112     };
114     /** es3fTransformFeedbackTests.findAttributeNameEquals
115      * Replaces original implementation of "VaryingNameEquals" and "AttributeNameEquals" in the C++ version
116      * Returns an es3fTransformFeedbackTests.Attribute or es3fTransformFeedbackTests.Varying object which matches its name with the passed string value in the function
117      * @param {(Array<es3fTransformFeedbackTests.Attribute> | Array<es3fTransformFeedbackTests.Varying>)} array
118      * @param {string} name
119      * @return { (es3fTransformFeedbackTests.Attribute | es3fTransformFeedbackTests.Varying | null)}
120      */
121     es3fTransformFeedbackTests.findAttributeNameEquals = function(array, name) {
122         for (var pos = 0; pos < array.length; pos++) {
123             if (array[pos].name === name) {
124                 return array[pos];
125             }
126         }
127         return null;
128     };
130     /**
131      * @struct
132      * @param {string} name
133      * @param {gluVarType.VarType} type
134      * @param {number} offset
135      * @constructor
136      */
137     es3fTransformFeedbackTests.Attribute = function(name, type, offset) {
138         this.name = name;
139         this.type = type;
140         this.offset = offset;
141     };
143     /**
144      * Constructs an es3fTransformFeedbackTests.Output object
145      * @constructor
146      */
147     es3fTransformFeedbackTests.Output = function() {
148         /** @type {number} */ this.bufferNdx = 0;
149         /** @type {number} */ this.offset = 0;
150         /** @type {string} */ this.name;
151         /** @type {gluVarType.VarType} */ this.type = null;
152         /** @type {Array<es3fTransformFeedbackTests.Attribute>} */ this.inputs = [];
153     };
155     /**
156      * Constructs an object type es3fTransformFeedbackTests.DrawCall.
157      * Contains the number of elements as well as whether the Transform Feedback is enabled or not.
158      * @struct
159      * @param {number} numElements
160      * @param {boolean} tfEnabled is Transform Feedback enabled or not
161      * @constructor
162      */
163     es3fTransformFeedbackTests.DrawCall = function(numElements, tfEnabled) {
164         this.numElements = numElements;
165         this.transformFeedbackEnabled = tfEnabled;
166     };
168     /**
169      * @constructor
170      */
171     es3fTransformFeedbackTests.ProgramSpec = function() {
173     /** @type {Array<gluVarType.StructType>} */ var m_structs = [];
174     /** @type {Array<es3fTransformFeedbackTests.Varying>} */ var m_varyings = [];
175     /** @type {Array<string>} */ var m_transformFeedbackVaryings = [];
177         this.createStruct = function(name) {
178             var struct = gluVarType.newStructType(name);
179             m_structs.push(struct);
180             return struct;
181         };
183         this.addVarying = function(name, type, interp) {
184             m_varyings.push(new es3fTransformFeedbackTests.Varying(name, type, interp));
185         };
187         this.addTransformFeedbackVarying = function(name) {
188             m_transformFeedbackVaryings.push(name);
189         };
191         this.getStructs = function() {
192             return m_structs;
193         };
194         this.getVaryings = function() {
195             return m_varyings;
196         };
197         this.getTransformFeedbackVaryings = function() {
198             return m_transformFeedbackVaryings;
199         };
201         this.isPointSizeUsed = function() {
202             for (var i = 0; i < m_transformFeedbackVaryings.length; ++i) {
203                 if (m_transformFeedbackVaryings[i] == 'gl_PointSize') return true;
204             }
205             return false;
206         };
208     };
210     /** Returns if the program is supported or not
211      * @param {es3fTransformFeedbackTests.ProgramSpec} spec
212      * @param {number} tfMode
213      * @return {boolean}
214      */
215     es3fTransformFeedbackTests.isProgramSupported = function(spec, tfMode) {
216         var maxVertexAttribs = Number(gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
217         var maxTfInterleavedComponents = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS));
218         var maxTfSeparateAttribs = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS));
219         var maxTfSeparateComponents = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS));
221         // Check vertex attribs.
222         /** @type {number} */ var totalVertexAttribs = (
223             1 /* a_position */ + (spec.isPointSizeUsed() ? 1 : 0)
224         );
226         for (var i = 0; i < spec.getVaryings().length; ++i) {
227             for (var v_iter = new gluVarTypeUtil.VectorTypeIterator(spec.getVaryings()[i].type); !v_iter.end(); v_iter.next()) {
228                 totalVertexAttribs += 1;
229             }
230         }
232         if (totalVertexAttribs > maxVertexAttribs)
233             return false; // Vertex attribute es3fTransformFeedbackTests.count exceeded.
235         // check varyings
236         /** @type {number} */ var totalTfComponents = 0;
237         /** @type {number} */ var totalTfAttribs = 0;
238         /** @type {Object.<number, number>} */ var presetNumComponents = {
239             gl_Position: 4,
240             gl_PointSize: 1
241         };
242         for (var i = 0; i < spec.getTransformFeedbackVaryings().length; ++i) {
243             var name = spec.getTransformFeedbackVaryings()[i];
244             var numComponents = 0;
246             if (typeof(presetNumComponents[name]) != 'undefined') {
247                 numComponents = presetNumComponents[name];
248             } else {
249                 var varName = gluVarTypeUtil.parseVariableName(name);
250                 // find the varying called varName
251                 /** @type {es3fTransformFeedbackTests.Varying} */ var varying = (function(varyings) {
252                     for (var i = 0; i < varyings.length; ++i) {
253                         if (varyings[i].name == varName) {
254                             return varyings[i];
255                         }
256                     }
257                     return null;
258                 }(spec.getVaryings()));
260                 // glu::TypeComponentVector
261                 var varPath = gluVarTypeUtil.parseTypePath(name, varying.type);
262                 numComponents = gluVarTypeUtil.getVarType(varying.type, varPath).getScalarSize();
263             }
265             if (tfMode == gl.SEPARATE_ATTRIBS && numComponents > maxTfSeparateComponents)
266                 return false; // Per-attribute component es3fTransformFeedbackTests.count exceeded.
268             totalTfComponents += numComponents;
269             totalTfAttribs += 1;
270         }
272         if (tfMode == gl.SEPARATE_ATTRIBS && totalTfAttribs > maxTfSeparateAttribs)
273             return false;
275         if (tfMode == gl.INTERLEAVED_ATTRIBS && totalTfComponents > maxTfInterleavedComponents)
276             return false;
278         return true;
280     };
282     /**
283      * @param {string} varyingName
284      * @param {Array<gluVarTypeUtil.VarTypeComponent>} path
285      * @return {string}
286      */
287     es3fTransformFeedbackTests.getAttributeName = function(varyingName, path) {
288     /** @type {string} */ var str = 'a_' + varyingName.substr(/^v_/.test(varyingName) ? 2 : 0);
290         for (var i = 0; i < path.length; ++i) {
291         /** @type {string} */ var prefix;
293             switch (path[i].type) {
294                 case gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER: prefix = '_m'; break;
295                 case gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT: prefix = '_e'; break;
296                 case gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN: prefix = '_c'; break;
297                 case gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT: prefix = '_s'; break;
298                 default:
299                     throw new Error('invalid type in the component path.');
300             }
301             str += prefix + path[i].index;
302         }
303         return str;
304     };
306     /**
307      * original definition:
308      * static void es3fTransformFeedbackTests.genShaderSources (const es3fTransformFeedbackTests.ProgramSpec& spec, std::string& vertSource, std::string& fragSource, bool pointSizeRequired)
309      * in place of the std::string references, this function returns those params in an object
310      *
311      * @param {es3fTransformFeedbackTests.ProgramSpec} spec
312      * @param {boolean} pointSizeRequired
313      * @return {Object.<string, string>}
314      */
315     es3fTransformFeedbackTests.genShaderSources = function(spec, pointSizeRequired) {
317         var vtx = { str: null };
318         var frag = { str: null };
319         var addPointSize = spec.isPointSizeUsed();
321         vtx.str = '#version 300 es\n' +
322                  'in highp vec4 a_position;\n';
323         frag.str = '#version 300 es\n' +
324                  'layout(location = 0) out mediump vec4 o_color;\n' +
325                  'uniform highp vec4 u_scale;\n' +
326                  'uniform highp vec4 u_bias;\n';
327         //vtx.str = 'attribute highp vec4 a_position;\n';
328         //frag.str = 'uniform highp vec4 u_scale;\n' +
329         //         'uniform highp vec4 u_bias;\n';
331         if (addPointSize) {
332             vtx.str += 'in highp float a_pointSize;\n';
333             //vtx.str += 'attribute highp float a_pointSize;\n';
334         }
336         // Declare attributes.
337         for (var i = 0; i < spec.getVaryings().length; ++i) {
339         /** @type {string} */ var name = spec.getVaryings()[i].name;
340         /** @type {gluVarType.VarType} */ var type = spec.getVaryings()[i].type;
342             for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(type); !vecIter.end(); vecIter.next()) {
344                 /** @type {gluVarType.VarType} */
345                 var attribType = gluVarTypeUtil.getVarType(type, vecIter.getPath());
347                 /** @type {string} */
348                 var attribName = es3fTransformFeedbackTests.getAttributeName(name, vecIter.getPath());
349                 vtx.str += 'in ' + gluVarType.declareVariable(attribType, attribName) + ';\n';
351             }
352         }
354         // Declare varyings.
355         for (var ndx = 0; ndx < 2; ++ndx) {
356             var inout = ndx ? 'in' : 'out';
357             var shader = ndx ? frag : vtx;
359             for (var i = 0; i < spec.getStructs().length; ++i) {
360                 var struct = spec.getStructs()[i];
361                 if (struct.hasTypeName()) {
362                     shader.str += gluVarType.declareStructType(struct) + ';\n';
363                 }
364             }
366             /** @type {Array<es3fTransformFeedbackTests.Varying>} */ var varyings = spec.getVaryings();
367             for (var i = 0; i < varyings.length; ++i) {
368                 var varying = varyings[i];
369                 shader.str += es3fTransformFeedbackTests.getInterpolationName(varying.interpolation) +
370                            ' ' + inout + ' ' +
371                            gluVarType.declareVariable(varying.type, varying.name) +
372                            ';\n';
373             }
374         }
376         vtx.str += '\nvoid main (void)\n {\n' +
377                  '\tgl_Position = a_position;\n';
378         frag.str += '\nvoid main (void)\n {\n' +
379                  '\thighp vec4 res = vec4(0.0);\n';
381         if (addPointSize) {
382             vtx.str += '\tgl_PointSize = a_pointSize;\n';
383         } else if (pointSizeRequired) {
384             vtx.str += '\tgl_PointSize = 1.0;\n';
385         }
387         for (var i = 0; i < spec.getVaryings().length; ++i) {
388             var name = spec.getVaryings()[i].name;
389             var type = spec.getVaryings()[i].type;
391             for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(type); !vecIter.end(); vecIter.next()) {
392                 /** @type {gluVarType.VarType} */var subType = gluVarTypeUtil.getVarType(type, vecIter.getPath());
393                 var attribName = es3fTransformFeedbackTests.getAttributeName(name, vecIter.getPath());
395                 if (!(
396                     subType.isBasicType() &&
397                     gluShaderUtil.isDataTypeScalarOrVector(subType.getBasicType())
398                 )) throw new Error('Not a scalar or vector.');
400                 // Vertex: assign from attribute.
401                 vtx.str += '\t' + name + vecIter.toString() + ' = ' + attribName + ';\n';
403                 // Fragment: add to res variable.
404                 var scalarSize = gluShaderUtil.getDataTypeScalarSize(subType.getBasicType());
406                 frag.str += '\tres += ';
407                 if (scalarSize == 1) frag.str += 'vec4(' + name + vecIter.toString() + ')';
408                 else if (scalarSize == 2) frag.str += 'vec2(' + name + vecIter.toString() + ').xxyy';
409                 else if (scalarSize == 3) frag.str += 'vec3(' + name + vecIter.toString() + ').xyzx';
410                 else if (scalarSize == 4) frag.str += 'vec4(' + name + vecIter.toString() + ')';
412                 frag.str += ';\n';
413             }
414         }
416         frag.str += '\to_color = res * u_scale + u_bias;\n}\n';
417         //frag.str += '\tgl_FragColor = res * u_scale + u_bias;\n}\n';
418         vtx.str += '}\n';
420         return {
421             vertSource: vtx.str,
422             fragSource: frag.str
423         };
424     };
426     /**
427      * Returns a Shader program
428      * @param {es3fTransformFeedbackTests.ProgramSpec} spec
429      * @param {number} bufferMode
430      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
431      * @return {gluShaderProgram.ShaderProgram}
432      */
433     es3fTransformFeedbackTests.createVertexCaptureProgram = function(spec, bufferMode, primitiveType) {
435     /** @type {Object.<string, string>} */ var source = es3fTransformFeedbackTests.genShaderSources(spec, primitiveType === gluDrawUtil.primitiveType.POINTS /* Is point size required? */);
437         var programSources = new gluShaderProgram.ProgramSources();
438         programSources.add(new gluShaderProgram.VertexSource(source.vertSource))
439                       .add(new gluShaderProgram.FragmentSource(source.fragSource))
440                       .add(new gluShaderProgram.TransformFeedbackVaryings(spec.getTransformFeedbackVaryings()))
441                       .add(new gluShaderProgram.TransformFeedbackMode(bufferMode));
443         return new gluShaderProgram.ShaderProgram(gl, programSources);
445     };
447     /**
448      * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
449      * @param {Array<es3fTransformFeedbackTests.Varying>} varyings
450      * @param {boolean} usePointSize
451      * @return {number} input stride
452      */
453     es3fTransformFeedbackTests.computeInputLayout = function(attributes, varyings, usePointSize) {
455         var inputStride = 0;
457         // Add position
458         var dataTypeVec4 = gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, gluShaderUtil.precision.PRECISION_HIGHP);
459         attributes.push(new es3fTransformFeedbackTests.Attribute('a_position', dataTypeVec4, inputStride));
460         inputStride += 4 * 4; /*sizeof(deUint32)*/
462         if (usePointSize) {
463             var dataTypeFloat = gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT, gluShaderUtil.precision.PRECISION_HIGHP);
464             attributes.push(new es3fTransformFeedbackTests.Attribute('a_pointSize', dataTypeFloat, inputStride));
465             inputStride += 1 * 4; /*sizeof(deUint32)*/
466         }
468         for (var i = 0; i < varyings.length; i++) {
469             for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(varyings[i].type); !vecIter.end(); vecIter.next()) {
470                 var type = vecIter.getType(); // originally getType() in getVarType() within gluVARTypeUtil.hpp.
471                 var name = es3fTransformFeedbackTests.getAttributeName(varyings[i].name, vecIter.getPath());
473                 attributes.push(new es3fTransformFeedbackTests.Attribute(name, type, inputStride));
474                 inputStride += gluShaderUtil.getDataTypeScalarSize(type.getBasicType()) * 4; /*sizeof(deUint32)*/
475             }
476         }
478         return inputStride;
479     };
481     /**
482      * @param {Array<es3fTransformFeedbackTests.Output>} transformFeedbackOutputs
483      * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
484      * @param {Array<es3fTransformFeedbackTests.Varying>} varyings
485      * @param {Array<string>} transformFeedbackVaryings
486      * @param {number} bufferMode
487      */
488     es3fTransformFeedbackTests.computeTransformFeedbackOutputs = function(transformFeedbackOutputs, attributes, varyings, transformFeedbackVaryings, bufferMode) {
490         /** @type {number} */ var accumulatedSize = 0;
492         // transformFeedbackOutputs.resize(transformFeedbackVaryings.size());
493         for (var varNdx = 0; varNdx < transformFeedbackVaryings.length; varNdx++) {
494             /** @type {string} */ var name = transformFeedbackVaryings[varNdx];
495             /** @type {number} */ var bufNdx = (bufferMode === gl.SEPARATE_ATTRIBS ? varNdx : 0);
496             /** @type {number} */ var offset = (bufferMode === gl.SEPARATE_ATTRIBS ? 0 : accumulatedSize);
497             /** @type {es3fTransformFeedbackTests.Output} */ var output = new es3fTransformFeedbackTests.Output();
499             output.name = name;
500             output.bufferNdx = bufNdx;
501             output.offset = offset;
503             if (name === 'gl_Position') {
504                 var posIn = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_position');
505                 output.type = posIn.type;
506                 output.inputs.push(posIn);
507             } else if (name === 'gl_PointSize') {
508                 var sizeIn = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_pointSize');
509                 output.type = sizeIn.type;
510                 output.inputs.push(sizeIn);
511             } else {
512                 var varName = gluVarTypeUtil.parseVariableName(name);
513                 var varying = es3fTransformFeedbackTests.findAttributeNameEquals(varyings, varName);
515                 var varPath = gluVarTypeUtil.parseTypePath(name, varying.type);
516                 output.type = gluVarTypeUtil.getVarType(varying.type, varPath);
518                 // Add all vectorized attributes as inputs.
519                 for (var iter = new gluVarTypeUtil.VectorTypeIterator(output.type); !iter.end(); iter.next()) {
520                     var fullpath = varPath.concat(iter.getPath());
521                     var attribName = es3fTransformFeedbackTests.getAttributeName(varName, fullpath);
522                     var attrib = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, attribName);
523                     output.inputs.push(attrib);
524                 }
525             }
526             transformFeedbackOutputs.push(output);
527             accumulatedSize += output.type.getScalarSize() * 4; /*sizeof(deUint32)*/
528         }
529     };
531     /**
532      * @param {es3fTransformFeedbackTests.Attribute} attrib
533      * @param {ArrayBuffer} buffer
534      * @param {number} stride
535      * @param {number} numElements
536      * @param {deRandom.Random} rnd
537      */
538     es3fTransformFeedbackTests.genAttributeData = function(attrib, buffer, stride, numElements, rnd) {
540         /** @type {number} */ var elementSize = 4; /*sizeof(deUint32)*/
541         /** @type {boolean} */ var isFloat = gluShaderUtil.isDataTypeFloatOrVec(attrib.type.getBasicType());
542         /** @type {boolean} */ var isInt = gluShaderUtil.isDataTypeIntOrIVec(attrib.type.getBasicType());
543         /** @type {boolean} */ var isUint = gluShaderUtil.isDataTypeUintOrUVec(attrib.type.getBasicType());
545         /** @type {gluShaderUtil.precision} */ var precision = attrib.type.getPrecision();
547         /** @type {number} */ var numComps = gluShaderUtil.getDataTypeScalarSize(attrib.type.getBasicType());
549         for (var elemNdx = 0; elemNdx < numElements; elemNdx++) {
550             for (var compNdx = 0; compNdx < numComps; compNdx++) {
551                 /** @type {number} */ var offset = attrib.offset + elemNdx * stride + compNdx * elementSize;
552                 if (isFloat) {
553                     var pos = new Float32Array(buffer, offset, 1);
554                     switch (precision) {
555                         case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = 0.25 * rnd.getInt(0, 4); break;
556                         case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getFloat(-1e3, 1e3); break;
557                         case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = rnd.getFloat(-1e5, 1e5); break;
558                         default: throw new Error('Unknown precision: ' + precision);
559                     }
560                 } else if (isInt) {
561                     var pos = new Int32Array(buffer, offset, 1);
562                     switch (precision) {
563                         case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = rnd.getInt(-128, 127); break;
564                         case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getInt(-32768, 32767); break;
565                         case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = rnd.getInt(); break;
566                         default: throw new Error('Unknown precision: ' + precision);
567                     }
568                 } else if (isUint) {
569                     var pos = new Uint32Array(buffer, offset, 1);
570                     switch (precision) {
571                         case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = rnd.getInt(0, 255); break;
572                         case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getInt(0, 65535); break;
573                         case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = Math.abs(rnd.getInt()); break;
574                         default: throw new Error('Unknown precision: ' + precision);
575                     }
576                 }
577             }
578         }
579     };
581     /**
582      * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
583      * @param {number} numInputs
584      * @param {number} inputStride
585      * @param {deRandom.Random} rnd
586      * @return {ArrayBuffer}
587      */
588     es3fTransformFeedbackTests.genInputData = function(attributes, numInputs, inputStride, rnd) {
589         var buffer = new ArrayBuffer(numInputs * inputStride);
591         var position = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_position');
592         if (!position)
593             throw new Error('Position attribute not found.');
595         for (var ndx = 0; ndx < numInputs; ndx++) {
596             var pos = new Float32Array(buffer, position.offset + inputStride * ndx, 4);
597             pos[0] = rnd.getFloat(-1.2, 1.2);
598             pos[1] = rnd.getFloat(-1.2, 1.2);
599             pos[2] = rnd.getFloat(-1.2, 1.2);
600             pos[3] = rnd.getFloat(0.1, 2.0);
601         }
603         var pointSizePos = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_pointSize');
604         if (pointSizePos) {
605             for (var ndx = 0; ndx < numInputs; ndx++) {
606                 var pos = new Float32Array(buffer, pointSizePos.offset + inputStride * ndx, 1);
607                 pos[0] = rnd.getFloat(1, 8);
608             }
609         }
611         // Random data for rest of components.
612         for (var i = 0; i < attributes.length; i++) {
613             if (attributes[i].name != 'a_position' && attributes[i].name != 'a_pointSize')
614                 es3fTransformFeedbackTests.genAttributeData(attributes[i], buffer, inputStride, numInputs, rnd);
615         }
617         return buffer;
618     };
620     /**
621      * Returns the number of outputs with the es3fTransformFeedbackTests.count for the Primitives in the Transform Feedback.
622      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
623      * @param {number} numElements
624      * @return {number}
625      */
626     es3fTransformFeedbackTests.getTransformFeedbackOutputCount = function(primitiveType, numElements) {
628     switch (primitiveType) {
629         case gluDrawUtil.primitiveType.TRIANGLES: return numElements - numElements % 3;
630         case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return Math.max(0, numElements - 2) * 3;
631         case gluDrawUtil.primitiveType.TRIANGLE_FAN: return Math.max(0, numElements - 2) * 3;
632         case gluDrawUtil.primitiveType.LINES: return numElements - numElements % 2;
633         case gluDrawUtil.primitiveType.LINE_STRIP: return Math.max(0, numElements - 1) * 2;
634         case gluDrawUtil.primitiveType.LINE_LOOP: return numElements > 1 ? numElements * 2 : 0;
635         case gluDrawUtil.primitiveType.POINTS: return numElements;
636         default:
637             throw new Error('Unrecognized primitiveType ' + primitiveType);
638        }
640     };
642     /**
643      * Returns a number with the es3fTransformFeedbackTests.count for the Primitives in the Transform Feedback.
644      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
645      * @param {number} numElements
646      * @return {number}
647      */
648     es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount = function(primitiveType, numElements) {
650     switch (primitiveType) {
651         case gluDrawUtil.primitiveType.TRIANGLES: return Math.floor(numElements / 3);
652         case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return Math.max(0, numElements - 2);
653         case gluDrawUtil.primitiveType.TRIANGLE_FAN: return Math.max(0, numElements - 2);
654         case gluDrawUtil.primitiveType.LINES: return Math.floor(numElements / 2);
655         case gluDrawUtil.primitiveType.LINE_STRIP: return Math.max(0, numElements - 1);
656         case gluDrawUtil.primitiveType.LINE_LOOP: return numElements > 1 ? numElements : 0;
657         case gluDrawUtil.primitiveType.POINTS: return numElements;
658         default:
659             throw new Error('Unrecognized primitiveType ' + primitiveType);
660        }
662     };
664     /**
665      * Returns the type of Primitive Mode: Triangles for all Triangle Primitive's type and same for Line and Points.
666      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
667      * @return {number} primitiveType
668      */
669     es3fTransformFeedbackTests.getTransformFeedbackPrimitiveMode = function(primitiveType) {
671     switch (primitiveType) {
672         case gluDrawUtil.primitiveType.TRIANGLES:
673         case gluDrawUtil.primitiveType.TRIANGLE_STRIP:
674         case gluDrawUtil.primitiveType.TRIANGLE_FAN:
675             return gl.TRIANGLES;
677         case gluDrawUtil.primitiveType.LINES:
678         case gluDrawUtil.primitiveType.LINE_STRIP:
679         case gluDrawUtil.primitiveType.LINE_LOOP:
680             return gl.LINES;
682         case gluDrawUtil.primitiveType.POINTS:
683             return gl.POINTS;
685         default:
686             throw new Error('Unrecognized primitiveType ' + primitiveType);
687        }
689     };
691     /**
692      * Returns the attribute index for a certain primitive type.
693      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
694      * @param {number} numInputs
695      * @param {number} outNdx
696      * @return {number}
697      */
698     es3fTransformFeedbackTests.getAttributeIndex = function(primitiveType, numInputs, outNdx) {
700     switch (primitiveType) {
702         case gluDrawUtil.primitiveType.TRIANGLES: return outNdx;
703         case gluDrawUtil.primitiveType.LINES: return outNdx;
704         case gluDrawUtil.primitiveType.POINTS: return outNdx;
706         case gluDrawUtil.primitiveType.TRIANGLE_STRIP: {
707             /** @type {number} */ var triNdx = outNdx / 3;
708             /** @type {number} */ var vtxNdx = outNdx % 3;
709             return (triNdx % 2 != 0 && vtxNdx < 2) ? (triNdx + 1 - vtxNdx) : (triNdx + vtxNdx);
710         }
712         case gluDrawUtil.primitiveType.TRIANGLE_FAN:
713             return (outNdx % 3 != 0) ? (outNdx / 3 + outNdx % 3) : 0;
715         case gluDrawUtil.primitiveType.LINE_STRIP:
716             return outNdx / 2 + outNdx % 2;
718         case gluDrawUtil.primitiveType.LINE_LOOP: {
719             var inNdx = outNdx / 2 + outNdx % 2;
720             return inNdx < numInputs ? inNdx : 0;
721         }
723         default:
724             throw new Error('Unrecognized primitiveType ' + primitiveType);
725        }
727     };
729     /**
730      * @param {gluDrawUtil.primitiveType} primitiveType type number in gluDrawUtil.primitiveType
731      * @param {es3fTransformFeedbackTests.Output} output
732      * @param {number} numInputs
733      * @param {Object} buffers
734      * @return {boolean} isOk
735      */
736     es3fTransformFeedbackTests.compareTransformFeedbackOutput = function(primitiveType, output, numInputs, buffers) {
737         /** @type {boolean} */ var isOk = true;
738         /** @type {number} */ var outOffset = output.offset;
740         for (var attrNdx = 0; attrNdx < output.inputs.length; attrNdx++) {
741         /** @type {es3fTransformFeedbackTests.Attribute} */ var attribute = output.inputs[attrNdx];
742         /** @type {gluShaderUtil.DataType} */ var type = attribute.type.getBasicType();
743         /** @type {number} */ var numComponents = gluShaderUtil.getDataTypeScalarSize(type);
745         /** @type {gluShaderUtil.precision} */ var precision = attribute.type.getPrecision();
747         /** @type {string} */ var scalarType = gluShaderUtil.getDataTypeScalarType(type);
748         /** @type {number} */ var numOutputs = es3fTransformFeedbackTests.getTransformFeedbackOutputCount(primitiveType, numInputs);
750             for (var outNdx = 0; outNdx < numOutputs; outNdx++) {
751             /** @type {number} */ var inNdx = es3fTransformFeedbackTests.getAttributeIndex(primitiveType, numInputs, outNdx);
753                 for (var compNdx = 0; compNdx < numComponents; compNdx++) {
754                 /** @type {boolean} */ var isEqual = false;
756                     if (scalarType === 'float') {
757                         var outBuffer = new Float32Array(buffers.output.buffer, buffers.output.offset + buffers.output.stride * outNdx + outOffset + compNdx * 4, 1);
758                         var inBuffer = new Float32Array(buffers.input.buffer, buffers.input.offset + buffers.input.stride * inNdx + attribute.offset + compNdx * 4, 1);
759                         var difInOut = inBuffer[0] - outBuffer[0];
760                         /* TODO: Original code used ULP comparison for highp and mediump precision. This could cause failures. */
761                         switch (precision) {
762                             case gluShaderUtil.precision.PRECISION_HIGHP: {
763                                 isEqual = Math.abs(difInOut) < 0.1;
764                                 break;
765                             }
767                             case gluShaderUtil.precision.PRECISION_MEDIUMP: {
768                                 isEqual = Math.abs(difInOut) < 0.1;
769                                 break;
770                             }
772                             case gluShaderUtil.precision.PRECISION_LOWP: {
773                                 isEqual = Math.abs(difInOut) < 0.1;
774                                 break;
775                             }
776                             default:
777                                 throw new Error('Unknown precision: ' + precision);
778                         }
779                     } else {
780                         var outBuffer = new Uint32Array(buffers.output.buffer, buffers.output.offset + buffers.output.stride * outNdx + outOffset + compNdx * 4, 1);
781                         var inBuffer = new Uint32Array(buffers.input.buffer, buffers.input.offset + buffers.input.stride * inNdx + attribute.offset + compNdx * 4, 1);
782                         isEqual = (inBuffer[0] == outBuffer[0]); // Bit-exact match required for integer types.
783                     }
785                     if (!isEqual) {
786                         bufferedLogToConsole('Mismatch in ' + output.name + ' (' + attribute.name + '), output = ' + outNdx + ', input = ' + inNdx + ', component = ' + compNdx);
787                         isOk = false;
788                         break;
789                     }
790                 }
792                 if (!isOk)
793                     break;
794             }
796             if (!isOk)
797                 break;
799             outOffset += numComponents * 4; /*sizeof(deUint32)*/
800         }
802         return isOk;
803     };
805     /**
806      * Returns (for all the draw calls) the type of Primitive Mode, as it calls "es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount".
807      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
808      * @param {Array<es3fTransformFeedbackTests.DrawCall>} array Object.<number, boolean>
809      * @return {number} primCount
810      */
811     es3fTransformFeedbackTests.computeTransformFeedbackPrimitiveCount = function(primitiveType, array) {
813     /** @type {number} */ var primCount = 0;
815         for (var i = 0; i < array.length; ++ i) {
817             if (array[i].transformFeedbackEnabled)
818                 primCount += es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount(primitiveType, array[i].numElements);
819         }
821         return primCount;
822     };
824     /**
825      * @param {number} target
826      * @param {number} bufferSize
827      * @param {number} guardSize
828      */
829     es3fTransformFeedbackTests.writeBufferGuard = function(target, bufferSize, guardSize) {
830         var buffer = new ArrayBuffer(guardSize);
831         var view = new Uint8Array(buffer);
832         for (var i = 0; i < guardSize; ++i) view[i] = 0xcd;
833         gl.bufferSubData(target, bufferSize, buffer);
834     };
836     /**
837      * Verifies guard
838      * @param {ArrayBuffer} buffer
839      * @param {number} start
840      * @return {boolean}
841      */
842     es3fTransformFeedbackTests.verifyGuard = function(buffer, start) {
843         start = start || 0;
844         var view = new Uint8Array(buffer, start);
845         for (var i = 0; i < view.length; i++) {
846             if (view[i] != 0xcd)
847                 return false;
848         }
849         return true;
850     };
852     /**
853      * @extends {tcuTestCase.DeqpTest}
854      * @param {string} name
855      * @param {string} desc
856      * @param {number} bufferMode
857      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
858      * @constructor
859      */
860     es3fTransformFeedbackTests.TransformFeedbackCase = function(name, desc, bufferMode, primitiveType) {
861         tcuTestCase.DeqpTest.call(this, name, desc);
862         this.m_bufferMode = bufferMode;
863         this.m_primitiveType = primitiveType;
864         this.m_progSpec = new es3fTransformFeedbackTests.ProgramSpec();
866         // Derived from es3fTransformFeedbackTests.ProgramSpec in es3fTransformFeedbackTests.init()
867         this.m_inputStride = 0;
868         this.m_attributes = []; // vector<es3fTransformFeedbackTests.Attribute>
869         this.m_transformFeedbackOutputs = []; // vector<es3fTransformFeedbackTests.Output>
870         this.m_bufferStrides = []; // vector<int>
872         // GL state.
873         this.m_program = null; // glu::ShaderProgram
874         this.m_transformFeedback = null; // glu::TransformFeedback
875         this.m_outputBuffers = []; // vector<deUint32>
877         this.m_iterNdx = 0; // int
878         this.m_testPassed = true;
879         // State machine
880         this.m_state = es3fTransformFeedbackTests.State.DRAW;
881         this.m_verifyStart = null;
883         this.m_frameWithTf = null;
884         this.m_frameWithoutTf = null;
886         this.m_viewportW = 0;
887         this.m_viewportH = 0;
888         this.m_viewportX = 0;
889         this.m_viewportY = 0;
891         this.m_primitiveQuery = null;
892         this.m_outputsOk = true;
894     };
896     setParentClass(es3fTransformFeedbackTests.TransformFeedbackCase, tcuTestCase.DeqpTest);
898     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.createVerificationResult = function(retry, result) {
899         return { retry: retry, result: result };
900     }
902     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.dumpShaderText = function() {
903         var dbgext = gl.getExtension('WEBGL_debug_shaders');
904         for (var ii = 0; ii < this.m_program.shaders.length; ++ii) {
905             debug('Shader source ' + ii + ' before translation:')
906             debug(this.m_program.shaders[ii].info.source);
907             debug('');
908             debug('Shader source ' + ii + ' after translation:');
909             debug(dbgext.getTranslatedShaderSource(this.m_program.shaders[ii].shader));
910         }
911     };
913     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.init = function() {
914         this.m_program = es3fTransformFeedbackTests.createVertexCaptureProgram(
915             this.m_progSpec,
916             this.m_bufferMode,
917             this.m_primitiveType
918         );
920         if (!this.m_program.isOk()) {
921             // this.dumpShaderText();
923             var linkFail = this.m_program.shadersOK &&
924                            !this.m_program.getProgramInfo().linkOk;
926             if (linkFail) {
927                 if (!es3fTransformFeedbackTests.isProgramSupported(this.m_progSpec, this.m_bufferMode)) {
928                     var msg = 'Not Supported. Implementation limits exceeded.';
929                     checkMessage(false, msg);
930                     throw new TestFailedException(msg);
931                 } else if (es3fTransformFeedbackTests.hasArraysInTFVaryings(this.m_progSpec)) {
932                     msg = 'Capturing arrays is not supported (undefined in specification)';
933                     checkMessage(false, msg);
934                     throw new TestFailedException(msg);
935                 } else {
936                     throw new Error('Link failed: ' + this.m_program.getProgramInfo().infoLog);
937                 }
938             } else {
939                 throw new Error('Compile failed');
940             }
941         } else {
942             // debug('Program is ' +
943             //       (gl.getProgramParameter(this.m_program.getProgram(), gl.LINK_STATUS) ? 'linked' : 'not linked'));
944             // this.dumpShaderText();
945         }
947 //          bufferedLogToConsole('Transform feedback varyings: ' + tcu.formatArray(this.m_progSpec.getTransformFeedbackVaryings()));
948         bufferedLogToConsole('Transform feedback varyings: ' + this.m_progSpec.getTransformFeedbackVaryings());
950         // Print out transform feedback points reported by GL.
951         // bufferedLogToConsole('Transform feedback varyings reported by compiler:');
952         //logTransformFeedbackVaryings(log, gl, this.m_program.getProgram());
954         // Compute input specification.
955         this.m_inputStride = es3fTransformFeedbackTests.computeInputLayout(this.m_attributes, this.m_progSpec.getVaryings(), this.m_progSpec.isPointSizeUsed());
957         // Build list of varyings used in transform feedback.
958         es3fTransformFeedbackTests.computeTransformFeedbackOutputs(
959             this.m_transformFeedbackOutputs,
960             this.m_attributes,
961             this.m_progSpec.getVaryings(),
962             this.m_progSpec.getTransformFeedbackVaryings(),
963             this.m_bufferMode
964         );
965         if (!this.m_transformFeedbackOutputs.length) {
966             throw new Error('transformFeedbackOutputs cannot be empty.');
967         }
969         if (this.m_bufferMode == gl.SEPARATE_ATTRIBS) {
970             for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
971                 this.m_bufferStrides.push(this.m_transformFeedbackOutputs[i].type.getScalarSize() * 4 /*sizeof(deUint32)*/);
972             }
973         } else {
974             var totalSize = 0;
975             for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
976                 totalSize += this.m_transformFeedbackOutputs[i].type.getScalarSize() * 4 /*sizeof(deUint32)*/;
977             }
978             this.m_bufferStrides.push(totalSize);
979         }
981         this.m_outputBuffers.length = this.m_bufferStrides.length;
982         for (var i = 0; i < this.m_outputBuffers.length; i++)
983             this.m_outputBuffers[i] = gl.createBuffer();
985         this.m_transformFeedback = gl.createTransformFeedback();
987         this.m_iterNdx = 0;
988 //          this.m_testCtx.setTestResult(QP_TEST_RESULT_PASS, 'Pass');
990     };
992     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.deinit = function() {
993         for (var i = 0; i < this.m_outputBuffers.length; i++)
994             gl.deleteBuffer(this.m_outputBuffers[i]);
996     //    delete this.m_transformFeedback;
997         this.m_transformFeedback = null;
999     //    delete this.m_program;
1000         this.m_program = null;
1002         // Clean up state.
1003         this.m_attributes = [];
1004         this.m_transformFeedbackOutputs = [];
1005         this.m_bufferStrides = [];
1006         this.m_inputStride = 0;
1008     };
1010     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.iterate = function() {
1011         var s = es3fTransformFeedbackTests.TransformFeedbackCase.s_iterate;
1012         var numIterations = s.iterations.length;
1013         var seed = deMath.deMathHash(this.m_iterNdx);
1014         switch(this.m_state) {
1015             case es3fTransformFeedbackTests.State.DRAW:
1016                 bufferedLogToConsole('Testing ' +
1017                     s.testCases[s.iterations[this.m_iterNdx]].length +
1018                     ' draw calls, (element es3fTransformFeedbackTests.count, TF state): ' +
1019                     s.testCases[s.iterations[this.m_iterNdx]]
1020                 );
1021                 this.draw(s.testCases[s.iterations[this.m_iterNdx]], seed);
1022                 this.m_state = es3fTransformFeedbackTests.State.VERIFY;
1023                 break;
1024             case es3fTransformFeedbackTests.State.VERIFY:
1025                 var verifyResult = this.verify(s.testCases[s.iterations[this.m_iterNdx]]);
1026                 if (verifyResult.retry) {
1027                     break;
1028                 }
1029                 this.m_testPassed = verifyResult.result;
1030                 this.m_iterNdx += 1;
1031                 if (this.m_testPassed && this.m_iterNdx < numIterations) {
1032                     this.m_state = es3fTransformFeedbackTests.State.DRAW;
1033                     break;
1034                 }
1035                 // Fall through
1036             case es3fTransformFeedbackTests.State.FINISH:
1037                 if (!this.m_testPassed) testFailedOptions('Result comparison failed for iteration ' + s.iterations[this.m_iterNdx - 1], false);
1038                 else testPassedOptions('Result comparison succeeded', true);
1039                 return tcuTestCase.IterateResult.STOP;
1040         }
1042         return tcuTestCase.IterateResult.CONTINUE;
1044     };
1046     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.draw = function(calls, seed) {
1047         var _min = function(x, y) { return x < y ? x : y; };
1049         var rnd = new deRandom.Random(seed);
1050         var numInputs = 0;
1051         var numOutputs = 0;
1052         var width = gl.drawingBufferWidth;
1053         var height = gl.drawingBufferHeight;
1054         this.m_viewportW = _min(es3fTransformFeedbackTests.VIEWPORT_WIDTH, width);
1055         this.m_viewportH = _min(es3fTransformFeedbackTests.VIEWPORT_HEIGHT, height);
1056         this.m_viewportX = rnd.getInt(0, width - this.m_viewportW);
1057         this.m_viewportY = rnd.getInt(0, height - this.m_viewportH);
1058         this.m_frameWithTf = new tcuSurface.Surface(this.m_viewportW, this.m_viewportH); // tcu::Surface
1059         this.m_frameWithoutTf = new tcuSurface.Surface(this.m_viewportW, this.m_viewportH); // tcu::Surface
1060         this.m_primitiveQuery = gl.createQuery();
1061         this.m_outputsOk = true;
1063         // Compute totals.
1064         for (var i = 0; i < calls.length; ++i) {
1065             var call = calls[i];
1066             numInputs += call.numElements;
1067             numOutputs += call.transformFeedbackEnabled ? es3fTransformFeedbackTests.getTransformFeedbackOutputCount(this.m_primitiveType, call.numElements) : 0;
1068         }
1070         // Input data.
1071         var inputData = es3fTransformFeedbackTests.genInputData(this.m_attributes, numInputs, this.m_inputStride, rnd);
1073         gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, this.m_transformFeedback);
1075         // Allocate storage for transform feedback output buffers and bind to targets.
1076         for (var bufNdx = 0; bufNdx < this.m_outputBuffers.length; ++bufNdx) {
1077             var buffer = this.m_outputBuffers[bufNdx]; // deUint32
1078             var stride = this.m_bufferStrides[bufNdx]; // int
1079             var target = bufNdx; // int
1080             var size = stride * numOutputs; // int
1081             var guardSize = stride * es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER; // int
1082             var usage = gl.DYNAMIC_READ; // const deUint32
1084             gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
1085             gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, size + guardSize, usage);
1086             es3fTransformFeedbackTests.writeBufferGuard(gl.TRANSFORM_FEEDBACK_BUFFER, size, guardSize);
1088             // \todo [2012-07-30 pyry] glBindBufferRange()?
1089             gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, target, buffer);
1090         }
1092         var attribBuffer = gl.createBuffer();
1093         gl.bindBuffer(gl.ARRAY_BUFFER, attribBuffer);
1094         gl.bufferData(gl.ARRAY_BUFFER, inputData, gl.STATIC_DRAW);
1096         // Setup attributes.
1097         for (var i = 0; i < this.m_attributes.length; ++i) {
1098             var attrib = this.m_attributes[i];
1099             var loc = gl.getAttribLocation(this.m_program.getProgram(), attrib.name);
1100             /** @type {string} */
1101             var scalarType = gluShaderUtil.getDataTypeScalarType(attrib.type.getBasicType());
1102             /** @type {number} */
1103             var numComponents = gluShaderUtil.getDataTypeScalarSize(attrib.type.getBasicType());
1105             if (loc >= 0) {
1106                 gl.enableVertexAttribArray(loc);
1107                 switch (scalarType) {
1108                     case 'float':
1109                         gl.vertexAttribPointer(loc, numComponents, gl.FLOAT, false, this.m_inputStride, attrib.offset); break;
1110                     case 'int':
1111                         gl.vertexAttribIPointer(loc, numComponents, gl.INT, this.m_inputStride, attrib.offset); break;
1112                     case 'uint':
1113                         gl.vertexAttribIPointer(loc, numComponents, gl.UNSIGNED_INT, this.m_inputStride, attrib.offset); break;
1114                 }
1115             }
1116         }
1118         // Setup viewport.
1119         gl.viewport(this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH);
1121         // Setup program.
1122         gl.useProgram(this.m_program.getProgram());
1124         gl.uniform4fv(
1125             gl.getUniformLocation(this.m_program.getProgram(), 'u_scale'),
1126             [0.01, 0.01, 0.01, 0.01]
1127         );
1128         gl.uniform4fv(
1129             gl.getUniformLocation(this.m_program.getProgram(), 'u_bias'),
1130             [0.5, 0.5, 0.5, 0.5]
1131         );
1133         // Enable query.
1134         gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, this.m_primitiveQuery);
1136         // Draw
1137         var offset = 0;
1138         var tfEnabled = true;
1140         gl.clear(gl.COLOR_BUFFER_BIT);
1142         var tfPrimitiveMode = es3fTransformFeedbackTests.getTransformFeedbackPrimitiveMode(this.m_primitiveType);
1143         gl.beginTransformFeedback(tfPrimitiveMode);
1145         for (var i = 0; i < calls.length; ++i) {
1146             var call = calls[i];
1148             // Pause or resume transform feedback if necessary.
1149             if (call.transformFeedbackEnabled != tfEnabled) {
1150                 if (call.transformFeedbackEnabled)
1151                     gl.resumeTransformFeedback();
1152                 else
1153                     gl.pauseTransformFeedback();
1154                 tfEnabled = call.transformFeedbackEnabled;
1155             }
1157             gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, this.m_primitiveType), offset, call.numElements);
1158             offset += call.numElements;
1159         }
1161         // Resume feedback before finishing it.
1162         if (!tfEnabled)
1163             gl.resumeTransformFeedback();
1165         gl.endTransformFeedback();
1167         gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
1169         // Check and log query status right after submit
1170         var query = this.m_primitiveQuery;
1172         var available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
1174         if (available) {
1175             this.m_testPassed = false;
1176             this.m_state = es3fTransformFeedbackTests.State.FINISH;
1177             testFailedOptions('Transform feedback query result must not be available the same frame as they are issued.', true);
1178         }
1180         // Compare result buffers.
1181         for (var bufferNdx = 0; bufferNdx < this.m_outputBuffers.length; ++bufferNdx) {
1182             var stride = this.m_bufferStrides[bufferNdx]; // int
1183             var size = stride * numOutputs; // int
1184             var guardSize = stride * es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER; // int
1185             var buffer = new ArrayBuffer(size + guardSize); // const void*
1187             // Bind buffer for reading.
1188             gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, this.m_outputBuffers[bufferNdx]);
1190             gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, new Uint8Array(buffer));
1192             // Verify all output variables that are written to this buffer.
1193             for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
1194                 var out = this.m_transformFeedbackOutputs[i];
1196                 if (out.bufferNdx != bufferNdx)
1197                     continue;
1199                 var inputOffset = 0;
1200                 var outputOffset = 0;
1202                 // Process all draw calls and check ones with transform feedback enabled
1203                 for (var callNdx = 0; callNdx < calls.length; ++callNdx) {
1204                     var call = calls[callNdx];
1206                     if (call.transformFeedbackEnabled) {
1207                         var inputPtr = inputData[0] + inputOffset * this.m_inputStride; // const deUint8*
1208                         var outputPtr = outputOffset * stride; // const deUint8*
1210                         if (!es3fTransformFeedbackTests.compareTransformFeedbackOutput(this.m_primitiveType, out, call.numElements, {
1211                                  input: {
1212                                     buffer: inputData,
1213                                     offset: inputOffset * this.m_inputStride,
1214                                     stride: this.m_inputStride
1215                                 },
1216                                 output: {
1217                                     buffer: buffer,
1218                                     offset: outputOffset * stride,
1219                                     stride: stride
1220                                 }
1221                             })) {
1222                             this.m_outputsOk = false;
1223                             break;
1224                         }
1225                     }
1227                     inputOffset += call.numElements;
1228                     outputOffset += call.transformFeedbackEnabled ? es3fTransformFeedbackTests.getTransformFeedbackOutputCount(this.m_primitiveType, call.numElements) : 0;
1229                 }
1230             }
1232             // Verify guardband.
1233             if (!es3fTransformFeedbackTests.verifyGuard(buffer, size)) {
1234                 bufferedLogToConsole('Error: Transform feedback buffer overrun detected');
1235                 this.m_outputsOk = false;
1236             }
1237         }
1238     };
1240     es3fTransformFeedbackTests.TransformFeedbackCase.prototype.verify = function(calls) {
1241         // Check status after mapping buffers.
1242         var mustBeReady = this.m_outputBuffers.length > 0; // Mapping buffer forces synchronization. // const bool
1243         var expectedCount = es3fTransformFeedbackTests.computeTransformFeedbackPrimitiveCount(this.m_primitiveType, calls); // const int
1244         var available = /** @type {boolean} */ (gl.getQueryParameter(this.m_primitiveQuery, gl.QUERY_RESULT_AVAILABLE));
1245         var verify_offset = 0;
1246         var queryOk = true;
1247         if (!available) {
1248             if (!this.m_verifyStart)
1249                 this.m_verifyStart = new Date();
1250             else {
1251                 var current = new Date();
1252                 var elapsedTime = 0.001 * (current.getTime() - this.m_verifyStart.getTime());
1253                 if (elapsedTime > es3fTransformFeedbackTests.MAX_VERIFY_WAIT) {
1254                     testFailed('Query result not available after ' + elapsedTime + ' seconds.');
1255                     this.m_state = es3fTransformFeedbackTests.State.FINISH;
1256                     return this.createVerificationResult(false, false);
1257                 }
1258             }
1259             return this.createVerificationResult(true, false);
1260         }
1262         var numPrimitives = /** @type {number} */ (gl.getQueryParameter(this.m_primitiveQuery, gl.QUERY_RESULT));
1264         if (!mustBeReady && available == false)
1265             bufferedLogToConsole('ERROR: gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN result not available after mapping buffers!');
1267         bufferedLogToConsole('gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = ' + numPrimitives);
1269         if (numPrimitives != expectedCount) {
1270             queryOk = false;
1271             bufferedLogToConsole('ERROR: Expected ' + expectedCount + ' primitives!');
1272         }
1274         // Clear transform feedback state.
1275         gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
1276         for (var bufNdx = 0; bufNdx < this.m_outputBuffers.length; ++bufNdx) {
1277             gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
1278             gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, bufNdx, null);
1279         }
1281         gl.bindBuffer(gl.ARRAY_BUFFER, null);
1283         // Read back rendered image.
1284         this.m_frameWithTf.readViewport(gl, [this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH]);
1286         // Render without transform feedback.
1288         gl.clear(gl.COLOR_BUFFER_BIT);
1290         for (var i = 0; i < calls.length; ++i) {
1291             var call = calls[i];
1292             gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, this.m_primitiveType), verify_offset, call.numElements);
1293             verify_offset += call.numElements;
1294         }
1295         this.m_frameWithoutTf.readViewport(gl, [this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH]);
1297         // Compare images with and without transform feedback.
1298         var imagesOk = tcuImageCompare.pixelThresholdCompare('Result', 'Image comparison result', this.m_frameWithoutTf, this.m_frameWithTf, [1, 1, 1, 1], tcuImageCompare.CompareLogMode.ON_ERROR);
1300         if (imagesOk)
1301             bufferedLogToConsole('Rendering result comparison between TF enabled and TF disabled passed.');
1302         else
1303             bufferedLogToConsole('ERROR: Rendering result comparison between TF enabled and TF disabled failed!');
1305         return this.createVerificationResult(false, this.m_outputsOk && imagesOk && queryOk);
1307     };
1309     es3fTransformFeedbackTests.dc = function(numElements, tfEnabled) {
1310         return new es3fTransformFeedbackTests.DrawCall(numElements, tfEnabled);
1311     };
1313     // static data
1314     es3fTransformFeedbackTests.TransformFeedbackCase.s_iterate = {
1316         testCases: {
1317             elemCount1: [es3fTransformFeedbackTests.dc(1, true)],
1318             elemCount2: [es3fTransformFeedbackTests.dc(2, true)],
1319             elemCount3: [es3fTransformFeedbackTests.dc(3, true)],
1320             elemCount4: [es3fTransformFeedbackTests.dc(4, true)],
1321             elemCount123: [es3fTransformFeedbackTests.dc(123, true)],
1322             basicPause1: [es3fTransformFeedbackTests.dc(64, true), es3fTransformFeedbackTests.dc(64, false), es3fTransformFeedbackTests.dc(64, true)],
1323             basicPause2: [es3fTransformFeedbackTests.dc(13, true), es3fTransformFeedbackTests.dc(5, true), es3fTransformFeedbackTests.dc(17, false),
1324                            es3fTransformFeedbackTests.dc(3, true), es3fTransformFeedbackTests.dc(7, false)],
1325             startPaused: [es3fTransformFeedbackTests.dc(123, false), es3fTransformFeedbackTests.dc(123, true)],
1326             random1: [es3fTransformFeedbackTests.dc(65, true), es3fTransformFeedbackTests.dc(135, false), es3fTransformFeedbackTests.dc(74, true),
1327                            es3fTransformFeedbackTests.dc(16, false), es3fTransformFeedbackTests.dc(226, false), es3fTransformFeedbackTests.dc(9, true),
1328                            es3fTransformFeedbackTests.dc(174, false)],
1329             random2: [es3fTransformFeedbackTests.dc(217, true), es3fTransformFeedbackTests.dc(171, true), es3fTransformFeedbackTests.dc(147, true),
1330                            es3fTransformFeedbackTests.dc(152, false), es3fTransformFeedbackTests.dc(55, true)]
1331         },
1332         iterations: [
1333             'elemCount1', 'elemCount2', 'elemCount3', 'elemCount4', 'elemCount123',
1334             'basicPause1', 'basicPause2', 'startPaused',
1335             'random1', 'random2'
1336         ]
1337     };
1339     es3fTransformFeedbackTests.hasArraysInTFVaryings = function(spec) {
1341         for (var i = 0; i < spec.getTransformFeedbackVaryings().length; ++i) {
1342             var tfVar = spec.getTransformFeedbackVaryings()[i];
1343             var varName = gluVarTypeUtil.parseVariableName(tfVar);
1345         var attr = es3fTransformFeedbackTests.findAttributeNameEquals(spec.getVaryings(), varName);
1346         if (attr && attr.type.isArrayType())
1347                 return true;
1348         }
1349         return false;
1351     };
1353     /** es3fTransformFeedbackTests.PositionCase
1354      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1355      * @param {string} name
1356      * @param {string} desc
1357      * @param {number} bufferMode
1358      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1359      * @constructor
1360      */
1361     es3fTransformFeedbackTests.PositionCase = function(name, desc, bufferMode, primitiveType) {
1362         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1363         this.m_progSpec.addTransformFeedbackVarying('gl_Position');
1364     };
1366     setParentClass(es3fTransformFeedbackTests.PositionCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1368     /** es3fTransformFeedbackTests.PointSizeCase
1369      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1370      * @param {string} name
1371      * @param {string} desc
1372      * @param {number} bufferMode
1373      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1374      * @constructor
1375      */
1376     es3fTransformFeedbackTests.PointSizeCase = function(name, desc, bufferMode, primitiveType) {
1377         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1378         this.m_progSpec.addTransformFeedbackVarying('gl_PointSize');
1380     };
1382     setParentClass(es3fTransformFeedbackTests.PointSizeCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1384     /** es3fTransformFeedbackTests.BasicTypeCase
1385      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1386      * @param {string} name
1387      * @param {string} desc
1388      * @param {number} bufferMode
1389      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1390      * @param {gluShaderUtil.DataType} type
1391      * @param {gluShaderUtil.precision} precision
1392      * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
1393      * @constructor
1394      */
1395     es3fTransformFeedbackTests.BasicTypeCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
1396         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1398         this.m_progSpec.addVarying('v_varA', gluVarType.newTypeBasic(type, precision), interpolation);
1399         this.m_progSpec.addVarying('v_varB', gluVarType.newTypeBasic(type, precision), interpolation);
1401         this.m_progSpec.addTransformFeedbackVarying('v_varA');
1402         this.m_progSpec.addTransformFeedbackVarying('v_varB');
1404     };
1406     setParentClass(es3fTransformFeedbackTests.BasicTypeCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1408     /** es3fTransformFeedbackTests.BasicArrayCase
1409      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1410      * @param {string} name
1411      * @param {string} desc
1412      * @param {number} bufferMode
1413      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1414      * @param {gluShaderUtil.DataType} type
1415      * @param {gluShaderUtil.precision} precision
1416      * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
1417      * @constructor
1418      */
1419     es3fTransformFeedbackTests.BasicArrayCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
1420         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1422         if (gluShaderUtil.isDataTypeMatrix(type) || this.m_bufferMode === gl.SEPARATE_ATTRIBS) {
1423             // note For matrix types we need to use reduced array sizes or otherwise we will exceed maximum attribute (16)
1424             // or transform feedback component es3fTransformFeedbackTests.count (64).
1425             // On separate attribs mode maximum component es3fTransformFeedbackTests.count per varying is 4.
1426             this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 1), interpolation);
1427             this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 2), interpolation);
1428         } else {
1429             this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 3), interpolation);
1430             this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 4), interpolation);
1431         }
1433         this.m_progSpec.addTransformFeedbackVarying('v_varA');
1434         this.m_progSpec.addTransformFeedbackVarying('v_varB');
1436     };
1438     setParentClass(es3fTransformFeedbackTests.BasicArrayCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1440     /** es3fTransformFeedbackTests.ArrayElementCase
1441      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1442      * @param {string} name
1443      * @param {string} desc
1444      * @param {number} bufferMode
1445      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1446      * @param {gluShaderUtil.DataType} type
1447      * @param {gluShaderUtil.precision} precision
1448      * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
1449      * @constructor
1450      */
1451     es3fTransformFeedbackTests.ArrayElementCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
1453         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1455         this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 3), interpolation);
1456         this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 4), interpolation);
1458         this.m_progSpec.addTransformFeedbackVarying('v_varA[1]');
1459         this.m_progSpec.addTransformFeedbackVarying('v_varB[0]');
1460         this.m_progSpec.addTransformFeedbackVarying('v_varB[3]');
1462     };
1464     setParentClass(es3fTransformFeedbackTests.ArrayElementCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1466     /** es3fTransformFeedbackTests.RandomCase
1467      * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
1468      * @param {string} name
1469      * @param {string} desc
1470      * @param {number} bufferMode
1471      * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
1472      * @param {number} seed
1473      * @constructor
1474      */
1475     es3fTransformFeedbackTests.RandomCase = function(name, desc, bufferMode, primitiveType, seed) {
1476         es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
1478     };
1480     setParentClass(es3fTransformFeedbackTests.RandomCase, es3fTransformFeedbackTests.TransformFeedbackCase);
1482     es3fTransformFeedbackTests.RandomCase.prototype.init = function() {
1484         /** @type {number} */
1485         var seed = /*deString.deStringHash(getName()) ^ */ deMath.deMathHash(this.m_iterNdx);
1487         /** @type {Array<gluShaderUtil.DataType>} */
1488         var typeCandidates = [
1489             gluShaderUtil.DataType.FLOAT,
1490             gluShaderUtil.DataType.FLOAT_VEC2,
1491             gluShaderUtil.DataType.FLOAT_VEC3,
1492             gluShaderUtil.DataType.FLOAT_VEC4,
1493             gluShaderUtil.DataType.INT,
1494             gluShaderUtil.DataType.INT_VEC2,
1495             gluShaderUtil.DataType.INT_VEC3,
1496             gluShaderUtil.DataType.INT_VEC4,
1497             gluShaderUtil.DataType.UINT,
1498             gluShaderUtil.DataType.UINT_VEC2,
1499             gluShaderUtil.DataType.UINT_VEC3,
1500             gluShaderUtil.DataType.UINT_VEC4,
1502             gluShaderUtil.DataType.FLOAT_MAT2,
1503             gluShaderUtil.DataType.FLOAT_MAT2X3,
1504             gluShaderUtil.DataType.FLOAT_MAT2X4,
1506             gluShaderUtil.DataType.FLOAT_MAT3X2,
1507             gluShaderUtil.DataType.FLOAT_MAT3,
1508             gluShaderUtil.DataType.FLOAT_MAT3X4,
1510             gluShaderUtil.DataType.FLOAT_MAT4X2,
1511             gluShaderUtil.DataType.FLOAT_MAT4X3,
1512             gluShaderUtil.DataType.FLOAT_MAT4
1513         ];
1515         /** @type {Array<gluShaderUtil.precision>} */
1516         var precisions = [
1517             gluShaderUtil.precision.PRECISION_LOWP,
1518             gluShaderUtil.precision.PRECISION_MEDIUMP,
1519             gluShaderUtil.precision.PRECISION_HIGHP
1520         ];
1522         var interpModes = [{name: 'smooth', interp: es3fTransformFeedbackTests.interpolation.SMOOTH}, {name: 'flat', interp: es3fTransformFeedbackTests.interpolation.FLAT}, {name: 'centroid', interp: es3fTransformFeedbackTests.interpolation.CENTROID}
1523         ];
1525         /** @type {number} */ var maxAttributeVectors = 16;
1526        //** @type {number} */  var maxTransformFeedbackComponents = 64; // note It is enough to limit attribute set size.
1527         /** @type {boolean} */ var isSeparateMode = (this.m_bufferMode === gl.SEPARATE_ATTRIBS);
1528         /** @type {number} */ var maxTransformFeedbackVars = isSeparateMode ? 4 : maxAttributeVectors;
1529         /** @type {number} */ var arrayWeight = 0.3;
1530         /** @type {number} */ var positionWeight = 0.7;
1531         /** @type {number} */ var pointSizeWeight = 0.1;
1532         /** @type {number} */ var captureFullArrayWeight = 0.5;
1534         /** @type {deRandom.Random} */
1535                                var rnd = new deRandom.Random(seed);
1536         /** @type {boolean} */ var usePosition = rnd.getFloat() < positionWeight;
1537         /** @type {boolean} */ var usePointSize = rnd.getFloat() < pointSizeWeight;
1538         /** @type {number} */ var numAttribVectorsToUse = rnd.getInt(
1539             1, maxAttributeVectors - 1/*position*/ - (usePointSize ? 1 : 0)
1540         );
1542         /** @type {number} */ var numAttributeVectors = 0;
1543         /** @type {number} */ var varNdx = 0;
1545         // Generate varyings.
1546         while (numAttributeVectors < numAttribVectorsToUse) {
1547             /** @type {number} */
1548             var maxVecs = isSeparateMode ? Math.min(2 /*at most 2*mat2*/, numAttribVectorsToUse - numAttributeVectors) : numAttribVectorsToUse - numAttributeVectors;
1549             /** @type {gluShaderUtil.DataType} */
1550             var begin = typeCandidates[0];
1551             /** @type {number} */
1552             var endCandidates = begin + (
1553                 maxVecs >= 4 ? 21 : (
1554                     maxVecs >= 3 ? 18 : (
1555                         maxVecs >= 2 ? (isSeparateMode ? 13 : 15) : 12
1556                     )
1557                 )
1558             );
1559             /** @type {gluShaderUtil.DataType} */
1560             var end = typeCandidates[endCandidates];
1562             /** @type {gluShaderUtil.DataType} */
1563             var type = rnd.choose(typeCandidates)[0];
1565             /** @type {gluShaderUtil.precision} */
1566             var precision = rnd.choose(precisions)[0];
1568             /** @type {es3fTransformFeedbackTests.interpolation} */
1569             var interp = (type === gluShaderUtil.DataType.FLOAT) ?
1570                        rnd.choose(interpModes)[0].interp :
1571                        es3fTransformFeedbackTests.interpolation.FLAT;
1573             /** @type {number} */
1574             var numVecs = gluShaderUtil.isDataTypeMatrix(type) ? gluShaderUtil.getDataTypeMatrixNumColumns(type) : 1;
1575             /** @type {number} */
1576             var numComps = gluShaderUtil.getDataTypeScalarSize(type);
1577             /** @type {number} */
1578             var maxArrayLen = Math.max(1, isSeparateMode ? (4 / numComps) : (maxVecs / numVecs));
1579             /** @type {boolean} */
1580             var useArray = rnd.getFloat() < arrayWeight;
1581             /** @type {number} */
1582             var arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 1;
1583             /** @type {string} */
1584             var name = 'v_var' + varNdx;
1586             if (useArray)
1587                 this.m_progSpec.addVarying(name, gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), arrayLen), interp);
1588             else
1589                 this.m_progSpec.addVarying(name, gluVarType.newTypeBasic(type, precision), interp);
1591             numAttributeVectors += arrayLen * numVecs;
1592             varNdx += 1;
1593         }
1595         // Generate transform feedback candidate set.
1596         /** @type {Array<string>} */ var tfCandidates = [];
1598         if (usePosition) tfCandidates.push('gl_Position');
1599         if (usePointSize) tfCandidates.push('gl_PointSize');
1601         for (var ndx = 0; ndx < varNdx; ndx++) {
1602             /** @type {es3fTransformFeedbackTests.Varying} */
1603             var varying = this.m_progSpec.getVaryings()[ndx];
1605             if (varying.type.isArrayType()) {
1606                 /** @type {boolean} */
1607                 var captureFull = rnd.getFloat() < captureFullArrayWeight;
1609                 if (captureFull) {
1610                     tfCandidates.push(varying.name);
1611                 } else {
1612                     /** @type {number} */
1613                     var numElem = varying.type.getArraySize();
1614                     for (var elemNdx = 0; elemNdx < numElem; elemNdx++)
1615                         tfCandidates.push(varying.name + '[' + elemNdx + ']');
1616                 }
1617             } else
1618                 tfCandidates.push(varying.name);
1619         }
1621         // Pick random selection.
1622         var tfVaryings = [];
1623         rnd.choose(tfCandidates, tfVaryings, Math.min(tfCandidates.length, maxTransformFeedbackVars));
1624         rnd.shuffle(tfVaryings);
1625         for (var i = 0; i < tfVaryings.length; i++)
1626             this.m_progSpec.addTransformFeedbackVarying(tfVaryings[i]);
1628         es3fTransformFeedbackTests.TransformFeedbackCase.prototype.init.call(this);
1630     };
1632     /**
1633      * Creates the test in order to be executed
1634     **/
1635     es3fTransformFeedbackTests.init = function() {
1637         /** @const @type {tcuTestCase.DeqpTest} */
1638         var testGroup = tcuTestCase.runner.testCases;
1640         var bufferModes = [{name: 'separate', mode: gl.SEPARATE_ATTRIBS}, {name: 'interleaved', mode: gl.INTERLEAVED_ATTRIBS}
1641         ];
1643         var primitiveTypes = [{name: 'points', type: gluDrawUtil.primitiveType.POINTS}, {name: 'lines', type: gluDrawUtil.primitiveType.LINES}, {name: 'triangles', type: gluDrawUtil.primitiveType.TRIANGLES}
1644         ];
1646         /** @type {Array<gluShaderUtil.DataType>} */
1647         var basicTypes = [
1648             gluShaderUtil.DataType.FLOAT,
1649             gluShaderUtil.DataType.FLOAT_VEC2,
1650             gluShaderUtil.DataType.FLOAT_VEC3,
1651             gluShaderUtil.DataType.FLOAT_VEC4,
1652             gluShaderUtil.DataType.FLOAT_MAT2,
1653             gluShaderUtil.DataType.FLOAT_MAT2X3,
1654             gluShaderUtil.DataType.FLOAT_MAT2X4,
1655             gluShaderUtil.DataType.FLOAT_MAT3X2,
1656             gluShaderUtil.DataType.FLOAT_MAT3,
1657             gluShaderUtil.DataType.FLOAT_MAT3X4,
1658             gluShaderUtil.DataType.FLOAT_MAT4X2,
1659             gluShaderUtil.DataType.FLOAT_MAT4X3,
1660             gluShaderUtil.DataType.FLOAT_MAT4,
1661             gluShaderUtil.DataType.INT,
1662             gluShaderUtil.DataType.INT_VEC2,
1663             gluShaderUtil.DataType.INT_VEC3,
1664             gluShaderUtil.DataType.INT_VEC4,
1665             gluShaderUtil.DataType.UINT,
1666             gluShaderUtil.DataType.UINT_VEC2,
1667             gluShaderUtil.DataType.UINT_VEC3,
1668             gluShaderUtil.DataType.UINT_VEC4
1669         ];
1671         /** @type {Array<gluShaderUtil.precision>} */
1672         var precisions = [
1674             gluShaderUtil.precision.PRECISION_LOWP,
1675             gluShaderUtil.precision.PRECISION_MEDIUMP,
1676             gluShaderUtil.precision.PRECISION_HIGHP
1678             // glsUBC.UniformFlags.PRECISION_LOW,
1679             // glsUBC.UniformFlags.PRECISION_MEDIUM,
1680             // glsUBC.UniformFlags.PRECISION_HIGH
1681         ];
1683         var interpModes = [{name: 'smooth', interp: es3fTransformFeedbackTests.interpolation.SMOOTH}, {name: 'flat', interp: es3fTransformFeedbackTests.interpolation.FLAT}, {name: 'centroid', interp: es3fTransformFeedbackTests.interpolation.CENTROID}
1684         ];
1686         // .position
1687         /** @type {tcuTestCase.DeqpTest} */
1688         var positionGroup = tcuTestCase.newTest('position', 'gl_Position capture using transform feedback');
1689         testGroup.addChild(positionGroup);
1691         for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
1692             for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
1693                 /** @type {string} */
1694                 var name = primitiveTypes[primitiveType].name + '_' + bufferModes[bufferMode].name;
1696                 positionGroup.addChild(new es3fTransformFeedbackTests.PositionCase(
1697                     name,
1698                     '',
1699                     bufferModes[bufferMode].mode,
1700                     primitiveTypes[primitiveType].type
1701                 ));
1702             }
1703         }
1705         // .point_size
1706         /** @type {tcuTestCase.DeqpTest} */ var pointSizeGroup = tcuTestCase.newTest('point_size', 'gl_PointSize capture using transform feedback');
1707         testGroup.addChild(pointSizeGroup);
1709         for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
1710             for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
1711                 var name = primitiveTypes[primitiveType].name + '_' + bufferModes[bufferMode].name;
1713                 pointSizeGroup.addChild(new es3fTransformFeedbackTests.PointSizeCase(
1714                     name,
1715                     '',
1716                     bufferModes[bufferMode].mode,
1717                     primitiveTypes[primitiveType].type
1718                 ));
1719             }
1720         }
1722         // .basic_type
1723         for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
1724             /** @type {number} */
1725             var bufferMode = bufferModes[bufferModeNdx].mode;
1726             for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
1727                 /** @type {tcuTestCase.DeqpTest} */
1728                 var primitiveGroup = tcuTestCase.newTest(
1729                     'basic_types.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
1730                     'Basic types in transform feedback');
1731                 /** @type {number} */
1732                 var primitiveType = primitiveTypes[primitiveTypeNdx].type;
1733                 testGroup.addChild(primitiveGroup);
1735                 for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
1736                     /** @type {gluShaderUtil.DataType} */
1737                     var type = basicTypes[typeNdx];
1738                     /** @type {boolean} */
1739                     var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
1741                     for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1742                         /** @type {gluShaderUtil.precision} */
1743                         var precision = precisions[precNdx];
1744                         var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
1746                         primitiveGroup.addChild(new es3fTransformFeedbackTests.BasicTypeCase(
1747                             name,
1748                             '',
1749                             bufferMode,
1750                             primitiveType,
1751                             type,
1752                             precision,
1753                             isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
1754                         ));
1755                     }
1756                 }
1757             }
1758         }
1760         // .array
1761         for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
1762             var bufferMode = bufferModes[bufferModeNdx].mode;
1763             for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
1764                 var primitiveGroup = tcuTestCase.newTest(
1765                     'array.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
1766                     'Capturing whole array in TF');
1767                 /** @type {number} */
1768                 var primitiveType = primitiveTypes[primitiveTypeNdx].type;
1769                 testGroup.addChild(primitiveGroup);
1771                 for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
1772                     var type = basicTypes[typeNdx];
1773                     var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
1775                     for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1776                         var precision = precisions[precNdx];
1777                         var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
1779                         primitiveGroup.addChild(new es3fTransformFeedbackTests.BasicArrayCase(
1780                             name,
1781                             '',
1782                             bufferMode,
1783                             primitiveType,
1784                             type,
1785                             precision,
1786                             isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
1787                         ));
1788                     }
1789                 }
1790             }
1791         }
1793         // .array_element
1794         for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
1795             var bufferMode = bufferModes[bufferModeNdx].mode;
1796             for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
1797                 var primitiveGroup = tcuTestCase.newTest(
1798                     'array_element.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
1799                     'Capturing single array element in TF');
1800                 var primitiveType = primitiveTypes[primitiveTypeNdx].type;
1801                 testGroup.addChild(primitiveGroup);
1803                 for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
1804                     var type = basicTypes[typeNdx];
1805                     var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
1807                     for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1808                         var precision = precisions[precNdx];
1809                         var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
1811                         primitiveGroup.addChild(new es3fTransformFeedbackTests.ArrayElementCase(
1812                             name,
1813                             '',
1814                             bufferMode,
1815                             primitiveType,
1816                             type,
1817                             precision,
1818                             isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
1819                         ));
1820                     }
1821                 }
1822             }
1823         }
1825         // .interpolation
1826         for (var modeNdx = 0; modeNdx < interpModes.length; modeNdx++) {
1827             var interp = interpModes[modeNdx].interp;
1828             var modeGroup = tcuTestCase.newTest(
1829                 'interpolation.' + interpModes[modeNdx].name,
1830                 'Different interpolation modes in transform feedback varyings');
1831             testGroup.addChild(modeGroup);
1833             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1834                 var precision = precisions[precNdx];
1836                 for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
1837                     for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
1838                         var name = (
1839                             gluShaderUtil.getPrecisionName(precision) +
1840                             '_vec4_' + primitiveTypes[primitiveType].name +
1841                             '_' + bufferModes[bufferMode].name
1842                         );
1844                         modeGroup.addChild(new es3fTransformFeedbackTests.BasicTypeCase(
1845                             name,
1846                             '',
1847                             bufferModes[bufferMode].mode,
1848                             primitiveTypes[primitiveType].type,
1849                             gluShaderUtil.DataType.FLOAT_VEC4,
1850                             precision,
1851                             interp
1852                         ));
1853                     }
1854                 }
1855             }
1856         }
1858         // .random
1859         for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
1860             /** @type {number} */
1861             var bufferMode = bufferModes[bufferModeNdx].mode;
1862             for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
1863                 var primitiveGroup = tcuTestCase.newTest(
1864                     'random.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
1865                     'Randomized transform feedback cases');
1866                 /** @type {number} */
1867                 var primitiveType = primitiveTypes[primitiveTypeNdx].type;
1868                 testGroup.addChild(primitiveGroup);
1870                 for (var ndx = 0; ndx < 10; ndx++) {
1871                     /** @type {number} */
1872                     var seed = deMath.deMathHash(bufferMode) ^ deMath.deMathHash(primitiveType) ^ deMath.deMathHash(ndx);
1874                     primitiveGroup.addChild(new es3fTransformFeedbackTests.RandomCase(
1875                         (ndx + 1).toString(),
1876                         '',
1877                         bufferMode,
1878                         primitiveType,
1879                         seed
1880                     ));
1881                 }
1882             }
1883         }
1885     };
1887     /**
1888      * Create and execute the test cases
1889      */
1890     es3fTransformFeedbackTests.run = function(context, range) {
1891         gl = context;
1892         var testName = 'transform_feedback';
1893         var testDescription = 'Transform Feedback Tests';
1894         var state = tcuTestCase.runner;
1896         state.testName = testName;
1897         state.testCases = tcuTestCase.newTest(testName, testDescription, null);
1899         //Set up name and description of this test series.
1900         setCurrentTestName(testName);
1901         description(testDescription);
1902         try {
1903             es3fTransformFeedbackTests.init();
1904             if (range)
1905                 state.setRange(range);
1906             tcuTestCase.runTestCases();
1907         } catch (err) {
1908             bufferedLogToConsole(err);
1909             tcuTestCase.runner.terminate();
1910         }
1912     };