Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fShaderPrecisionTests.js
blob28a697397c41b04beafb19106d22303f706dc4c9
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.es3fShaderPrecisionTests');
23 goog.require('framework.common.tcuTestCase');
24 goog.require('framework.common.tcuFloat');
25 goog.require('framework.delibs.debase.deMath');
26 goog.require('framework.delibs.debase.deRandom');
27 goog.require('framework.delibs.debase.deString');
28 goog.require('framework.opengl.gluDrawUtil');
29 goog.require('framework.opengl.gluShaderProgram');
30 goog.require('framework.opengl.gluShaderUtil');
32 goog.scope(function() {
33     var es3fShaderPrecisionTests = functional.gles3.es3fShaderPrecisionTests;
34     var deMath = framework.delibs.debase.deMath;
35     var deRandom = framework.delibs.debase.deRandom;
36     var deString = framework.delibs.debase.deString;
37     var tcuFloat = framework.common.tcuFloat;
38     var tcuTestCase = framework.common.tcuTestCase;
39     var gluDrawUtil = framework.opengl.gluDrawUtil;
40     var gluShaderUtil = framework.opengl.gluShaderUtil;
41     var gluShaderProgram = framework.opengl.gluShaderProgram;
43     /** @const {number} */ es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH = 32;
44     /** @const {number} */ es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT = 32;
46     es3fShaderPrecisionTests.add = function(a, b) { return a + b; };
47     es3fShaderPrecisionTests.sub = function(a, b) { return a - b; };
48     es3fShaderPrecisionTests.mul = function(a, b) { return a * b; };
49     // a * b = (a1 * 2^16 + a0) * (b1 * 2^16 + b0) = a1 * b1 * 2^32 + (a0 * b1 + a1 * b0) * 2^16 + a0 * b0
50     // 32bit integer multiplication may overflow in JavaScript. Only return low 32bit of the result.
51     es3fShaderPrecisionTests.mul32 = function(a, b) {
52         var sign = Math.sign(a) * Math.sign(b);
53         a = Math.abs(a);
54         b = Math.abs(b);
55         var a1 = deMath.split16(a)[1];
56         var a0 = deMath.split16(a)[0];
57         var b1 = deMath.split16(b)[1];
58         var b0 = deMath.split16(b)[0];
59         return sign * ((a0 * b1 + a1 * b0) * 0x10000 + a0 * b0);
60     }
61     es3fShaderPrecisionTests.div = function(a, b) { if (b !== 0) return a / b; else throw new Error('division by zero.')};
63     /**
64      * @param {gluShaderUtil.precision} precision
65      * @param {string} evalOp
66      * @param {boolean} isVertexCase
67      * @return {gluShaderProgram.ShaderProgram}
68      */
69     es3fShaderPrecisionTests.createFloatPrecisionEvalProgram = function(precision, evalOp, isVertexCase) {
70         /** @type {gluShaderUtil.DataType} */ var type = gluShaderUtil.DataType.FLOAT;
71         /** @type {gluShaderUtil.DataType} */ var outType = gluShaderUtil.DataType.UINT;
72         /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(type);
73         /** @type {string} */ var outTypeName = gluShaderUtil.getDataTypeName(outType);
74         /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(precision);
75         /** @type {string} */ var vtx = '';
76         /** @type {string} */ var frag = '';
77         /** @type {string} */ var op = '';
79         vtx += '#version 300 es\n' +
80             'in highp vec4 a_position;\n' +
81             'in ' + precName + ' ' + typeName + ' a_in0;\n' +
82             'in ' + precName + ' ' + typeName + ' a_in1;\n';
83         frag += '#version 300 es\n' +
84             'layout(location = 0) out highp ' + outTypeName + ' o_out;\n';
86         if (isVertexCase) {
87             vtx += 'flat out ' + precName + ' ' + typeName + ' v_out;\n';
88             frag += 'flat in ' + precName + ' ' + typeName + ' v_out;\n';
89         } else {
90             vtx += 'flat out ' + precName + ' ' + typeName + ' v_in0;\n' +
91                 'flat out ' + precName + ' ' + typeName + ' v_in1;\n';
92             frag += 'flat in ' + precName + ' ' + typeName + ' v_in0;\n' +
93                 'flat in ' + precName + ' ' + typeName + ' v_in1;\n';
94         }
96         vtx += '\nvoid main (void)\n{\n' +
97             '    gl_Position = a_position;\n';
98         frag += '\nvoid main (void)\n{\n';
100         op += '\t' + precName + ' ' + typeName + ' in0 = ' + (isVertexCase ? 'a_' : 'v_') + 'in0;\n' +
101             '\t' + precName + ' ' + typeName + ' in1 = ' + (isVertexCase ? 'a_' : 'v_') + 'in1;\n';
103         if (!isVertexCase)
104             op += '\t' + precName + ' ' + typeName + ' res;\n';
106         op += '\t' + (isVertexCase ? 'v_out' : 'res') + ' = ' + evalOp + ';\n';
108         vtx += isVertexCase ? op : '';
109         frag += isVertexCase ? '' : op;
110         op = '';
112         if (isVertexCase) {
113             frag += '    o_out = floatBitsToUint(v_out);\n';
114         } else {
115             vtx += '    v_in0 = a_in0;\n' +
116                 '    v_in1 = a_in1;\n';
117             frag += '    o_out = floatBitsToUint(res);\n';
118         }
120         vtx += '}\n';
121         frag += '}\n';
123         return new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
124     };
126     /**
127      * @param {gluShaderUtil.DataType} type
128      * @param {gluShaderUtil.precision} precision
129      * @param {string} evalOp
130      * @param {boolean} isVertexCase
131      * @return {gluShaderProgram.ShaderProgram}
132      */
133     es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram = function(type, precision, evalOp, isVertexCase) {
134         /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(type);
135         /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(precision);
136         /** @type {string} */ var vtx = '';
137         /** @type {string} */ var frag = '';
138         /** @type {string} */ var op = '';
140         vtx += '#version 300 es\n' +
141             'in highp vec4 a_position;\n' +
142             'in ' + precName + ' ' + typeName + ' a_in0;\n' +
143             'in ' + precName + ' ' + typeName + ' a_in1;\n';
144         frag += '#version 300 es\n' +
145             'layout(location = 0) out ' + precName + ' ' + typeName + ' o_out;\n';
147         if (isVertexCase) {
148             vtx += 'flat out ' + precName + ' ' + typeName + ' v_out;\n';
149             frag += 'flat in ' + precName + ' ' + typeName + ' v_out;\n';
150         } else {
151             vtx += 'flat out ' + precName + ' ' + typeName + ' v_in0;\n' +
152                 'flat out ' + precName + ' ' + typeName + ' v_in1;\n';
153             frag += 'flat in ' + precName + ' ' + typeName + ' v_in0;\n' +
154                 'flat in ' + precName + ' ' + typeName + ' v_in1;\n';
155         }
157         vtx += '\nvoid main (void)\n{\n'+
158             '    gl_Position = a_position;\n';
159         frag += '\nvoid main (void)\n{\n';
161         op += '\t' + precName + ' ' + typeName + ' in0 = ' + (isVertexCase ? 'a_' : 'v_') + 'in0;\n' +
162             '\t' + precName + ' ' + typeName + ' in1 = ' + (isVertexCase ? 'a_' : 'v_') + 'in1;\n';
164         op += '\t' + (isVertexCase ? 'v_' : 'o_') + 'out = ' + evalOp + ';\n';
166         vtx += isVertexCase ? op : '';
167         frag += isVertexCase ? '' : op;
168         op = '';
170         if (isVertexCase) {
171             frag += '    o_out = v_out;\n';
172         } else {
173             vtx += '    v_in0 = a_in0;\n' +
174                 '    v_in1 = a_in1;\n';
175         }
177         vtx += '}\n';
178         frag += '}\n';
180         return new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
181     };
183     /** @typedef {function(number, number)} */ es3fShaderPrecisionTests.EvalFunc;
186     /**
187      * @constructor
188      * @extends {tcuTestCase.DeqpTest}
189      * @param {string} name
190      * @param {string} desc
191      * @param {string} op
192      * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
193      * @param {gluShaderUtil.precision} precision
194      * @param {Array<number>} rangeA
195      * @param {Array<number>} rangeB
196      * @param {boolean} isVertexCase
197      */
198     es3fShaderPrecisionTests.ShaderFloatPrecisionCase = function(name, desc, op, evalFunc, precision, rangeA, rangeB, isVertexCase) {
199         tcuTestCase.DeqpTest.call(this, name, desc);
200         // Case parameters.
201         /** @type {string} */ this.m_op = op;
202         /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
203         /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
204         /** @type {Array<number>} */ this.m_rangeA = rangeA;
205         /** @type {Array<number>} */ this.m_rangeB = rangeB;
206         /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
208         /** @type {number} */ this.m_numTestsPerIter = 32;
209         /** @type {number} */ this.m_numIters = 4;
210         /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
212         // Iteration state.
213         /** @type {?gluShaderProgram.ShaderProgram} */ this.m_program = null;
214         /** @type {?WebGLFramebuffer} */ this.m_framebuffer = null;
215         /** @type {?WebGLRenderbuffer} */ this.m_renderbuffer = null;
216         /** @type {number} */ this.m_iterNdx = 0;
217         /** @type {Array<boolean>} */ this.m_iterPass = [];
218     };
220     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
221     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderFloatPrecisionCase;
223     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.init = function() {
224         assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
226         // Create program.
227         this.m_program = es3fShaderPrecisionTests.createFloatPrecisionEvalProgram(this.m_precision, this.m_op, this.m_isVertexCase);
229         if (!this.m_program.isOk())
230             assertMsgOptions(false, 'Compile failed', false, true);
232         // Create framebuffer.
233         this.m_framebuffer = gl.createFramebuffer();
234         this.m_renderbuffer = gl.createRenderbuffer();
236         gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
237         gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32UI, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
239         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
240         gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
242         assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
244         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
246         this.m_iterNdx = 0;
247     };
249     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.deinit = function() {
250         if(this.m_framebuffer)
251             gl.deleteFramebuffer(this.m_framebuffer);
252         if(this.m_renderbuffer)
253             gl.deleteRenderbuffer(this.m_renderbuffer);
254         this.m_program = null;
255         this.m_framebuffer = null;
256         this.m_renderbuffer = null;
257     };
259     /**
260      * @param {number} in0
261      * @param {number} in1
262      * @param {number} reference
263      * @param {number} result
264      */
266     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.compare = function(in0, in1, reference, result) {
267         // Comparison is done using 64-bit reference value to accurately evaluate rounding mode error.
268         // If 32-bit reference value is used, 2 bits of rounding error must be allowed.
270         // For mediump and lowp types the comparison currently allows 3 bits of rounding error:
271         // two bits from conversions and one from actual operation.
273         // \todo [2013-09-30 pyry] Make this more strict: determine if rounding can actually happen.
275         /** @type {number} */ var  mantissaBits = this.m_precision == gluShaderUtil.precision.PRECISION_HIGHP ? 23 : 10;
276         /** @type {number} */ var  numPrecBits = 52 - mantissaBits;
278         /** @type {number} */ var  in0Exp = tcuFloat.newFloat32(in0).exponent();
279         /** @type {number} */ var  in1Exp = tcuFloat.newFloat32(in1).exponent();
280         /** @type {number} */ var  resExp = tcuFloat.newFloat32(result).exponent();
281         /** @type {number} */ var  numLostBits = Math.max(in0Exp - resExp, in1Exp - resExp, 0); // Lost due to mantissa shift.
283         /** @type {number} */ var  roundingUlpError = this.m_precision == gluShaderUtil.precision.PRECISION_HIGHP ? 1 : 3;
284         /** @type {number} */ var  maskBits = numLostBits + numPrecBits;
286         bufferedLogToConsole("Assuming " + mantissaBits + " mantissa bits, " + numLostBits + " bits lost in operation, and " + roundingUlpError + " ULP rounding error.")
288         // These numbers should never be larger than 52 bits. An assertion in getBitRange verifies this.
289         /** @type {number} */ var accurateRefBits = tcuFloat.newFloat64(reference).getBitRange(maskBits, 64);
290         /** @type {number} */ var accurateResBits = tcuFloat.newFloat64(result).getBitRange(maskBits, 64);
291         /** @type {number} */ var ulpDiff = Math.abs(accurateRefBits - accurateResBits);
293         if (ulpDiff > roundingUlpError) {
294             bufferedLogToConsole("ERROR: comparison failed! ULP diff (ignoring lost/undefined bits) = " + ulpDiff );
295             return false;
296         }
297         else
298             return true;
299     };
301     /**
302      * @return {tcuTestCase.IterateResult}
303      */
304     es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.iterate = function() {
305         var testPassed = true;
306         var testPassedMsg = 'Pass';
308         // Constant data.
309         /** @type {Array<number>} */ var position =[
310         -1.0, -1.0, 0.0, 1.0,
311             -1.0, 1.0, 0.0, 1.0,
312             1.0, -1.0, 0.0, 1.0,
313             1.0, 1.0, 0.0, 1.0
314     ];
316         /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
317         /** @type {number} */ var numVertices = 4;
318         /** @type {Array<number>} */ var in0Arr = [0.0, 0.0, 0.0, 0.0];
319         /** @type {Array<number>} */ var in1Arr = [0.0, 0.0, 0.0, 0.0];
321         /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
323         // Image read from GL.
324         /** @type {goog.TypedArray} */ var pixels_uint = new Uint32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
326         // \todo [2012-05-03 pyry] Could be cached.
327         /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
329         gl.useProgram(prog);
330         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
332         vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
335         // Compute values and reference.
336         for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
337             /** @type {number} */ var in0 = this.m_rnd.getFloat(this.m_rangeA[0], this.m_rangeA[1]);
338             /** @type {number} */ var in1 = this.m_rnd.getFloat(this.m_rangeB[0], this.m_rangeB[1]);
340             // These random numbers are used in the reference computation. But
341             // highp is only 32 bits, so these float64s must be rounded to
342             // float32 first for correctness. This is needed for highp_mul_* on
343             // one Linux/NVIDIA machine.
344             in0 = tcuFloat.newFloat32(in0).getValue();
345             in1 = tcuFloat.newFloat32(in1).getValue();
347             /** @type {number} */ var refD = this.m_evalFunc(in0, in1);
349             bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": "+
350                 "in0 = " + in0 + " / " + tcuFloat.newFloat32(in0).bits() +
351                 ", in1 = " + in1 + " / " + tcuFloat.newFloat32(in1).bits() +
352                 "  reference = " + refD + " / " + tcuFloat.newFloat32(refD).bits());
354             in0Arr = [in0, in0, in0, in0];
355             in1Arr = [in1, in1, in1, in1];
356             vertexArrays[1] = gluDrawUtil.newFloatVertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
357             vertexArrays[2] = gluDrawUtil.newFloatVertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
359             gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
361             gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
362                 es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT, gl.RGBA_INTEGER, gl.UNSIGNED_INT, pixels_uint);
364             var pixels = new Float32Array(pixels_uint.buffer);
365             bufferedLogToConsole("  result = " + pixels[0] + " / " + tcuFloat.newFloat32(pixels[0]).bits());
367             // Verify results
368             /** @type {boolean} */ var firstPixelOk = this.compare(in0, in1, refD, pixels[0]);
370             if (firstPixelOk) {
371                 // Check that rest of pixels match to first one.
372                 /** @type {number} */ var firstPixelBits = tcuFloat.newFloat32(pixels[0]).bits();
373                 /** @type {boolean} */ var allPixelsOk = true;
375                 for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
376                     for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
377                         /** @type {number} */ var pixelBits = tcuFloat.newFloat32(pixels[(y * es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4]).bits();
379                         if (pixelBits != firstPixelBits) {
380                             bufferedLogToConsole("ERROR: Inconsistent results, got " + pixelBits + " at (" + x + ", " + y + ")")
381                             allPixelsOk = false;
382                         }
383                     }
385                     if (!allPixelsOk)
386                         break;
387                 }
389                 if (!allPixelsOk){
390                     bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + "Inconsistent values in framebuffer");
391                     testPassed = false;
392                     testPassedMsg = 'Inconsistent values in framebuffer';
393                 }
394             }
395             else{
396                 bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + "Result comparison failed");
397                 testPassed = false;
398                 testPassedMsg = 'Result comparison failed'
399             }
400         }
402         // [dag] Aggregating test results to make the test less verbose.
403         this.m_iterPass[this.m_iterNdx] = testPassed;
405         // [dag] Show test results after the last iteration is done.
406         if (this.m_iterPass.length === this.m_numIters) {
407             if (!deMath.boolAll(this.m_iterPass))
408                 testFailedOptions(testPassedMsg, false);
409             else
410                 testPassedOptions(testPassedMsg, true);
411         }
412         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
414         this.m_iterNdx += 1;
415         return (this.m_iterNdx < this.m_numIters) ? tcuTestCase.IterateResult.CONTINUE : tcuTestCase.IterateResult.STOP;
416     };
418     /**
419      * @constructor
420      * @extends {tcuTestCase.DeqpTest}
421      * @param {string} name
422      * @param {string} desc
423      * @param {string} op
424      * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
425      * @param {gluShaderUtil.precision} precision
426      * @param {number} bits
427      * @param {Array<number>} rangeA
428      * @param {Array<number>} rangeB
429      * @param {boolean} isVertexCase
430      */
431     es3fShaderPrecisionTests.ShaderIntPrecisionCase = function(name, desc, op, evalFunc, precision, bits, rangeA, rangeB, isVertexCase) {
432         tcuTestCase.DeqpTest.call(this, name, desc);
433         // Case parameters.
434         /** @type {string} */ this.m_op = op;
435         /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
436         /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
437         /** @type {number} */ this.m_bits = bits;
438         /** @type {Array<number>} */ this.m_rangeA = rangeA;
439         /** @type {Array<number>} */ this.m_rangeB = rangeB;
440         /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
442         /** @type {number} */ this.m_numTestsPerIter = 32;
443         /** @type {number} */ this.m_numIters = 4;
444         /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
446         // Iteration state.
447         /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
448         /** @type {WebGLFramebuffer} */ this.m_framebuffer = null;
449         /** @type {WebGLRenderbuffer} */ this.m_renderbuffer = null;
450         /** @type {number} */ this.m_iterNdx = 0;
451     };
453     es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
454     es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderIntPrecisionCase;
456     es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.init = function() {
457         assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
458         // Create program.
459         this.m_program = es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram(gluShaderUtil.DataType.INT, this.m_precision, this.m_op, this.m_isVertexCase);
461         if (!this.m_program.isOk())
462             assertMsgOptions(false, 'Compile failed', false, true);
464         // Create framebuffer.
465         this.m_framebuffer = gl.createFramebuffer();
466         this.m_renderbuffer = gl.createRenderbuffer();
468         gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
469         gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32I, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
471         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
472         gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
474         assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
476         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
478         this.m_iterNdx = 0;
480         bufferedLogToConsole("Number of accurate bits assumed = " + this.m_bits);
481     };
483     es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.deinit = function() {
484         if(this.m_framebuffer)
485             gl.deleteFramebuffer(this.m_framebuffer);
486         if(this.m_renderbuffer)
487             gl.deleteRenderbuffer(this.m_renderbuffer);
488         this.m_program = null;
489         this.m_framebuffer = null;
490         this.m_renderbuffer = null;
491     };
493     /**
494      * @param {number} value
495      * @param {number} bits
496      * @return {number}
497      */
499     es3fShaderPrecisionTests.extendTo32Bit = function(value, bits) {
500         return (value & ((1 << (bits - 1)) - 1)) | ((value & (1 << (bits - 1))) << (32 - bits)) >> (32 - bits);
501     };
503     /**
504      * @return {tcuTestCase.IterateResult}
505      */
506     es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.iterate = function() {
507         var testPassed = true;
508         var testPassedMsg = 'Pass';
509         // Constant data.
510         /** @type {Array<number>} */ var position = [
511         -1.0, -1.0, 0.0, 1.0,
512             -1.0, 1.0, 0.0, 1.0,
513             1.0, -1.0, 0.0, 1.0,
514             1.0, 1.0, 0.0, 1.0
515     ]
516         /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
518         /** @type {number} */ var numVertices    = 4;
519         /** @type {Array<number>} */ var in0Arr = [0, 0, 0, 0];
520         /** @type {Array<number>} */ var in1Arr = [0, 0, 0, 0];
522         /** @type {number} */ var mask = this.m_bits === 32 ? 0xffffffff : ((1 << this.m_bits) - 1);
523         /** @type {goog.TypedArray} */ var pixels = new Int32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
524         /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
526         /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
528         // \todo [2012-05-03 pyry] A bit hacky. getInt() should work fine with ranges like this.
529         /** @type {boolean} */ var isMaxRangeA = this.m_rangeA[0] === 0x80000000 && this.m_rangeA[1] === 0x7fffffff;
530         /** @type {boolean} */ var isMaxRangeB = this.m_rangeB[0] === 0x80000000 && this.m_rangeB[1] === 0x7fffffff;
532         gl.useProgram(prog);
533         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
535         vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
537         // Compute values and reference.
538         for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
539             /** @type {number} */ var in0 = this.m_rnd.getInt(this.m_rangeA[0], this.m_rangeA[1]); //es3fShaderPrecisionTests.extendTo32Bit(((isMaxRangeA ? Math.abs(this.m_rnd.getInt()) : this.m_rnd.getInt(this.m_rangeA[0], this.m_rangeA[1])) & mask), this.m_bits);
540             /** @type {number} */ var in1 = this.m_rnd.getInt(this.m_rangeB[0], this.m_rangeB[1]); //es3fShaderPrecisionTests.extendTo32Bit(((isMaxRangeB ? Math.abs(this.m_rnd.getInt()) : this.m_rnd.getInt(this.m_rangeB[0], this.m_rangeB[1])) & mask), this.m_bits);
541             /** @type {number} */ var refMasked = this.m_evalFunc(in0, in1) & mask;
542             /** @type {number} */ var refOut = es3fShaderPrecisionTests.extendTo32Bit(refMasked, this.m_bits);
544             bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": " +
545                 "in0 = " + in0 + ", in1 = " + in1 + ", ref out = " + refOut + " / " + refMasked);
547             in0Arr = [in0, in0, in0, in0];
548             in1Arr = [in1, in1, in1, in1];
550             vertexArrays[1] = gluDrawUtil.newInt32VertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
551             vertexArrays[2] = gluDrawUtil.newInt32VertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
553             gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
555             gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
556                 es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT,
557                 gl.RGBA_INTEGER, gl.INT, pixels);
559             // Compare pixels.
560             for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
561                 for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
562                     /** @type {number} */ var cmpOut = pixels[(y * es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4];
563                     /** @type {number} */ var cmpMasked = cmpOut & mask;
565                     if (cmpMasked != refMasked) {
566                         bufferedLogToConsole("Comparison failed (at " + x + ", " + y + "): " +
567                             + "got " + cmpOut + " / " + cmpOut);
568                         testPassed = false;
569                         testPassedMsg = 'Comparison failed';
570                     }
571                 }
572             }
573         }
575         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
577         this.m_iterNdx += 1;
578         if (!testPassed) {
579             testFailedOptions(testPassedMsg, false);
580             return tcuTestCase.IterateResult.STOP;
581         } else if (testPassed && this.m_iterNdx < this.m_numIters) {
582             return tcuTestCase.IterateResult.CONTINUE;
583         } else {
584             testPassedOptions(testPassedMsg, true);
585             return tcuTestCase.IterateResult.STOP;
586         }
587     };
589     /**
590      * @constructor
591      * @extends {tcuTestCase.DeqpTest}
592      * @param {string} name
593      * @param {string} desc
594      * @param {string} op
595      * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
596      * @param {gluShaderUtil.precision} precision
597      * @param {number} bits
598      * @param {Array<number>} rangeA
599      * @param {Array<number>} rangeB
600      * @param {boolean} isVertexCase
601      */
602     es3fShaderPrecisionTests.ShaderUintPrecisionCase = function(name, desc, op, evalFunc, precision, bits, rangeA, rangeB, isVertexCase) {
603         tcuTestCase.DeqpTest.call(this, name, desc);
604         // Case parameters.
605         /** @type {string} */ this.m_op = op;
606         /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
607         /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
608         /** @type {number} */ this.m_bits = bits;
609         /** @type {Array<number>} */ this.m_rangeA = rangeA;
610         /** @type {Array<number>} */ this.m_rangeB = rangeB;
611         /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
613         /** @type {number} */ this.m_numTestsPerIter = 32;
614         /** @type {number} */ this.m_numIters = 4;
615         /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
617         // Iteration state.
618         /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
619         /** @type {WebGLFramebuffer} */ this.m_framebuffer = null;
620         /** @type {WebGLRenderbuffer} */ this.m_renderbuffer = null;
621         /** @type {number} */ this.m_iterNdx = 0;
622     };
624     es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
625     es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderUintPrecisionCase;
627     es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.init = function() {
628         assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
629         // Create program.
630         this.m_program = es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram(gluShaderUtil.DataType.UINT, this.m_precision, this.m_op, this.m_isVertexCase);
632         if (!this.m_program.isOk())
633             assertMsgOptions(false, 'Compile failed', false, true);
635         // Create framebuffer.
636         this.m_framebuffer = gl.createFramebuffer();
637         this.m_renderbuffer = gl.createRenderbuffer();
639         gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
640         gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32UI, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
642         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
643         gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
645         assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
647         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
649         this.m_iterNdx = 0;
651         bufferedLogToConsole("Number of accurate bits assumed = " + this.m_bits);
652     };
654     es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.deinit = function() {
655         if(this.m_framebuffer)
656             gl.deleteFramebuffer(this.m_framebuffer);
657         if(this.m_renderbuffer)
658             gl.deleteRenderbuffer(this.m_renderbuffer);
659         this.m_program = null;
660         this.m_framebuffer = null;
661         this.m_renderbuffer = null;
662     };
664     /**
665      * @return {tcuTestCase.IterateResult}
666      */
667     es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.iterate = function() {
668         var testPassed = true;
669         var testPassedMsg = 'Pass';
671         // Constant data.
672         /** @type {Array<number>} */ var position = [
673         -1.0, -1.0, 0.0, 1.0,
674             -1.0, 1.0, 0.0, 1.0,
675             1.0, -1.0, 0.0, 1.0,
676             1.0, 1.0, 0.0, 1.0
677     ];
678         /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
680         /** @type {number} */ var numVertices = 4;
681         /** @type {Array<number>} */ var in0Arr = [0, 0, 0, 0];
682         /** @type {Array<number>} */ var in1Arr = [0, 0, 0, 0];
684         /** @type {number} */ var mask = this.m_bits === 32 ? 0xffffffff : ((1 << this.m_bits) - 1);
685         /** @type {goog.TypedArray} */ var pixels = new Uint32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
686         /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
688         /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
690         // \todo [2012-05-03 pyry] A bit hacky.
691         /** @type {boolean} */ var isMaxRangeA = this.m_rangeA[0] === 0 && this.m_rangeA[1] === 0xffffffff;
692         /** @type {boolean} */ var isMaxRangeB = this.m_rangeB[0] === 0 && this.m_rangeB[1] === 0xffffffff;
694         gl.useProgram(prog);
695         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
697         vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
699         // Compute values and reference.
700         for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
701             /** @type {number} */ var in0 = (isMaxRangeA ? Math.abs(this.m_rnd.getInt()) : (this.m_rangeA[0] + Math.abs(this.m_rnd.getInt()) % (this.m_rangeA[1] - this.m_rangeA[0] + 1))) & mask;
702             /** @type {number} */ var in1 = (isMaxRangeB ? Math.abs(this.m_rnd.getInt()) : (this.m_rangeB[0] + Math.abs(this.m_rnd.getInt()) % (this.m_rangeB[1] - this.m_rangeB[0] + 1))) & mask;
703             /** @type {number} */ var refOut = this.m_evalFunc(in0, in1) & mask;
705             bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": " +
706                 + "in0 = " + in0 + ", in1 = " + in1 + ", ref out = " + refOut)
708             in0Arr = [in0, in0, in0, in0];
709             in1Arr = [in1, in1, in1, in1];
710             vertexArrays[1] = gluDrawUtil.newUint32VertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
711             vertexArrays[2] = gluDrawUtil.newUint32VertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
713             gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
715             gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
716                 es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT, gl.RGBA_INTEGER, gl.UNSIGNED_INT, pixels);
718             // Compare pixels.
719             for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
720                 for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
721                     /** @type {number} */ var cmpOut = pixels[(y*es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4];
722                     /** @type {number} */ var cmpMasked = cmpOut & mask;
724                     if (cmpMasked != refOut) {
725                         bufferedLogToConsole("Comparison failed (at " + x + ", " + y + "): " + "got " + cmpOut)
726                         testPassed = false;
727                         testPassedMsg = 'Comparison failed';
728                     }
729                 }
730             }
731         }
734         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
736         this.m_iterNdx += 1;
737         if (!testPassed) {
738             testFailedOptions(testPassedMsg, false);
739             return tcuTestCase.IterateResult.STOP;
740         } else if (testPassed && this.m_iterNdx < this.m_numIters) {
741             return tcuTestCase.IterateResult.CONTINUE;
742         } else {
743             testPassedOptions(testPassedMsg, true);
744             return tcuTestCase.IterateResult.STOP;
745         }
746     };
748     /**
749      * @constructor
750      * @extends {tcuTestCase.DeqpTest}
751      */
752     es3fShaderPrecisionTests.ShaderPrecisionTests = function() {
753         tcuTestCase.DeqpTest.call(this, 'precision', 'Shader precision requirements validation tests');
754     };
756     es3fShaderPrecisionTests.ShaderPrecisionTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
757     es3fShaderPrecisionTests.ShaderPrecisionTests.prototype.constructor = es3fShaderPrecisionTests.ShaderPrecisionTests;
759     es3fShaderPrecisionTests.ShaderPrecisionTests.prototype.init = function() {
760         var testGroup = tcuTestCase.runner.testCases;
761         // Exp = Emax-2, Mantissa = 0
762         // /** @type {number} */ var minF32 = tcuFloat.newFloat32((1 << 31) | (0xfd << 23) | 0x0).getValue();
763         // /** @type {number} */ var maxF32 = tcuFloat.newFloat32((0 << 31) | (0xfd << 23) | 0x0).getValue();
764         // [dag] Workaround for float32 numbers
765         /** @type {number} */ var minF32 = new Float32Array(new Uint32Array([1<<31|0xfd<<23|0x0]).buffer)[0];
766         /** @type {number} */ var maxF32 = new Float32Array(new Uint32Array([0<<31|0xfd<<23|0x0]).buffer)[0];
768         // /** @type {number} */ var minF16 = tcuFloat.newFloat16(((1 << 15) | (0x1d << 10) | 0x0)).getValue();
769         // /** @type {number} */ var maxF16 = tcuFloat.newFloat16(((0 << 15) | (0x1d << 10) | 0x0)).getValue();
770         /** @type {number} */ var minF16 = -16384; //-1 << 14; // 1 << 15 | 0x1d | 0x0 == 0b1111010000000000; -1 * (2**(29-15)) * 1
771         /** @type {number} */ var maxF16 = 16384; //1 << 14; // 0 << 15 | 0x1d | 0x0 == 0b0111010000000000; +1 * (2**(29-15)) * 1
773         /** @type {Array<number>} */ var fullRange32F = [minF32, maxF32];
774         /** @type {Array<number>} */ var fullRange16F = [minF16, maxF16];
775         /** @type {Array<number>} */ var fullRange32I = [-2147483648, 2147483647]; // [0x80000000|0, 0x7fffffff|0]; // |0 to force the number as a 32-bit integer
776         /** @type {Array<number>} */ var fullRange16I = [minF16, maxF16 - 1]; //[-(1 << 15), (1 << 15) - 1]; // Added the negative sign to index 0
777         /** @type {Array<number>} */ var fullRange8I = [-128, 127]; //[-(1 << 7), (1 << 7) - 1]; // Added the negative sign to index 0
778         /** @type {Array<number>} */ var fullRange32U = [0, 0xffffffff];
779         /** @type {Array<number>} */ var fullRange16U = [0, 0xffff];
780         /** @type {Array<number>} */ var fullRange8U = [0, 0xff];
782         // \note Right now it is not programmatically verified that the results shouldn't end up being inf/nan but
783         // actual values used are ok.
785         /**
786          * @constructor
787          * @struct
788          * @param {string} name
789          * @param {string} op
790          * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
791          * @param {gluShaderUtil.precision} precision
792          * @param {Array<number>} rangeA
793          * @param {Array<number>} rangeB
794          */
795         var FloatCase = function(name, op, evalFunc, precision, rangeA, rangeB) {
796             /** @type {string} */ this.name = name;
797             /** @type {string} */ this.op = op;
798             /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
799             /** @type {gluShaderUtil.precision} */ this.precision = precision;
800             /** @type {Array<number>} */ this.rangeA = rangeA;
801             /** @type {Array<number>} */ this.rangeB = rangeB;
802         };
804         /** @type {Array<FloatCase>} */ var floatCases = [
805         new FloatCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, fullRange32F, fullRange32F),
806             new FloatCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, fullRange32F, fullRange32F),
807             new FloatCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_HIGHP, [-1e5, 1e5], [-1e5, 1e5]),
808             new FloatCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, [-1e5, 1e5], [-1e5, 1e5]),
809             new FloatCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, fullRange16F, fullRange16F),
810             new FloatCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, fullRange16F, fullRange16F),
811             new FloatCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, [-1e2, 1e2], [-1e2, 1e2]),
812             new FloatCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, [-1e2, 1e2], [-1e2, 1e2])
813     ];
815         /**
816          * @constructor
817          * @struct
818          * @param {string} name
819          * @param {string} op
820          * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
821          * @param {gluShaderUtil.precision} precision
822          * @param {number} bits
823          * @param {Array<number>} rangeA
824          * @param {Array<number>} rangeB
825          */
826         var IntCase = function(name, op, evalFunc, precision, bits, rangeA, rangeB) {
827             /** @type {string} */ this.name = name;
828             /** @type {string} */ this.op = op;
829             /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
830             /** @type {gluShaderUtil.precision} */ this.precision = precision;
831             /** @type {number} */ this.bits = bits;
832             /** @type {Array<number>} */ this.rangeA = rangeA;
833             /** @type {Array<number>} */ this.rangeB = rangeB;
834         };
836         /** @type {Array<IntCase>} */ var intCases = [
837         new IntCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
838             new IntCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
839             new IntCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul32, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
840             new IntCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, [-10000, -1]),
841             new IntCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
842             new IntCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
843             new IntCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
844             new IntCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, [1, 1000]),
845             new IntCase('lowp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
846             new IntCase('lowp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
847             new IntCase('lowp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
848             new IntCase('lowp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, [-50, -1])
849     ];
851         /**
852          * @constructor
853          * @struct
854          * @param {string} name
855          * @param {string} op
856          * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
857          * @param {gluShaderUtil.precision} precision
858          * @param {number} bits
859          * @param {Array<number>} rangeA
860          * @param {Array<number>} rangeB
861          */
862         var UintCase = function(name, op, evalFunc, precision, bits, rangeA, rangeB) {
863             /** @type {string} */ this.name = name;
864             /** @type {string} */ this.op = op;
865             /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
866             /** @type {gluShaderUtil.precision} */ this.precision = precision;
867             /** @type {number} */ this.bits = bits;
868             /** @type {Array<number>} */ this.rangeA = rangeA;
869             /** @type {Array<number>} */ this.rangeB = rangeB;
870         };
872         /** @type {Array<UintCase>} */ var uintCases = [
873         new UintCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
874             new UintCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
875             new UintCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul32, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
876             new UintCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, [1, 10000]),
877             new UintCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
878             new UintCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
879             new UintCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
880             new UintCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, [1, 1000]),
881             new UintCase('lowp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
882             new UintCase('lowp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
883             new UintCase('lowp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
884             new UintCase('lowp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, [1, 50])
885     ];
887         /** @type {tcuTestCase.DeqpTest} */ var floatGroup = tcuTestCase.newTest('float', 'Floating-point precision tests');
888         testGroup.addChild(floatGroup);
889         for (var ndx = 0; ndx < floatCases.length; ndx++) {
890             floatGroup.addChild(new es3fShaderPrecisionTests.ShaderFloatPrecisionCase(
891                 floatCases[ndx].name + '_vertex', '', floatCases[ndx].op, floatCases[ndx].evalFunc,
892                 floatCases[ndx].precision, floatCases[ndx].rangeA, floatCases[ndx].rangeB, true));
893             floatGroup.addChild(new es3fShaderPrecisionTests.ShaderFloatPrecisionCase(
894                 floatCases[ndx].name + '_fragment', '', floatCases[ndx].op, floatCases[ndx].evalFunc,
895                 floatCases[ndx].precision, floatCases[ndx].rangeA, floatCases[ndx].rangeB, false));
896         }
898         /** @type {tcuTestCase.DeqpTest} */ var intGroup = tcuTestCase.newTest('int', 'Integer precision tests');
899         testGroup.addChild(intGroup);
900         for (var ndx = 0; ndx < intCases.length; ndx++) {
901             intGroup.addChild(new es3fShaderPrecisionTests.ShaderIntPrecisionCase(
902                 intCases[ndx].name + '_vertex', '', intCases[ndx].op, intCases[ndx].evalFunc,
903                 intCases[ndx].precision, intCases[ndx].bits, intCases[ndx].rangeA, intCases[ndx].rangeB, true));
904             intGroup.addChild(new es3fShaderPrecisionTests.ShaderIntPrecisionCase(
905                 intCases[ndx].name + '_fragment', '', intCases[ndx].op, intCases[ndx].evalFunc,
906                 intCases[ndx].precision, intCases[ndx].bits, intCases[ndx].rangeA, intCases[ndx].rangeB, false));
907         }
909         /** @type {tcuTestCase.DeqpTest} */ var uintGroup = tcuTestCase.newTest('uint', 'Unsigned integer precision tests');
910         testGroup.addChild(uintGroup);
911         for (var ndx = 0; ndx < uintCases.length; ndx++) {
912             uintGroup.addChild(new es3fShaderPrecisionTests.ShaderUintPrecisionCase(
913                 uintCases[ndx].name + '_vertex', '', uintCases[ndx].op, uintCases[ndx].evalFunc,
914                 uintCases[ndx].precision, uintCases[ndx].bits, uintCases[ndx].rangeA, uintCases[ndx].rangeB, true));
915             uintGroup.addChild(new es3fShaderPrecisionTests.ShaderUintPrecisionCase(
916                 uintCases[ndx].name + '_fragment', '', uintCases[ndx].op, uintCases[ndx].evalFunc,
917                 uintCases[ndx].precision, uintCases[ndx].bits, uintCases[ndx].rangeA, uintCases[ndx].rangeB, false));
918         }
919     };
921     /**
922      * Run test
923      * @param {WebGL2RenderingContext} context
924      */
925     es3fShaderPrecisionTests.run = function(context, range) {
926         gl = context;
927         //Set up Test Root parameters
928         var state = tcuTestCase.runner;
929         state.setRoot(new es3fShaderPrecisionTests.ShaderPrecisionTests());
931         //Set up name and description of this test series.
932         setCurrentTestName(state.testCases.fullName());
933         description(state.testCases.getDescription());
935         try {
936             if (range)
937                 state.setRange(range);
938             //Run test cases
939             tcuTestCase.runTestCases();
940         }
941         catch (err) {
942             testFailedOptions('Failed to es3fShaderPrecisionTests.run tests', false);
943             tcuTestCase.runner.terminate();
944         }
945     };