Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fShaderDerivateTests.js
blob9c859c296f4c8ecaf8ad75555ab776e14cd37ba9
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.es3fShaderDerivateTests');
23 goog.require('framework.delibs.debase.deMath');
24 goog.require('framework.delibs.debase.deRandom');
25 goog.require('framework.delibs.debase.deString');
26 goog.require('framework.opengl.gluDrawUtil');
27 goog.require('framework.opengl.gluPixelTransfer');
28 goog.require('framework.opengl.gluShaderProgram');
29 goog.require('framework.opengl.gluShaderUtil');
30 goog.require('framework.opengl.gluTexture');
31 goog.require('framework.opengl.gluTextureUtil');
32 goog.require('framework.common.tcuInterval');
33 goog.require('framework.common.tcuFloat');
34 goog.require('framework.common.tcuLogImage');
35 goog.require('framework.common.tcuMatrix');
36 goog.require('framework.common.tcuPixelFormat');
37 goog.require('framework.common.tcuRGBA');
38 goog.require('framework.common.tcuStringTemplate');
39 goog.require('framework.common.tcuSurface');
40 goog.require('framework.common.tcuTexture');
41 goog.require('framework.common.tcuTextureUtil');
42 goog.require('framework.common.tcuTestCase');
43 goog.require('modules.shared.glsShaderRenderCase');
45 goog.scope(function() {
46     var es3fShaderDerivateTests = functional.gles3.es3fShaderDerivateTests;
47     var deMath = framework.delibs.debase.deMath;
48     var deRandom = framework.delibs.debase.deRandom;
49     var deString = framework.delibs.debase.deString;
50     var gluDrawUtil = framework.opengl.gluDrawUtil;
51     var gluPixelTransfer = framework.opengl.gluPixelTransfer;
52     var gluShaderProgram = framework.opengl.gluShaderProgram;
53     var gluShaderUtil = framework.opengl.gluShaderUtil;
54     var gluTexture = framework.opengl.gluTexture;
55     var gluTextureUtil = framework.opengl.gluTextureUtil;
56     var tcuInterval = framework.common.tcuInterval;
57     var tcuFloat = framework.common.tcuFloat;
58     var tcuLogImage = framework.common.tcuLogImage;
59     var tcuMatrix = framework.common.tcuMatrix;
60     var tcuPixelFormat = framework.common.tcuPixelFormat;
61     var tcuRGBA = framework.common.tcuRGBA;
62     var tcuStringTemplate = framework.common.tcuStringTemplate;
63     var tcuSurface = framework.common.tcuSurface;
64     var tcuTexture = framework.common.tcuTexture;
65     var tcuTextureUtil = framework.common.tcuTextureUtil;
66     var tcuTestCase = framework.common.tcuTestCase;
67     var glsShaderRenderCase = modules.shared.glsShaderRenderCase;
69     /** @const {number} */ es3fShaderDerivateTests.VIEWPORT_WIDTH = 167;
70     /** @const {number} */ es3fShaderDerivateTests.VIEWPORT_HEIGHT = 103;
71     /** @const {number} */ es3fShaderDerivateTests.FBO_WIDTH = 99;
72     /** @const {number} */ es3fShaderDerivateTests.FBO_HEIGHT = 133;
73     /** @const {number} */ es3fShaderDerivateTests.MAX_FAILED_MESSAGES = 10;
74     /** @const {number} */ es3fShaderDerivateTests.INTERPOLATION_LOST_BITS = 3; // number mantissa of bits allowed to be lost in varying interpolation
75     /**
76      * @enum {number}
77      */
78     es3fShaderDerivateTests.DerivateFunc = {
79         DFDX: 0,
80         DFDY: 1,
81         FWIDTH: 2
82     };
84     /**
85      * @enum {number}
86      */
87     es3fShaderDerivateTests.SurfaceType = {
88         DEFAULT_FRAMEBUFFER: 0,
89         UNORM_FBO: 1,
90         FLOAT_FBO: 2 // \note Uses RGBA32UI fbo actually, since FP rendertargets are not in core spec.
91     };
93     /**
94      * @enum {number}
95      */
96     es3fShaderDerivateTests.VerificationLogging = {
97         LOG_ALL: 0,
98         LOG_NOTHING: 1
99     };
101     /**
102      * @param {es3fShaderDerivateTests.DerivateFunc} func
103      * @return {string}
104      */
105     es3fShaderDerivateTests.getDerivateFuncName = function(func) {
106         switch (func) {
107             case es3fShaderDerivateTests.DerivateFunc.DFDX: return 'dFdx';
108             case es3fShaderDerivateTests.DerivateFunc.DFDY: return 'dFdy';
109             case es3fShaderDerivateTests.DerivateFunc.FWIDTH: return 'fwidth';
110             default: throw new Error('Derivate Func not supported.');
111         }
112     };
114     /**
115      * @param {es3fShaderDerivateTests.DerivateFunc} func
116      * @return {string}
117      */
118     es3fShaderDerivateTests.getDerivateFuncCaseName = function(func) {
119         switch (func) {
120             case es3fShaderDerivateTests.DerivateFunc.DFDX: return 'dfdx';
121             case es3fShaderDerivateTests.DerivateFunc.DFDY: return 'dfdy';
122             case es3fShaderDerivateTests.DerivateFunc.FWIDTH: return 'fwidth';
123             default: throw new Error('Derivate Func not supported.');
124         }
125     };
127     /**
128      * @param {?gluShaderUtil.DataType} type
129      * @return {Array<boolean>}
130      */
131     es3fShaderDerivateTests.getDerivateMask = function(type) {
132         switch (type) {
133             case gluShaderUtil.DataType.FLOAT: return [true, false, false, false];
134             case gluShaderUtil.DataType.FLOAT_VEC2: return [true, true, false, false];
135             case gluShaderUtil.DataType.FLOAT_VEC3: return [true, true, true, false];
136             case gluShaderUtil.DataType.FLOAT_VEC4: return [true, true, true, true];
137             default: throw new Error('Data Type not supported.');
138         }
139     };
141     /**
142      * @param {tcuTexture.ConstPixelBufferAccess} surface
143      * @param {Array<number>} derivScale
144      * @param {Array<number>} derivBias
145      * @param {number} x
146      * @param {number} y
147      * @return {Array<number>}
148      */
149     es3fShaderDerivateTests.readDerivate = function(surface, derivScale, derivBias, x, y) {
150         return deMath.divide(deMath.subtract(surface.getPixel(x, y), derivBias), derivScale);
151     };
153     /**
154      * @param {Array<number>} v
155      * @return {Array<number>}
156      */
157     es3fShaderDerivateTests.getCompExpBits = function(v) {
158         return [tcuFloat.newFloat32(v[0]).exponentBits(),
159             tcuFloat.newFloat32(v[1]).exponentBits(),
160             tcuFloat.newFloat32(v[2]).exponentBits(),
161             tcuFloat.newFloat32(v[3]).exponentBits()];
162     };
164     /**
165      * @param {number} value
166      * @param {number} numAccurateBits
167      * @return {number}
168      */
169     es3fShaderDerivateTests.computeFloatingPointError = function(value, numAccurateBits) {
170         /** @type {number} */ var numGarbageBits = 23 - numAccurateBits;
171         /** @type {number} */ var mask = (1 << numGarbageBits) - 1 ;
172         /** @type {number} */ var exp = tcuFloat.newFloat32(value).exponent();
174         return (new tcuFloat.deFloat()).construct(1, exp, (1 << 23) | mask).getValue() - (new tcuFloat.deFloat()).construct(1, exp, 1 << 23).getValue();
175     };
177     /**
178        * @param {?gluShaderUtil.precision} precision
179      * @return {number}
180      */
181     es3fShaderDerivateTests.getNumMantissaBits = function(precision) {
182         switch (precision) {
183             case gluShaderUtil.precision.PRECISION_HIGHP: return 23;
184             case gluShaderUtil.precision.PRECISION_MEDIUMP: return 10;
185             case gluShaderUtil.precision.PRECISION_LOWP: return 6;
186             default:
187                 throw new Error('Precision not supported: ' + precision);
188         }
189     };
191     /**
192      * @param {?gluShaderUtil.precision} precision
193      * @return {number}
194      */
195     es3fShaderDerivateTests.getMinExponent = function(precision) {
196         switch (precision) {
197             case gluShaderUtil.precision.PRECISION_HIGHP: return -126;
198             case gluShaderUtil.precision.PRECISION_MEDIUMP: return -14;
199             case gluShaderUtil.precision.PRECISION_LOWP: return -8;
200             default:
201                 throw new Error('Precision not supported: ' + precision);
202         }
203     };
205     /**
206      * @param {number} exp
207      * @param {number} numMantissaBits
208      * @return {number}
209      */
210     es3fShaderDerivateTests.getSingleULPForExponent = function(exp, numMantissaBits) {
211         if (numMantissaBits > 0) {
212             assertMsgOptions(numMantissaBits <= 23, 'numMantissaBits must be less or equal than 23.', false, true);
214             /** @type {number} */ var ulpBitNdx = 23 - numMantissaBits;
216             return (new tcuFloat.deFloat()).construct(1, exp, (1 << 23) | (1 << ulpBitNdx)).getValue() - (new tcuFloat.deFloat()).construct(1, exp, 1 << 23).getValue();
217         } else {
218             assertMsgOptions(numMantissaBits === 0, 'numMantissaBits must equal to 0.', false, true);
219             return (new tcuFloat.deFloat()).construct(1, exp, (1 << 23)).getValue()
220         }
221     };
223     /**
224      * @param {number} value
225      * @param {number} numMantissaBits
226      * @return {number}
227      */
228     es3fShaderDerivateTests.getSingleULPForValue = function(value, numMantissaBits) {
229         /** @type {number} */ var exp = (new tcuFloat.deFloat().deFloatNumber(value)).exponent();
230         return es3fShaderDerivateTests.getSingleULPForExponent(exp, numMantissaBits);
231     };
233     /**
234      * @param {number} value
235      * @param {number} minExponent
236      * @param {number} numAccurateBits
237      * @return {number}
238      */
239     es3fShaderDerivateTests.convertFloorFlushToZero = function(value, minExponent, numAccurateBits) {
240         if (value === 0.0) {
241             return 0.0;
242         } else {
243             /** @type {tcuFloat.deFloat} */ var inputFloat = new tcuFloat.deFloat().deFloatNumber(value);
244             /** @type {number} */ var numTruncatedBits = 23 - numAccurateBits;
245             /** @type {number} */ var truncMask = (1 << numTruncatedBits) - 1;
247             if (value > 0.0) {
248                 if (value > 0.0 && (new tcuFloat.deFloat().deFloatNumber(value)).exponent() < minExponent) {
249                     // flush to zero if possible
250                     return 0.0;
251                 } else {
252                     // just mask away non-representable bits
253                     return (new tcuFloat.deFloat()).construct(1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).getValue();
254                 }
255             } else {
256                 if (inputFloat.mantissa() & truncMask) {
257                     // decrement one ulp if truncated bits are non-zero (i.e. if value is not representable)
258                     return (new tcuFloat.deFloat()).construct(-1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).getValue() - es3fShaderDerivateTests.getSingleULPForExponent(inputFloat.exponent(), numAccurateBits);
259                 } else {
260                     // value is representable, no need to do anything
261                     return value;
262                 }
263             }
264         }
265     };
267     /**
268      * @param {number} value
269      * @param {number} minExponent
270      * @param {number} numAccurateBits
271      * @return {number}
272      */
273     es3fShaderDerivateTests.convertCeilFlushToZero = function(value, minExponent, numAccurateBits) {
274         return -es3fShaderDerivateTests.convertFloorFlushToZero(-value, minExponent, numAccurateBits);
275     };
277     /**
278      * @param {number} value
279      * @param {number} numUlps
280      * @param {number} numMantissaBits
281      * @return {number}
282      */
283     es3fShaderDerivateTests.addErrorUlp = function(value, numUlps, numMantissaBits) {
284         return value + numUlps * es3fShaderDerivateTests.getSingleULPForValue(value, numMantissaBits);
285     };
287     /**
288      * @param {?gluShaderUtil.precision} precision
289      * @param {Array<number>} valueMin
290      * @param {Array<number>} valueMax
291      * @param {Array<number>} expectedDerivate
292      * @return {Array<number>}
293      */
294     es3fShaderDerivateTests.getDerivateThreshold = function(precision, valueMin, valueMax, expectedDerivate) {
295         /** @type {number} */ var baseBits = es3fShaderDerivateTests.getNumMantissaBits(precision);
296         /** @type {Array<number>} */ var derivExp = es3fShaderDerivateTests.getCompExpBits(expectedDerivate);
297         /** @type {Array<number>} */ var maxValueExp = deMath.max(es3fShaderDerivateTests.getCompExpBits(valueMin), es3fShaderDerivateTests.getCompExpBits(valueMax));
298         /** @type {Array<number>} */ var numBitsLost = deMath.subtract(maxValueExp, deMath.min(maxValueExp, derivExp));
299         /** @type {Array<number>} */
300         var numAccurateBits = deMath.max(
301             deMath.addScalar(
302                 deMath.subtract(
303                     [baseBits, baseBits, baseBits, baseBits],
304                     numBitsLost),
305                 -es3fShaderDerivateTests.INTERPOLATION_LOST_BITS),
306             [0, 0, 0, 0]);
308         return [es3fShaderDerivateTests.computeFloatingPointError(expectedDerivate[0], numAccurateBits[0]),
309                 es3fShaderDerivateTests.computeFloatingPointError(expectedDerivate[1], numAccurateBits[1]),
310                 es3fShaderDerivateTests.computeFloatingPointError(expectedDerivate[2], numAccurateBits[2]),
311                 es3fShaderDerivateTests.computeFloatingPointError(expectedDerivate[3], numAccurateBits[3])];
312     };
314     /**
315      * @param {tcuTexture.ConstPixelBufferAccess} result
316      * @param {tcuTexture.PixelBufferAccess} errorMask
317      * @param {?gluShaderUtil.DataType} dataType
318      * @param {Array<number>} reference
319      * @param {Array<number>} threshold
320      * @param {Array<number>} scale
321      * @param {Array<number>} bias
322      * @param {es3fShaderDerivateTests.VerificationLogging=} logPolicy
323      * @return {boolean}
324      */
325     es3fShaderDerivateTests.verifyConstantDerivate = function(result, errorMask, dataType, reference, threshold, scale, bias, logPolicy) {
326         logPolicy = logPolicy === undefined ? es3fShaderDerivateTests.VerificationLogging.LOG_ALL : logPolicy;
327         /** @type {Array<boolean>} */ var mask = deMath.logicalNotBool(es3fShaderDerivateTests.getDerivateMask(dataType));
328         /** @type {number} */ var numFailedPixels = 0;
330         if (logPolicy === es3fShaderDerivateTests.VerificationLogging.LOG_ALL)
331             bufferedLogToConsole('Expecting ' + reference + ' with threshold ' + threshold);
333         for (var y = 0; y < result.getHeight(); y++) {
334             for (var x = 0; x < result.getWidth(); x++) {
335                 /** @type {Array<number>} */ var resDerivate = es3fShaderDerivateTests.readDerivate(result, scale, bias, x, y);
336                 /** @type {boolean} */
337                 var isOk = deMath.boolAll(
338                     deMath.logicalOrBool(
339                         deMath.lessThanEqual(
340                             deMath.abs(deMath.subtract(reference, resDerivate)),
341                             threshold),
342                         mask));
344                 if (!isOk) {
345                     if (numFailedPixels < es3fShaderDerivateTests.MAX_FAILED_MESSAGES && logPolicy === es3fShaderDerivateTests.VerificationLogging.LOG_ALL)
346                         bufferedLogToConsole('FAIL: got ' + resDerivate + ', diff = ' + deMath.abs(deMath.subtract(reference, resDerivate)) + ', at x = ' + x + ', y = ' + y);
347                     numFailedPixels += 1;
348                     errorMask.setPixel(tcuRGBA.RGBA.red.toVec(), x, y);
349                 }
350             }
351         }
353         if (numFailedPixels >= es3fShaderDerivateTests.MAX_FAILED_MESSAGES && logPolicy === es3fShaderDerivateTests.VerificationLogging.LOG_ALL)
354             bufferedLogToConsole('...');
356         if (numFailedPixels > 0 && logPolicy === es3fShaderDerivateTests.VerificationLogging.LOG_ALL)
357             bufferedLogToConsole('FAIL: found ' + numFailedPixels + ' failed pixels');
359         return numFailedPixels === 0;
360     };
362     /**
363      *      .-----.
364      *      | s_x |
365      *  M x | s_y |
366      *      | 1.0 |
367      *      '-----'
368      * @struct
369      * @constructor
370      */
371     es3fShaderDerivateTests.Linear2DFunctionEvaluator = function() {
372         /** @type {tcuMatrix.Matrix} */ this.matrix = new tcuMatrix.Matrix(4, 3);
373     };
375     es3fShaderDerivateTests.Linear2DFunctionEvaluator.prototype.evaluateAt = function(screenX, screenY) {
376         /** @type {Array<number>} */ var position = [screenX, screenY, 1.0];
377         return tcuMatrix.multiplyMatVec(this.matrix, position);
378     };
380     /**
381      * @param {tcuTexture.ConstPixelBufferAccess} result
382      * @param {tcuTexture.PixelBufferAccess} errorMask
383      * @param {?gluShaderUtil.DataType} dataType
384      * @param {?gluShaderUtil.precision} precision
385      * @param {Array<number>} derivScale
386      * @param {Array<number>} derivBias
387      * @param {Array<number>} surfaceThreshold
388      * @param {es3fShaderDerivateTests.DerivateFunc} derivateFunc
389      * @param {es3fShaderDerivateTests.Linear2DFunctionEvaluator} func
390      * @return {boolean}
391      */
392     es3fShaderDerivateTests.reverifyConstantDerivateWithFlushRelaxations = function(result, errorMask, dataType, precision, derivScale, derivBias, surfaceThreshold, derivateFunc, func) {
393         assertMsgOptions(result.getWidth() === errorMask.getWidth(), 'Dimensions of result and errorMask inconsistent.', false, true);
394         assertMsgOptions(result.getHeight() === errorMask.getHeight(), 'Dimensions of result and errorMask inconsistent.', false, true);
395         assertMsgOptions(derivateFunc === es3fShaderDerivateTests.DerivateFunc.DFDX || derivateFunc === es3fShaderDerivateTests.DerivateFunc.DFDY, 'Derivate Function should be DFDX or DFDY.', false, true);
397         /** @type {Array<number>} */ var red = [255, 0, 0, 255];
398         /** @type {Array<number>} */ var green = [0, 255, 0, 255];
399         /** @type {number} */ var divisionErrorUlps = 2.5;
401         /** @type {number} */ var numComponents = gluShaderUtil.getDataTypeScalarTypeAsDataType(dataType);
402         /** @type {number} */ var numBits = es3fShaderDerivateTests.getNumMantissaBits(precision);
403         /** @type {number} */ var minExponent = es3fShaderDerivateTests.getMinExponent(precision);
405         /** @type {number} */ var numVaryingSampleBits = numBits - es3fShaderDerivateTests.INTERPOLATION_LOST_BITS;
406         /** @type {number} */ var numFailedPixels = 0;
408         errorMask.clear(green);
410         // search for failed pixels
411         for (var y = 0; y < result.getHeight(); ++y)
412         for (var x = 0; x < result.getWidth(); ++x) {
413             //                 flushToZero?(f2z?(functionValueCurrent) - f2z?(functionValueBefore))
414             // flushToZero? ( ------------------------------------------------------------------------ +- 2.5 ULP )
415             //                                                  dx
417             /** @type {Array<number>} */ var resultDerivative = es3fShaderDerivateTests.readDerivate(result, derivScale, derivBias, x, y);
419             // sample at the front of the back pixel and the back of the front pixel to cover the whole area of
420             // legal sample positions. In general case this is NOT OK, but we know that the target funtion is
421             // (mostly*) linear which allows us to take the sample points at arbitrary points. This gets us the
422             // maximum difference possible in exponents which are used in error bound calculations.
423             // * non-linearity may happen around zero or with very high function values due to subnorms not
424             //   behaving well.
425             /** @type {Array<number>} */ var functionValueForward = (derivateFunc === es3fShaderDerivateTests.DerivateFunc.DFDX) ?
426                                                         (func.evaluateAt(x + 2.0, y + 0.5)) :
427                                                         (func.evaluateAt(x + 0.5, y + 2.0));
428             /** @type {Array<number>} */ var functionValueBackward = (derivateFunc === es3fShaderDerivateTests.DerivateFunc.DFDX) ?
429                                                         (func.evaluateAt(x - 1.0, y + 0.5)) :
430                                                         (func.evaluateAt(x + 0.5, y - 1.0));
432             /** @type {boolean} */ var anyComponentFailed = false;
434             // check components separately
435             for (var c = 0; c < numComponents; ++c) {
436                 // interpolation value range
437                 /** @type {tcuInterval.Interval} */ var forwardComponent = tcuInterval.withIntervals(
438                     new tcuInterval.Interval(es3fShaderDerivateTests.convertFloorFlushToZero(
439                         es3fShaderDerivateTests.addErrorUlp(functionValueForward[c], -0.5, numVaryingSampleBits), minExponent, numBits)),
440                     new tcuInterval.Interval(es3fShaderDerivateTests.convertCeilFlushToZero(
441                         es3fShaderDerivateTests.addErrorUlp(functionValueForward[c], +0.5, numVaryingSampleBits), minExponent, numBits))
442                 );
444                 /** @type {tcuInterval.Interval} */ var backwardComponent = tcuInterval.withIntervals(
445                     new tcuInterval.Interval(es3fShaderDerivateTests.convertFloorFlushToZero(
446                         es3fShaderDerivateTests.addErrorUlp(functionValueBackward[c], -0.5, numVaryingSampleBits), minExponent, numBits)),
447                     new tcuInterval.Interval(es3fShaderDerivateTests.convertCeilFlushToZero(
448                         es3fShaderDerivateTests.addErrorUlp(functionValueBackward[c], +0.5, numVaryingSampleBits), minExponent, numBits))
449                 );
451                 /** @type {number} */
452                 var maxValueExp = Math.max(
453                         (new tcuFloat.deFloat().deFloatNumber(forwardComponent.lo())).exponent(),
454                         (new tcuFloat.deFloat().deFloatNumber(forwardComponent.hi())).exponent(),
455                         (new tcuFloat.deFloat().deFloatNumber(backwardComponent.lo())).exponent(),
456                         (new tcuFloat.deFloat().deFloatNumber(backwardComponent.hi())).exponent());
458                 // subtraction in nominator will likely cause a cancellation of the most
459                 // significant bits. Apply error bounds.
460                 /** @type {tcuInterval.Interval} */ var nominator = tcuInterval.Interval.operatorSub(forwardComponent, backwardComponent);
461                 /** @type {number} */ var nominatorLoExp = (new tcuFloat.deFloat().deFloatNumber(nominator.lo())).exponent();
462                 /** @type {number} */ var nominatorHiExp = (new tcuFloat.deFloat().deFloatNumber(nominator.hi())).exponent();
463                 /** @type {number} */ var nominatorLoBitsLost = maxValueExp - nominatorLoExp;
464                 /** @type {number} */ var nominatorHiBitsLost = maxValueExp - nominatorHiExp;
465                 /** @type {number} */ var nominatorLoBits = Math.max(0, numBits - nominatorLoBitsLost);
466                 /** @type {number} */ var nominatorHiBits = Math.max(0, numBits - nominatorHiBitsLost);
468                 /** @type {tcuInterval.Interval} */ var nominatorRange = tcuInterval.withIntervals(
469                     new tcuInterval.Interval(es3fShaderDerivateTests.convertFloorFlushToZero(nominator.lo(), minExponent, nominatorLoBits)),
470                     new tcuInterval.Interval(es3fShaderDerivateTests.convertCeilFlushToZero(nominator.hi(), minExponent, nominatorHiBits)));
471                 //
472                 /** @type {tcuInterval.Interval} */ var divisionRange = tcuInterval.Interval.operatorDiv(nominatorRange, new tcuInterval.Interval(3.0)); // legal sample area is anywhere within this and neighboring pixels (i.e. size = 3)
473                 /** @type {tcuInterval.Interval} */ var divisionResultRange = tcuInterval.withIntervals(
474                     new tcuInterval.Interval(es3fShaderDerivateTests.convertFloorFlushToZero(es3fShaderDerivateTests.addErrorUlp(divisionRange.lo(), -divisionErrorUlps, numBits), minExponent, numBits)),
475                     new tcuInterval.Interval(es3fShaderDerivateTests.convertCeilFlushToZero(es3fShaderDerivateTests.addErrorUlp(divisionRange.hi(), divisionErrorUlps, numBits), minExponent, numBits)));
476                 /** @type {tcuInterval.Interval} */ var finalResultRange = tcuInterval.withIntervals(
477                     new tcuInterval.Interval(divisionResultRange.lo() - surfaceThreshold[c]),
478                     new tcuInterval.Interval(divisionResultRange.hi() + surfaceThreshold[c]));
480                 if (resultDerivative[c] >= finalResultRange.lo() && resultDerivative[c] <= finalResultRange.hi()) {
481                     // value ok
482                 } else {
483                     if (numFailedPixels < es3fShaderDerivateTests.MAX_FAILED_MESSAGES)
484                         bufferedLogToConsole('Error in pixel at ' + x + ', ' + y + ' with component ' + c + ' (channel ' + ('rgba'[c]) + ')\n' +
485                             '\tGot pixel value ' + result.getPixelInt(x, y) + '\n' +
486                             '\t\tdFd' + ((derivateFunc === es3fShaderDerivateTests.DerivateFunc.DFDX) ? 'x' : 'y') + ' ~= ' + resultDerivative[c] + '\n' +
487                             '\t\tdifference to a valid range: ' +
488                             ((resultDerivative[c] < finalResultRange.lo()) ? '-' : '+') +
489                             ((resultDerivative[c] < finalResultRange.lo()) ? (finalResultRange.lo() - resultDerivative[c]) : (resultDerivative[c] - finalResultRange.hi())) +
490                             '\n' +
491                             '\tDerivative value range:\n' +
492                             '\t\tMin: ' + finalResultRange.lo() + '\n' +
493                             '\t\tMax: ' + finalResultRange.hi() + '\n');
495                     ++numFailedPixels;
496                     anyComponentFailed = true;
497                 }
498             }
500             if (anyComponentFailed)
501                 errorMask.setPixel(red, x, y);
502         }
504         if (numFailedPixels >= es3fShaderDerivateTests.MAX_FAILED_MESSAGES)
505             bufferedLogToConsole('...');
507         if (numFailedPixels > 0)
508             bufferedLogToConsole('FAIL: found ' + numFailedPixels + ' failed pixels');
510         return numFailedPixels === 0;
511     };
513     /**
514      * @constructor
515      * @extends {tcuTestCase.DeqpTest}
516      * @param {string} name
517      * @param {string} description
518      */
519     es3fShaderDerivateTests.TriangleDerivateCase = function(name, description) {
520         tcuTestCase.DeqpTest.call(this, name, description);
521         /** @type {?gluShaderUtil.DataType} */ this.m_dataType = null;
522         /** @type {?gluShaderUtil.precision} */ this.m_precision = null;
524         /** @type {?gluShaderUtil.DataType} */ this.m_coordDataType = null;
525         /** @type {?gluShaderUtil.precision} */ this.m_coordPrecision = null;
527         /** @type {string} */ this.m_fragmentSrc;
529         /** @type {Array<number>} */ this.m_coordMin = [];
530         /** @type {Array<number>} */ this.m_coordMax = [];
531         /** @type {Array<number>} */ this.m_derivScale = [];
532         /** @type {Array<number>} */ this.m_derivBias = [];
534         /** @type {es3fShaderDerivateTests.SurfaceType} */ this.m_surfaceType = es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER;
535         /** @type {number} */ this.m_numSamples = 0;
536         /** @type {number} */ this.m_hint = gl.DONT_CARE;
538         assertMsgOptions(this.m_surfaceType !== es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER || this.m_numSamples === 0, 'Did not expect surfaceType = DEFAULT_FRAMEBUFFER or numSamples = 0', false, true);
539     };
541     es3fShaderDerivateTests.TriangleDerivateCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
542     es3fShaderDerivateTests.TriangleDerivateCase.prototype.constructor = es3fShaderDerivateTests.TriangleDerivateCase;
544     es3fShaderDerivateTests.TriangleDerivateCase.prototype.deinit = function() {};
546     /** @param {WebGLProgram} program */
547     es3fShaderDerivateTests.TriangleDerivateCase.prototype.setupRenderState = function(program) {};
549     /**
550      * @param {?gluShaderUtil.DataType} coordType
551      * @param {?gluShaderUtil.precision} precision
552      * @return {string}
553      */
554     es3fShaderDerivateTests.genVertexSource = function(coordType, precision) {
555         assertMsgOptions(gluShaderUtil.isDataTypeFloatOrVec(coordType), 'Coord Type not supported', false, true);
557         /** @type {string} */ var vertexTmpl = '' +
558             '#version 300 es\n' +
559             'in highp vec4 a_position;\n' +
560             'in ${PRECISION} ${DATATYPE} a_coord;\n' +
561             'out ${PRECISION} ${DATATYPE} v_coord;\n' +
562             'void main (void)\n' +
563             '{\n' +
564             ' gl_Position = a_position;\n' +
565             ' v_coord = a_coord;\n' +
566             '}\n';
568         /** @type {Object} */ var vertexParams = {};
570         vertexParams['PRECISION'] = gluShaderUtil.getPrecisionName(precision);
571         vertexParams['DATATYPE'] = gluShaderUtil.getDataTypeName(coordType);
573         return tcuStringTemplate.specialize(vertexTmpl, vertexParams);
574     };
576     /**
577      * @return {Array<number>}
578      */
579     es3fShaderDerivateTests.TriangleDerivateCase.prototype.getViewportSize = function() {
580         if (this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER) {
581             /** @type {number} */ var width = Math.min(gl.drawingBufferWidth, es3fShaderDerivateTests.VIEWPORT_WIDTH);
582             /** @type {number} */ var height = Math.min(gl.drawingBufferHeight, es3fShaderDerivateTests.VIEWPORT_HEIGHT);
583             return [width, height];
584         } else
585             return [es3fShaderDerivateTests.FBO_WIDTH, es3fShaderDerivateTests.FBO_HEIGHT];
586     };
588     /**
589      * @return {tcuTestCase.IterateResult}
590      */
591     es3fShaderDerivateTests.TriangleDerivateCase.prototype.iterate = function() {
592         /** @type {gluShaderProgram.ShaderProgram} */ var program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(es3fShaderDerivateTests.genVertexSource(this.m_coordDataType, this.m_coordPrecision), this.m_fragmentSrc));
593         /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xbbc24);
594         /** @type {boolean} */ var useFbo = this.m_surfaceType != es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER;
595         /** @type {number} */ var fboFormat = this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.FLOAT_FBO ? gl.RGBA32UI : gl.RGBA8;
596         /** @type {Array<number>} */ var viewportSize = this.getViewportSize();
597         /** @type {number} */ var viewportX = useFbo ? 0 : rnd.getInt(0, gl.drawingBufferWidth - viewportSize[0]);
598         /** @type {number} */ var viewportY = useFbo ? 0 : rnd.getInt(0, gl.drawingBufferHeight - viewportSize[1]);
599         /** @type {?WebGLFramebuffer} */ var fbo = null;
600         /** @type {?WebGLRenderbuffer} */ var rbo = null;
601         /** @type {tcuTexture.TextureLevel} */ var result = null;
603         bufferedLogToConsole(program.getProgramInfo().infoLog);
605         if (!program.isOk())
606             assertMsgOptions(false, 'Compile failed', false, true);
608         if (useFbo) {
609             bufferedLogToConsole('Rendering to FBO, format = ' + wtu.glEnumToString(gl, fboFormat) + ', samples = ' + this.m_numSamples);
611             fbo = gl.createFramebuffer();
612             rbo = gl.createRenderbuffer();
614             gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
615             gl.renderbufferStorageMultisample(gl.RENDERBUFFER, this.m_numSamples, fboFormat, viewportSize[0], viewportSize[1]);
616             gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
617             gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
618         } else {
619             /** @type {tcuPixelFormat.PixelFormat} */ var pixelFormat = tcuPixelFormat.PixelFormatFromContext(gl);
621             bufferedLogToConsole('Rendering to default framebuffer\n' +
622                 '\tColor depth: R=' + pixelFormat.redBits + ', G=' + pixelFormat.greenBits + ', B=' + pixelFormat.blueBits + ', A=' + pixelFormat.alphaBits);
623         }
625         bufferedLogToConsole('in: ' + this.m_coordMin + ' ' + this.m_coordMax + '\n' +
626             'v_coord.x = in.x * x\n' +
627             'v_coord.y = in.y * y\n' +
628             'v_coord.z = in.z * (x+y)/2\n' +
629             'v_coord.w = in.w * (1 - (x+y)/2)\n' +
630             '\n' +
631             'u_scale: ' + this.m_derivScale + ', u_bias: ' + this.m_derivBias + ' (displayed values have scale/bias removed)' +
632             'Viewport: ' + viewportSize[0] + 'x' + viewportSize[1] +
633             'gl.FRAGMENT_SHADER_DERIVATE_HINT: ' + wtu.glEnumToString(gl, this.m_hint));
634         // Draw
635         /** @type {Array<number>} */ var positions = [
636             -1.0, -1.0, 0.0, 1.0,
637             -1.0, 1.0, 0.0, 1.0,
638             1.0, -1.0, 0.0, 1.0,
639             1.0, 1.0, 0.0, 1.0
640         ];
642         /** @type {Array<number>} */ var coords =[
643             this.m_coordMin[0], this.m_coordMin[1], this.m_coordMin[2], this.m_coordMax[3],
644             this.m_coordMin[0], this.m_coordMax[1], (this.m_coordMin[2] + this.m_coordMax[2]) * 0.5, (this.m_coordMin[3]+this.m_coordMax[3]) * 0.5,
645             this.m_coordMax[0], this.m_coordMin[1], (this.m_coordMin[2] + this.m_coordMax[2]) * 0.5, (this.m_coordMin[3]+this.m_coordMax[3]) * 0.5,
646             this.m_coordMax[0], this.m_coordMax[1], this.m_coordMax[2], this.m_coordMin[3]
647         ];
649         /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [
650             gluDrawUtil.newFloatVertexArrayBinding('a_position', 4, 4, 0, positions),
651             gluDrawUtil.newFloatVertexArrayBinding('a_coord', 4, 4, 0, coords)
652         ];
654         /** @type {Array<number>} */ var indices = [0, 2, 1, 2, 3, 1];
656         gl.clearColor(0.125, 0.25, 0.5, 1.0);
657         // We can't really call clear() on gl.COLOR_BUFFER_BIT here as in c++ deqp.
658         // The fbo format might be of integer type and WebGL2 requires an INVALID_OPERATION to be generated.
659         var formatObj = gluTextureUtil.mapGLInternalFormat(fboFormat);
660         var fmtClass = tcuTexture.getTextureChannelClass(formatObj.type);
661         switch (fmtClass) {
662             case tcuTexture.TextureChannelClass.FLOATING_POINT:
663             case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
664             case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
665                 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
666                 break;
667             case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
668                 gl.clearBufferuiv(gl.COLOR, 0, new Uint32Array([31, 63, 127, 255]));
669                 gl.clear(gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
670                 break;
671             case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
672                 gl.clearBufferiv(gl.COLOR, 0, new Int32Array([31, 63, 127, 255]));
673                 gl.clear(gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
674                 break;
675             default:
676                 throw new Error('Invalid channelclass ' + fmtClass);
677         }
678         gl.disable(gl.DITHER);
680         gl.useProgram(program.getProgram());
682         /** @type {WebGLUniformLocation} */ var scaleLoc = gl.getUniformLocation(program.getProgram(), 'u_scale');
683         /** @type {WebGLUniformLocation} */ var biasLoc = gl.getUniformLocation(program.getProgram(), 'u_bias');
685         switch (this.m_dataType) {
686             case gluShaderUtil.DataType.FLOAT:
687                 gl.uniform1f(scaleLoc, this.m_derivScale[0]);
688                 gl.uniform1f(biasLoc, this.m_derivBias[0]);
689                 break;
691             case gluShaderUtil.DataType.FLOAT_VEC2:
692                 gl.uniform2fv(scaleLoc, this.m_derivScale.slice(0,2));
693                 gl.uniform2fv(biasLoc, this.m_derivBias.slice(0,2));
694                 break;
696             case gluShaderUtil.DataType.FLOAT_VEC3:
697                 gl.uniform3fv(scaleLoc, this.m_derivScale.slice(0,3));
698                 gl.uniform3fv(biasLoc, this.m_derivBias.slice(0,3));
699                 break;
701             case gluShaderUtil.DataType.FLOAT_VEC4:
702                 gl.uniform4fv(scaleLoc, this.m_derivScale);
703                 gl.uniform4fv(biasLoc, this.m_derivBias);
704                 break;
706             default:
707                 throw new Error('Data Type not supported: ' + this.m_dataType);
708         }
710         glsShaderRenderCase.setupDefaultUniforms(program.getProgram());
711         this.setupRenderState(program.getProgram());
713         gl.hint(gl.FRAGMENT_SHADER_DERIVATIVE_HINT, this.m_hint);
715         gl.viewport(viewportX, viewportY, viewportSize[0], viewportSize[1]);
716         gluDrawUtil.draw(gl, program.getProgram(), vertexArrays, gluDrawUtil.triangles(indices));
718         // Read back results
720         /** @type {boolean} */ var isMSAA = useFbo && this.m_numSamples > 0;
721         /** @type {?WebGLFramebuffer} */ var resFbo = null;
722         /** @type {?WebGLRenderbuffer} */ var resRbo = null;
724         // Resolve if necessary
725         if (isMSAA) {
726             resFbo = gl.createFramebuffer();
727             resRbo = gl.createRenderbuffer();
729             gl.bindRenderbuffer(gl.RENDERBUFFER, resRbo);
730             gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 0, fboFormat, viewportSize[0], viewportSize[1]);
731             gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resFbo);
732             gl.framebufferRenderbuffer(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, resRbo);
734             gl.blitFramebuffer(0, 0, viewportSize[0], viewportSize[1], 0, 0, viewportSize[0], viewportSize[1], gl.COLOR_BUFFER_BIT, gl.NEAREST);
736             gl.bindFramebuffer(gl.READ_FRAMEBUFFER, resFbo);
737         }
738         switch (this.m_surfaceType) {
739             case es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER:
740             case es3fShaderDerivateTests.SurfaceType.UNORM_FBO:
741                 var dataFormat = new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
742                 result = new tcuTexture.TextureLevel(dataFormat, viewportSize[0], viewportSize[1]);
743                 gluPixelTransfer.readPixels(gl, viewportX, viewportY, dataFormat, result);
744                 break;
746             case es3fShaderDerivateTests.SurfaceType.FLOAT_FBO:
747                 var dataFormat = new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT);
748                 var transferFormat = new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT32);
749                 result = new tcuTexture.TextureLevel(dataFormat, viewportSize[0], viewportSize[1]);
750                 gluPixelTransfer.readPixels(gl, viewportX, viewportY, transferFormat, result);
751                 break;
753             default:
754                 throw new Error('Surface Type not supported: ' + this.m_surfaceType);
755         }
757         // Verify
758         /** @type {tcuSurface.Surface} */
759         var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight());
761         errorMask.getAccess().clear(tcuRGBA.RGBA.green.toVec());
763         /** @type {boolean} */ var isOk = this.verify(result.getAccess(), errorMask.getAccess());
765         if (!isOk) {
766             tcuLogImage.logImage('Rendered', 'Rendered image', result.getAccess());
767             tcuLogImage.logImage('ErrorMask', 'Error mask', errorMask.getAccess());
768             testFailedOptions('Fail', false);
769         } else
770             testPassedOptions('Pass', true);
772         // Cleaning up buffers
773         gl.deleteFramebuffer(fbo);
774         gl.deleteRenderbuffer(rbo);
775         gl.deleteFramebuffer(resFbo);
776         gl.deleteRenderbuffer(resRbo);
778         return tcuTestCase.IterateResult.STOP;
779     };
781     /**
782      * @return {Array<number>}
783      */
784     es3fShaderDerivateTests.TriangleDerivateCase.prototype.getSurfaceThreshold = function() {
785         switch (this.m_surfaceType) {
786             case es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER:
787                 /** @type {tcuPixelFormat.PixelFormat} */ var pixelFormat = tcuPixelFormat.PixelFormatFromContext(gl);
788                 /** @type {Array<number>} */ var channelBits = [pixelFormat.redBits, pixelFormat.greenBits, pixelFormat.blueBits, pixelFormat.alphaBits];
789                 /** @type {Array<number>} */ var intThreshold = deMath.arrayShiftLeft([1, 1, 1, 1], deMath.subtract([8, 8, 8, 8], channelBits));
790                 /** @type {Array<number>} */ var normThreshold = deMath.scale(intThreshold, 1.0/255.0);
792                 return normThreshold;
794             case es3fShaderDerivateTests.SurfaceType.UNORM_FBO: return deMath.scale([1, 1, 1, 1], 1.0/255.0);
795             case es3fShaderDerivateTests.SurfaceType.FLOAT_FBO: return [0.0, 0.0, 0.0, 0.0];
796             default:
797                 assertMsgOptions(false, 'Surface Type not supported. Falling back to default retun value [0.0, 0.0, 0.0, 0.0]', false, false);
798                 return [0.0, 0.0, 0.0, 0.0];
799         }
800     };
802     /**
803      * @constructor
804      * @extends {es3fShaderDerivateTests.TriangleDerivateCase}
805      * @param {string} name
806      * @param {string} description
807      * @param {es3fShaderDerivateTests.DerivateFunc} func
808      * @param {gluShaderUtil.DataType} type
809      */
810     es3fShaderDerivateTests.ConstantDerivateCase = function(name, description, func, type) {
811         es3fShaderDerivateTests.TriangleDerivateCase.call(this, name, description);
812         /** @type {es3fShaderDerivateTests.DerivateFunc} */ this.m_func = func;
813         this.m_dataType = type;
814         this.m_precision = gluShaderUtil.precision.PRECISION_HIGHP;
815         this.m_coordDataType = this.m_dataType;
816         this.m_coordPrecision = this.m_precision;
817     };
819     es3fShaderDerivateTests.ConstantDerivateCase.prototype = Object.create(es3fShaderDerivateTests.TriangleDerivateCase.prototype);
820     es3fShaderDerivateTests.ConstantDerivateCase.prototype.constructor = es3fShaderDerivateTests.ConstantDerivateCase;
822     es3fShaderDerivateTests.ConstantDerivateCase.prototype.init = function() {
823         /** @type {string} */ var fragmentTmpl = '' +
824             '#version 300 es\n' +
825             'layout(location = 0) out mediump vec4 o_color;\n' +
826             'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
827             'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
828             'void main (void)\n' +
829             '{\n' +
830             ' ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n' +
831             ' o_color = ${CAST_TO_OUTPUT};\n' +
832             '}\n';
834         /** @type {Object} */ var fragmentParams = {};
835         fragmentParams['PRECISION'] = gluShaderUtil.getPrecisionName(this.m_precision);
836         fragmentParams['DATATYPE'] = gluShaderUtil.getDataTypeName(this.m_dataType);
837         fragmentParams['FUNC'] = es3fShaderDerivateTests.getDerivateFuncName(this.m_func);
838         fragmentParams['VALUE'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'vec4(1.0, 7.2, -1e5, 0.0)' :
839             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'vec3(1e2, 8.0, 0.01)' :
840             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'vec2(-0.0, 2.7)' :
841             '7.7';
842         fragmentParams['CAST_TO_OUTPUT'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'res' :
843             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'vec4(res, 1.0)' :
844             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'vec4(res, 0.0, 1.0)' :
845             'vec4(res, 0.0, 0.0, 1.0)';
847         this.m_fragmentSrc = tcuStringTemplate.specialize(fragmentTmpl, fragmentParams);
849         this.m_derivScale = [1e3, 1e3, 1e3, 1e3];
850         this.m_derivBias = [0.5, 0.5, 0.5, 0.5];
851     };
853     /**
854      * @param {tcuTexture.ConstPixelBufferAccess} result
855      * @param {tcuTexture.PixelBufferAccess} errorMask
856      * @return {boolean}
857      */
858     es3fShaderDerivateTests.ConstantDerivateCase.prototype.verify = function(result, errorMask) {
859         /** @type {Array<number>} */ var reference = [0.0, 0.0, 0.0, 0.0]; // Derivate of constant argument should always be 0
860         /** @type {Array<number>} */ var threshold = deMath.divide(this.getSurfaceThreshold(), deMath.abs(this.m_derivScale));
861         return es3fShaderDerivateTests.verifyConstantDerivate(result, errorMask, this.m_dataType,
862             reference, threshold, this.m_derivScale, this.m_derivBias);
863     };
865     /**
866      * @constructor
867      * @extends {es3fShaderDerivateTests.TriangleDerivateCase}
868      * @param {string} name
869      * @param {string} description
870      * @param {es3fShaderDerivateTests.DerivateFunc} func
871      * @param {gluShaderUtil.DataType} type
872      * @param {gluShaderUtil.precision} precision
873      * @param {number} hint
874      * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
875      * @param {number} numSamples
876      * @param {string} fragmentSrcTmpl
877      */
878     es3fShaderDerivateTests.LinearDerivateCase = function(name, description, func, type, precision, hint, surfaceType, numSamples, fragmentSrcTmpl) {
879         es3fShaderDerivateTests.TriangleDerivateCase.call(this, name, description);
880         /** @type {es3fShaderDerivateTests.DerivateFunc} */ this.m_func = func;
881         /** @type {string} */ this.m_fragmentTmpl = fragmentSrcTmpl;
882         this.m_dataType = type;
883         this.m_precision = precision;
884         this.m_coordDataType = this.m_dataType;
885         this.m_coordPrecision = this.m_precision;
886         this.m_hint = hint;
887         this.m_surfaceType = surfaceType;
888         this.m_numSamples = numSamples;
889     };
891     es3fShaderDerivateTests.LinearDerivateCase.prototype = Object.create(es3fShaderDerivateTests.TriangleDerivateCase.prototype);
892     es3fShaderDerivateTests.LinearDerivateCase.prototype.constructor = es3fShaderDerivateTests.LinearDerivateCase;
894     es3fShaderDerivateTests.LinearDerivateCase.prototype.init = function() {
895         /** @type {Array<number>} */ var viewportSize = this.getViewportSize();
896         /** @type {number} */ var w = viewportSize[0];
897         /** @type {number} */ var h = viewportSize[1];
898         /** @type {boolean} */ var packToInt = this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.FLOAT_FBO;
900         /** @type {Object} */ var fragmentParams = {};
901         fragmentParams['OUTPUT_TYPE'] = gluShaderUtil.getDataTypeName(packToInt ? gluShaderUtil.DataType.UINT_VEC4 : gluShaderUtil.DataType.FLOAT_VEC4);
902         fragmentParams['OUTPUT_PREC'] = gluShaderUtil.getPrecisionName(packToInt ? gluShaderUtil.precision.PRECISION_HIGHP : this.m_precision);
903         fragmentParams['PRECISION'] = gluShaderUtil.getPrecisionName(this.m_precision);
904         fragmentParams['DATATYPE'] = gluShaderUtil.getDataTypeName(this.m_dataType);
905         fragmentParams['FUNC'] = es3fShaderDerivateTests.getDerivateFuncName(this.m_func);
907         if (packToInt) {
908             fragmentParams['CAST_TO_OUTPUT'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'floatBitsToUint(res)' :
909                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'floatBitsToUint(vec4(res, 1.0))' :
910                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'floatBitsToUint(vec4(res, 0.0, 1.0))' :
911                 'floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))';
912         } else {
913             fragmentParams['CAST_TO_OUTPUT'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'res' :
914                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'vec4(res, 1.0)' :
915                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'vec4(res, 0.0, 1.0)' :
916                 'vec4(res, 0.0, 0.0, 1.0)';
917         }
919         this.m_fragmentSrc = tcuStringTemplate.specialize(this.m_fragmentTmpl, fragmentParams);
921         switch (this.m_precision) {
922             case gluShaderUtil.precision.PRECISION_HIGHP:
923                 this.m_coordMin = [-97., 0.2, 71., 74.];
924                 this.m_coordMax = [-13.2, -77., 44., 76.];
925                 break;
927             case gluShaderUtil.precision.PRECISION_MEDIUMP:
928                 this.m_coordMin = [-37.0, 47., -7., 0.0];
929                 this.m_coordMax = [-1.0, 12., 7., 19.];
930                 break;
932             case gluShaderUtil.precision.PRECISION_LOWP:
933                 this.m_coordMin = [0.0, -1.0, 0.0, 1.0];
934                 this.m_coordMax = [1.0, 1.0, -1.0, -1.0];
935                 break;
937             default:
938                 throw new Error('Precision not supported: ' + this.m_precision);
939         }
941         if (this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.FLOAT_FBO) {
942             // No scale or bias used for accuracy.
943             this.m_derivScale = [1.0, 1.0, 1.0, 1.0];
944             this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
945         } else {
946             // Compute scale - bias that normalizes to 0..1 range.
947             /** @type {Array<number>} */ var dx = deMath.divide(deMath.subtract(this.m_coordMax, this.m_coordMin), [w, w, w * 0.5, -w * 0.5]);
948             /** @type {Array<number>} */ var dy = deMath.divide(deMath.subtract(this.m_coordMax, this.m_coordMin), [h, h, h * 0.5, -h * 0.5]);
950             switch (this.m_func) {
951                 case es3fShaderDerivateTests.DerivateFunc.DFDX:
952                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dx);
953                     break;
955                 case es3fShaderDerivateTests.DerivateFunc.DFDY:
956                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dy);
957                     break;
959                 case es3fShaderDerivateTests.DerivateFunc.FWIDTH:
960                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], deMath.add(deMath.abs(dx), deMath.abs(dy)));
961                     break;
963                 default:
964                     throw new Error('Derivate Function not supported: ' + this.m_func);
965             }
967             this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
968         }
969     };
971     /**
972      * @param {tcuTexture.ConstPixelBufferAccess} result
973      * @param {tcuTexture.PixelBufferAccess} errorMask
974      * @return {boolean}
975      */
976     es3fShaderDerivateTests.LinearDerivateCase.prototype.verify = function(result, errorMask) {
977         /** @type {Array<number>} */ var xScale = [1.0, 0.0, 0.5, -0.5];
978         /** @type {Array<number>} */ var yScale = [0.0, 1.0, 0.5, -0.5];
979         /** @type {Array<number>} */ var surfaceThreshold = deMath.divide(this.getSurfaceThreshold(), deMath.abs(this.m_derivScale));
981         /** @type {number} */ var w;
982         /** @type {number} */ var h;
983         /** @type {Array<number>} */ var reference;
984         /** @type {Array<number>} */ var threshold;
986         if (this.m_func === es3fShaderDerivateTests.DerivateFunc.DFDX || this.m_func === es3fShaderDerivateTests.DerivateFunc.DFDY) {
987             /** @type {boolean} */ var isX = this.m_func === es3fShaderDerivateTests.DerivateFunc.DFDX;
988             /** @type {number} */ var div = isX ? result.getWidth() : result.getHeight();
989             /** @type {Array<number>} */ var scale = isX ? xScale : yScale;
990             reference = deMath.multiply(deMath.scale(deMath.subtract(this.m_coordMax, this.m_coordMin), 1/div), scale);
991             /** @type {Array<number>} */ var opThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_coordMin, scale), deMath.multiply(this.m_coordMax, scale), reference);
992             threshold = deMath.max(surfaceThreshold, opThreshold);
993             bufferedLogToConsole('Verifying result image.\n' +
994                 '\tValid derivative is ' + reference + ' with threshold ' + threshold);
996             // short circuit if result is strictly within the normal value error bounds.
997             // This improves performance significantly.
998             if (es3fShaderDerivateTests.verifyConstantDerivate(result, errorMask,
999                 this.m_dataType, reference, threshold, this.m_derivScale,
1000                 this.m_derivBias, es3fShaderDerivateTests.VerificationLogging.LOG_NOTHING)) {
1001                 bufferedLogToConsole('No incorrect derivatives found, result valid.');
1002                 return true;
1003             }
1005             // some pixels exceed error bounds calculated for normal values. Verify that these
1006             // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1008             bufferedLogToConsole('Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n' +
1009                 '\tVerifying each result derivative is within its range of legal result values.');
1011             /** @type {Array<number>} */ var viewportSize = this.getViewportSize();
1012             /** @type {Array<number>} */ var valueRamp = deMath.subtract(this.m_coordMax, this.m_coordMin);
1013             /** @type {es3fShaderDerivateTests.Linear2DFunctionEvaluator} */ var function_ = new es3fShaderDerivateTests.Linear2DFunctionEvaluator();
1014             w = viewportSize[0];
1015             h = viewportSize[1];
1017             function_.matrix.setRow(0, [valueRamp[0] / w, 0.0, this.m_coordMin[0]]);
1018             function_.matrix.setRow(1, [0.0, valueRamp[1] / h, this.m_coordMin[1]]);
1019             function_.matrix.setRow(2, deMath.scale([valueRamp[2] / w, valueRamp[2] / h, this.m_coordMin[2] + this.m_coordMin[2]], 1 / 2.0));
1020             function_.matrix.setRow(3, deMath.scale([-valueRamp[3] / w, -valueRamp[3] / h, this.m_coordMax[3] + this.m_coordMax[3]], 1 / 2.0));
1022             return es3fShaderDerivateTests.reverifyConstantDerivateWithFlushRelaxations(
1023                 result, errorMask, this.m_dataType, this.m_precision, this.m_derivScale,
1024                 this.m_derivBias, surfaceThreshold, this.m_func, function_);
1025         } else {
1026             assertMsgOptions(this.m_func === es3fShaderDerivateTests.DerivateFunc.FWIDTH, 'Expected DerivateFunc.FWIDTH', false, true);
1027             w = result.getWidth();
1028             h = result.getHeight();
1030             /** @type {Array<number>} */ var dx = deMath.multiply(deMath.scale(deMath.subtract(this.m_coordMax, this.m_coordMin), 1 / w), xScale);
1031             /** @type {Array<number>} */ var dy = deMath.multiply(deMath.scale(deMath.subtract(this.m_coordMax, this.m_coordMin), 1 / h), yScale);
1032             reference = deMath.add(deMath.abs(dx), deMath.abs(dy));
1033             /** @type {Array<number>} */ var dxThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_coordMin, xScale), deMath.multiply(this.m_coordMax, xScale), dx);
1034             /** @type {Array<number>} */ var dyThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_coordMin, yScale), deMath.multiply(this.m_coordMax, yScale), dy);
1035             threshold = deMath.max(surfaceThreshold, deMath.max(dxThreshold, dyThreshold));
1037             return es3fShaderDerivateTests.verifyConstantDerivate(result, errorMask, this.m_dataType,
1038                                           reference, threshold, this.m_derivScale, this.m_derivBias);
1039         }
1040     };
1042     /**
1043      * @constructor
1044      * @extends {es3fShaderDerivateTests.TriangleDerivateCase}
1045      * @param {string} name
1046      * @param {string} description
1047      * @param {es3fShaderDerivateTests.DerivateFunc} func
1048      * @param {gluShaderUtil.DataType} type
1049      * @param {gluShaderUtil.precision} precision
1050      * @param {number} hint
1051      * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1052      * @param {number} numSamples
1053      */
1054     es3fShaderDerivateTests.TextureDerivateCase = function(name, description, func, type, precision, hint, surfaceType, numSamples) {
1055         es3fShaderDerivateTests.TriangleDerivateCase.call(this, name, description);
1056         /** @type {es3fShaderDerivateTests.DerivateFunc} */ this.m_func = func;
1057         /** @type {gluTexture.Texture2D} */ this.m_texture = null;
1058         /** @type {Array<number>} */ this.m_texValueMin = [];
1059         /** @type {Array<number>} */ this.m_texValueMax = [];
1060         this.m_dataType = type;
1061         this.m_precision = precision;
1062         this.m_coordDataType = gluShaderUtil.DataType.FLOAT_VEC2;
1063         this.m_coordPrecision = gluShaderUtil.precision.PRECISION_HIGHP;
1064         this.m_hint = hint;
1065         this.m_surfaceType = surfaceType;
1066         this.m_numSamples = numSamples;
1067     };
1069     es3fShaderDerivateTests.TextureDerivateCase.prototype = Object.create(es3fShaderDerivateTests.TriangleDerivateCase.prototype);
1070     es3fShaderDerivateTests.TextureDerivateCase.prototype.constructor = es3fShaderDerivateTests.TextureDerivateCase;
1072     es3fShaderDerivateTests.TextureDerivateCase.prototype.deinit = function() {
1073             this.m_texture = null;
1074     };
1076     es3fShaderDerivateTests.TextureDerivateCase.prototype.init = function() {
1077         // Generate shader
1078         /** @type {string} */ var fragmentTmpl = '' +
1079             '#version 300 es\n' +
1080             'in highp vec2 v_coord;\n' +
1081             'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1082             'uniform ${PRECISION} sampler2D u_sampler;\n' +
1083             'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1084             'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1085             'void main (void)\n' +
1086             '{\n' +
1087             ' ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n' +
1088             ' ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n' +
1089             ' o_color = ${CAST_TO_OUTPUT};\n' +
1090             '}\n';
1092         /** @type {boolean} */ var packToInt = this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.FLOAT_FBO;
1093         /** @type {Object} */ var fragmentParams = {};
1094         /** @type {Array<number>} */ var viewportSize;
1095         fragmentParams['OUTPUT_TYPE'] = gluShaderUtil.getDataTypeName(packToInt ? gluShaderUtil.DataType.UINT_VEC4 : gluShaderUtil.DataType.FLOAT_VEC4);
1096         fragmentParams['OUTPUT_PREC'] = gluShaderUtil.getPrecisionName(packToInt ? gluShaderUtil.precision.PRECISION_HIGHP : this.m_precision);
1097         fragmentParams['PRECISION'] = gluShaderUtil.getPrecisionName(this.m_precision);
1098         fragmentParams['DATATYPE'] = gluShaderUtil.getDataTypeName(this.m_dataType);
1099         fragmentParams['FUNC'] = es3fShaderDerivateTests.getDerivateFuncName(this.m_func);
1100         fragmentParams['SWIZZLE'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? '' :
1101             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? '.xyz' :
1102             this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? '.xy' :
1103             '.x';
1105         if (packToInt) {
1106             fragmentParams['CAST_TO_OUTPUT'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'floatBitsToUint(res)' :
1107                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'floatBitsToUint(vec4(res, 1.0))' :
1108                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'floatBitsToUint(vec4(res, 0.0, 1.0))' :
1109                 'floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))';
1110         } else {
1111             fragmentParams['CAST_TO_OUTPUT'] = this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC4 ? 'res' :
1112                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC3 ? 'vec4(res, 1.0)' :
1113                 this.m_dataType === gluShaderUtil.DataType.FLOAT_VEC2 ? 'vec4(res, 0.0, 1.0)' :
1114                 'vec4(res, 0.0, 0.0, 1.0)';
1115         }
1117         this.m_fragmentSrc = tcuStringTemplate.specialize(fragmentTmpl, fragmentParams);
1119         // Texture size matches viewport and nearest sampling is used. Thus texture sampling
1120         // is equal to just interpolating the texture value range.
1122         // Determine value range for texture.
1124         switch (this.m_precision) {
1125             case gluShaderUtil.precision.PRECISION_HIGHP:
1126                 this.m_texValueMin = [-97., 0.2, 71., 74.];
1127                 this.m_texValueMax = [-13.2, -77., 44., 76.];
1128                 break;
1130             case gluShaderUtil.precision.PRECISION_MEDIUMP:
1131                 this.m_texValueMin = [-37.0, 47., -7., 0.0];
1132                 this.m_texValueMax = [-1.0, 12., 7., 19.];
1133                 break;
1135             case gluShaderUtil.precision.PRECISION_LOWP:
1136                 this.m_texValueMin = [0.0, -1.0, 0.0, 1.0];
1137                 this.m_texValueMax = [1.0, 1.0, -1.0, -1.0];
1138                 break;
1140             default:
1141                 throw new Error(false, 'Precision not supported:' + this.m_precision);
1142         }
1144         // Lowp and mediump cases use RGBA16F format, while highp uses RGBA32F.
1145         viewportSize = this.getViewportSize();
1146         assertMsgOptions(!this.m_texture, 'Texture not null', false, true);
1147         this.m_texture = gluTexture.texture2DFromInternalFormat(gl, this.m_precision === gluShaderUtil.precision.PRECISION_HIGHP ? gl.RGBA32F : gl.RGBA16F, viewportSize[0], viewportSize[1]);
1148         this.m_texture.getRefTexture().allocLevel(0);
1150         // Texture coordinates
1151         this.m_coordMin = [0.0, 0.0, 0.0, 0.0];
1152         this.m_coordMax = [1.0, 1.0, 1.0, 1.0];
1154         // Fill with gradients.
1155         /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.m_texture.getRefTexture().getLevel(0);
1156         for (var y = 0; y < level0.getHeight(); y++) {
1157             for (var x = 0; x < level0.getWidth(); x++) {
1158                 /** @type {number} */ var xf = (x + 0.5) / level0.getWidth();
1159                 /** @type {number} */ var yf = (y + 0.5) / level0.getHeight();
1160                 /** @type {Array<number>} */ var s = [xf, yf, (xf + yf) / 2.0, 1.0 - (xf + yf) / 2.0];
1162                 level0.setPixel(deMath.add(this.m_texValueMin, deMath.multiply(deMath.subtract(this.m_texValueMax, this.m_texValueMin), s)), x, y);
1163             }
1164         }
1166         this.m_texture.upload();
1168         if (this.m_surfaceType === es3fShaderDerivateTests.SurfaceType.FLOAT_FBO) {
1169             // No scale or bias used for accuracy.
1170             this.m_derivScale = [1.0, 1.0, 1.0, 1.0];
1171             this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
1172         } else {
1173             // Compute scale - bias that normalizes to 0..1 range.
1174             viewportSize = this.getViewportSize();
1175             /** @type {number} */ var w = viewportSize[0];
1176             /** @type {number} */ var h = viewportSize[1];
1177             /** @type {Array<number>} */ var dx = deMath.divide(deMath.subtract(this.m_texValueMax, this.m_texValueMin), [w, w, w * 0.5, -w * 0.5]);
1178             /** @type {Array<number>} */ var dy = deMath.divide(deMath.subtract(this.m_texValueMax, this.m_texValueMin), [h, h, h * 0.5, -h * 0.5]);
1180             switch (this.m_func) {
1181                 case es3fShaderDerivateTests.DerivateFunc.DFDX:
1182                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dx);
1183                     break;
1185                 case es3fShaderDerivateTests.DerivateFunc.DFDY:
1186                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dy);
1187                     break;
1189                 case es3fShaderDerivateTests.DerivateFunc.FWIDTH:
1190                     this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], deMath.add(deMath.abs(dx), deMath.abs(dy)));
1191                     break;
1193                 default:
1194                     throw new Error('Derivate Function not supported: ' + this.m_func);
1195             }
1197             this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
1198         }
1199     };
1201     /**
1202      * @param {WebGLProgram} program
1203      */
1204     es3fShaderDerivateTests.TextureDerivateCase.prototype.setupRenderState = function(program) {
1205         /** @type {number} */ var texUnit = 1;
1207         gl.activeTexture(gl.TEXTURE0 + texUnit);
1208         gl.bindTexture(gl.TEXTURE_2D, this.m_texture.getGLTexture());
1209         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1210         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1211         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1212         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1214         gl.uniform1i(gl.getUniformLocation(program, 'u_sampler'), texUnit);
1215     };
1217     /**
1218      * @param {tcuTexture.PixelBufferAccess} result
1219      * @param {tcuTexture.PixelBufferAccess} errorMask
1220      * @return {boolean}
1221      */
1222     es3fShaderDerivateTests.TextureDerivateCase.prototype.verify = function(result, errorMask) {
1223         // \note Edges are ignored in comparison
1224         if (result.getWidth() < 2 || result.getHeight() < 2)
1225             throw new Error('Too small viewport');
1227         /** @type {tcuTexture.PixelBufferAccess} */ var compareArea = tcuTextureUtil.getSubregion(result, 1, 1, 0, result.getWidth() - 2, result.getHeight() - 2, 1);
1228         /** @type {tcuTexture.PixelBufferAccess} */ var maskArea = tcuTextureUtil.getSubregion(errorMask, 1, 1, 0, errorMask.getWidth() - 2, errorMask.getHeight() - 2, 1);
1229         /** @type {Array<number>} */ var xScale = [1.0, 0.0, 0.5, -0.5];
1230         /** @type {Array<number>} */ var yScale = [0.0, 1.0, 0.5, -0.5];
1231         /** @type {number} */ var w = result.getWidth();
1232         /** @type {number} */ var h = result.getHeight();
1234         /** @type {Array<number>} */ var surfaceThreshold = deMath.divide(this.getSurfaceThreshold(), deMath.abs(this.m_derivScale));
1235         /** @type {Array<number>} */ var reference;
1236         /** @type {Array<number>} */ var threshold;
1237         if (this.m_func == es3fShaderDerivateTests.DerivateFunc.DFDX || this.m_func == es3fShaderDerivateTests.DerivateFunc.DFDY) {
1238             /** @type {boolean} */ var isX = this.m_func == es3fShaderDerivateTests.DerivateFunc.DFDX;
1239             /** @type {number} */ var div = isX ? w : h;
1240             /** @type {Array<number>} */ var scale = isX ? xScale : yScale;
1241             reference = deMath.multiply(deMath.scale(deMath.subtract(this.m_texValueMax, this.m_texValueMin), 1 / div), scale);
1242             /** @type {Array<number>} */ var opThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_texValueMin, scale), deMath.multiply(this.m_texValueMax, scale), reference);
1243             threshold = deMath.max(surfaceThreshold, opThreshold);
1245             bufferedLogToConsole('Verifying result image.\n'+
1246                 '\tValid derivative is ' + reference + ' with threshold ' + threshold);
1248             // short circuit if result is strictly within the normal value error bounds.
1249             // This improves performance significantly.
1250             if (es3fShaderDerivateTests.verifyConstantDerivate(compareArea, maskArea, this.m_dataType,
1251                 reference, threshold, this.m_derivScale, this.m_derivBias,
1252                 es3fShaderDerivateTests.VerificationLogging.LOG_NOTHING)) {
1253                     bufferedLogToConsole('No incorrect derivatives found, result valid.');
1254                     return true;
1255             }
1256             // some pixels exceed error bounds calculated for normal values. Verify that these
1257             // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
1259             bufferedLogToConsole('Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n' +
1260                 '\tVerifying each result derivative is within its range of legal result values.');
1262             /** @type {Array<number>} */ var valueRamp = deMath.subtract(this.m_texValueMax, this.m_texValueMin);
1263             /** @type {es3fShaderDerivateTests.Linear2DFunctionEvaluator} */ var function_ = new es3fShaderDerivateTests.Linear2DFunctionEvaluator();
1265             function_.matrix.setRow(0, [valueRamp[0] / w, 0.0, this.m_texValueMin[0]]);
1266             function_.matrix.setRow(1, [0.0, valueRamp[1] / h, this.m_texValueMin[1]]);
1267             function_.matrix.setRow(2, deMath.scale([valueRamp[2] / w, valueRamp[2] / h, this.m_texValueMin[2] + this.m_texValueMin[2]], 1 / 2.0));
1268             function_.matrix.setRow(3, deMath.scale([-valueRamp[3] / w, -valueRamp[3] / h, this.m_texValueMax[3] + this.m_texValueMax[3]], 1 / 2.0));
1270             return es3fShaderDerivateTests.reverifyConstantDerivateWithFlushRelaxations(compareArea, maskArea, this.m_dataType, this.m_precision,
1271                 this.m_derivScale, this.m_derivBias, surfaceThreshold, this.m_func, function_);
1272         } else {
1273             assertMsgOptions(this.m_func == es3fShaderDerivateTests.DerivateFunc.FWIDTH, 'Expected Derivate Function FWIDTH', false, true);
1274             /** @type {Array<number>} */ var dx = deMath.multiply(deMath.scale(deMath.subtract(this.m_texValueMax, this.m_texValueMin), 1 / w), xScale);
1275             /** @type {Array<number>} */ var dy = deMath.multiply(deMath.scale(deMath.subtract(this.m_texValueMax, this.m_texValueMin), 1 / h), yScale);
1276             reference = deMath.add(deMath.abs(dx), deMath.abs(dy));
1277             /** @type {Array<number>} */ var dxThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_texValueMin, xScale), deMath.multiply(this.m_texValueMax, xScale), dx);
1278             /** @type {Array<number>} */ var dyThreshold = es3fShaderDerivateTests.getDerivateThreshold(this.m_precision, deMath.multiply(this.m_texValueMin, yScale), deMath.multiply(this.m_texValueMax, yScale), dy);
1279             threshold = deMath.max(surfaceThreshold, deMath.max(dxThreshold, dyThreshold));
1281             return es3fShaderDerivateTests.verifyConstantDerivate(compareArea, maskArea, this.m_dataType,
1282                 reference, threshold, this.m_derivScale, this.m_derivBias);
1283         };
1284     };
1286     /**
1287      * @constructor
1288      * @extends {tcuTestCase.DeqpTest}
1289      */
1290     es3fShaderDerivateTests.ShaderDerivateTests = function() {
1291         tcuTestCase.DeqpTest.call(this, 'derivate', 'Derivate Function Tests');
1292     };
1294     es3fShaderDerivateTests.ShaderDerivateTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
1295     es3fShaderDerivateTests.ShaderDerivateTests.prototype.constructor = es3fShaderDerivateTests.ShaderDerivateTests
1297     /**
1298      * @struct
1299      * @constructor
1300      * @param {string} name
1301      * @param {es3fShaderDerivateTests.DerivateFunc} func
1302      * @param {gluShaderUtil.DataType} dataType_
1303      * @param {gluShaderUtil.precision} precision_
1304      */
1305     es3fShaderDerivateTests.FunctionSpec = function(name, func, dataType_, precision_) {
1306         this.name = name;
1307         this.function_ = func;
1308         this.dataType = dataType_;
1309         this.precision = precision_;
1310     };
1312     es3fShaderDerivateTests.ShaderDerivateTests.prototype.init = function() {
1313         var testGroup = tcuTestCase.runner.testCases;
1314         /**
1315          * @struct
1316          * @constructor
1317          * @param {string} name
1318          * @param {string} description
1319          * @param {string} source
1320          */
1321         var LinearDerivateCase = function(name, description, source) {
1322             /** @type {string} */ this.name = name;
1323             /** @type {string} */ this.description = description;
1324             /** @type {string} */ this.source = source;
1325         };
1327         /** @type {Array<LinearDerivateCase>} */
1328         var s_linearDerivateCases = [
1329             new LinearDerivateCase(
1330                 'linear',
1331                 'Basic derivate of linearly interpolated argument',
1332                 '#version 300 es\n' +
1333                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1334                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1335                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1336                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1337                 'void main (void)\n' +
1338                 '{\n' +
1339                 ' ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1340                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1341                 '}\n'),
1342             new LinearDerivateCase(
1343                 'in_function',
1344                 'Derivate of linear function argument',
1345                 '#version 300 es\n' +
1346                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1347                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1348                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1349                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1350                 '\n' +
1351                 '${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n' +
1352                 '{\n' +
1353                 ' return ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1354                 '}\n' +
1355                 '\n' +
1356                 'void main (void)\n' +
1357                 '{\n' +
1358                 ' ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n' +
1359                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1360                 '}\n'),
1361             new LinearDerivateCase(
1362                 'static_if',
1363                 'Derivate of linearly interpolated value in static if',
1364                 '#version 300 es\n' +
1365                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1366                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1367                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1368                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1369                 'void main (void)\n' +
1370                 '{\n' +
1371                 ' ${PRECISION} ${DATATYPE} res;\n' +
1372                 ' if (false)\n' +
1373                 ' res = ${FUNC}(-v_coord) * u_scale + u_bias;\n' +
1374                 ' else\n' +
1375                 ' res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1376                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1377                 '}\n'),
1378             new LinearDerivateCase(
1379                 'static_loop',
1380                 'Derivate of linearly interpolated value in static loop',
1381                 '#version 300 es\n' +
1382                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1383                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1384                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1385                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1386                 'void main (void)\n' +
1387                 '{\n' +
1388                 ' ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n' +
1389                 ' for (int i = 0; i < 2; i++)\n' +
1390                 ' res += ${FUNC}(v_coord * float(i));\n' +
1391                 ' res = res * u_scale + u_bias;\n' +
1392                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1393                 '}\n'),
1394             new LinearDerivateCase(
1395                 'static_switch',
1396                 'Derivate of linearly interpolated value in static switch',
1397                 '#version 300 es\n' +
1398                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1399                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1400                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1401                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1402                 'void main (void)\n' +
1403                 '{\n' +
1404                 ' ${PRECISION} ${DATATYPE} res;\n' +
1405                 ' switch (1)\n' +
1406                 ' {\n' +
1407                 ' case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n' +
1408                 ' case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n' +
1409                 ' }\n' +
1410                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1411                 '}\n'),
1412             new LinearDerivateCase(
1413                 'uniform_if',
1414                 'Derivate of linearly interpolated value in uniform if',
1415                 '#version 300 es\n' +
1416                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1417                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1418                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1419                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1420                 'uniform bool ub_true;\n' +
1421                 'void main (void)\n' +
1422                 '{\n' +
1423                 ' ${PRECISION} ${DATATYPE} res;\n' +
1424                 ' if (ub_true)\n' +
1425                 ' res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1426                 ' else\n' +
1427                 ' res = ${FUNC}(-v_coord) * u_scale + u_bias;\n' +
1428                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1429                 '}\n'),
1430             new LinearDerivateCase(
1431                 'uniform_loop',
1432                 'Derivate of linearly interpolated value in uniform loop',
1433                 '#version 300 es\n' +
1434                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1435                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1436                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1437                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1438                 'uniform int ui_two;\n' +
1439                 'void main (void)\n' +
1440                 '{\n' +
1441                 ' ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n' +
1442                 ' for (int i = 0; i < ui_two; i++)\n' +
1443                 ' res += ${FUNC}(v_coord * float(i));\n' +
1444                 ' res = res * u_scale + u_bias;\n' +
1445                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1446                 '}\n'),
1447             new LinearDerivateCase(
1448                 'uniform_switch',
1449                 'Derivate of linearly interpolated value in uniform switch',
1450                 '#version 300 es\n' +
1451                 'in ${PRECISION} ${DATATYPE} v_coord;\n' +
1452                 'layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n' +
1453                 'uniform ${PRECISION} ${DATATYPE} u_scale;\n' +
1454                 'uniform ${PRECISION} ${DATATYPE} u_bias;\n' +
1455                 'uniform int ui_one;\n' +
1456                 'void main (void)\n' +
1457                 '{\n' +
1458                 ' ${PRECISION} ${DATATYPE} res;\n' +
1459                 ' switch (ui_one)\n' +
1460                 ' {\n' +
1461                 ' case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias; break;\n' +
1462                 ' case 1: res = ${FUNC}(v_coord) * u_scale + u_bias; break;\n' +
1463                 ' }\n' +
1464                 ' o_color = ${CAST_TO_OUTPUT};\n' +
1465                 '}\n')
1466         ];
1468         /**
1469          * @struct
1470          * @constructor
1471          * @param {string} name
1472          * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1473          * @param {number} numSamples
1474          */
1475         var FboConfig = function(name, surfaceType, numSamples) {
1476             /** @type {string} */ this.name = name;
1477             /** @type {es3fShaderDerivateTests.SurfaceType} */ this.surfaceType = surfaceType;
1478             /** @type {number} */ this.numSamples = numSamples;
1479         };
1481         /** @type {Array<FboConfig>} */ var s_fboConfigs = [
1482             new FboConfig('fbo', es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER, 0),
1483             new FboConfig('fbo_msaa2', es3fShaderDerivateTests.SurfaceType.UNORM_FBO, 2),
1484             new FboConfig('fbo_msaa4', es3fShaderDerivateTests.SurfaceType.UNORM_FBO, 4),
1485             new FboConfig('fbo_float', es3fShaderDerivateTests.SurfaceType.FLOAT_FBO, 0)
1486         ];
1488         /**
1489          * @struct
1490          * @constructor
1491          * @param {string} name
1492          * @param {number} hint
1493          */
1494         var Hint = function(name, hint) {
1495             /** @type {string} */ this.name = name;
1496             /** @type {number} */ this.hint = hint;
1497         };
1499         /** @type {Array<Hint>} */ var s_hints = [
1500             new Hint('fastest', gl.FASTEST),
1501             new Hint('nicest', gl.NICEST)
1502         ];
1504         /**
1505          * @struct
1506          * @constructor
1507          * @param {string} name
1508          * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1509          * @param {number} numSamples
1510          */
1511         var HintFboConfig = function(name, surfaceType, numSamples) {
1512             /** @type {string} */ this.name = name;
1513             /** @type {es3fShaderDerivateTests.SurfaceType} */ this.surfaceType = surfaceType;
1514             /** @type {number} */ this.numSamples = numSamples;
1515         };
1517         /** @type {Array<HintFboConfig>} */ var s_hintFboConfigs = [
1518             new HintFboConfig('default', es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER, 0),
1519             new HintFboConfig('fbo_msaa4', es3fShaderDerivateTests.SurfaceType.UNORM_FBO, 4),
1520             new HintFboConfig('fbo_float', es3fShaderDerivateTests.SurfaceType.FLOAT_FBO, 0)
1521         ];
1523         /**
1524          * @struct
1525          * @constructor
1526          * @param {string} name
1527          * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1528          * @param {number} numSamples
1529          * @param {number} hint
1530          */
1531         var TextureConfig = function(name, surfaceType, numSamples, hint) {
1532             /** @type {string} */ this.name = name;
1533             /** @type {es3fShaderDerivateTests.SurfaceType} */ this.surfaceType = surfaceType;
1534             /** @type {number} */ this.numSamples = numSamples;
1535             /** @type {number} */ this.hint = hint;
1536         };
1538         /** @type {Array<TextureConfig>} */ var s_textureConfigs = [
1539             new TextureConfig('basic', es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER, 0, gl.DONT_CARE),
1540             new TextureConfig('msaa4', es3fShaderDerivateTests.SurfaceType.UNORM_FBO, 4, gl.DONT_CARE),
1541             new TextureConfig('float_fastest', es3fShaderDerivateTests.SurfaceType.FLOAT_FBO, 0, gl.FASTEST),
1542             new TextureConfig('float_nicest', es3fShaderDerivateTests.SurfaceType.FLOAT_FBO, 0, gl.NICEST)
1543         ];
1545         /** @type {gluShaderUtil.DataType} */ var dataType;
1546         /** @type {string} */ var source;
1547         /** @type {gluShaderUtil.precision} */ var precision;
1548         /** @type {es3fShaderDerivateTests.SurfaceType} */ var surfaceType;
1549         /** @type {number} */ var numSamples;
1550         /** @type {number} */ var hint;
1551         /** @type {string} */ var caseName;
1552         /** @type {tcuTestCase.DeqpTest} */ var fboGroup;
1554         // .dfdx, .dfdy, .fwidth
1555         for (var funcNdx in es3fShaderDerivateTests.DerivateFunc) {
1556             /** @type {es3fShaderDerivateTests.DerivateFunc} */ var function_ = es3fShaderDerivateTests.DerivateFunc[funcNdx];
1557             /** @type {tcuTestCase.DeqpTest} */ var functionGroup = tcuTestCase.newTest(es3fShaderDerivateTests.getDerivateFuncCaseName(function_), es3fShaderDerivateTests.getDerivateFuncName(function_));
1558             testGroup.addChild(functionGroup);
1560             // .constant - no precision variants, checks that derivate of constant arguments is 0
1561             /** @type {tcuTestCase.DeqpTest} */ var constantGroup = tcuTestCase.newTest('constant', 'Derivate of constant argument');
1562             functionGroup.addChild(constantGroup);
1564             for (var vecSize = 1; vecSize <= 4; vecSize++) {
1565                 dataType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT;
1566                 constantGroup.addChild(new es3fShaderDerivateTests.ConstantDerivateCase(gluShaderUtil.getDataTypeName(dataType), '', function_, dataType));
1567             }
1569             // Cases based on LinearDerivateCase
1570             for (var caseNdx = 0; caseNdx < s_linearDerivateCases.length; caseNdx++) {
1571                 /** @type {tcuTestCase.DeqpTest} */ var linearCaseGroup = tcuTestCase.newTest(s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description);
1572                 source = s_linearDerivateCases[caseNdx].source;
1573                 functionGroup.addChild(linearCaseGroup);
1575                 for (var vecSize = 1; vecSize <= 4; vecSize++)
1576                 for (var precNdx in gluShaderUtil.precision) {
1577                     dataType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT;
1578                     precision = gluShaderUtil.precision[precNdx];
1579                     surfaceType = es3fShaderDerivateTests.SurfaceType.DEFAULT_FRAMEBUFFER;
1580                     numSamples = 0;
1581                     hint = gl.DONT_CARE;
1583                     if (caseNdx !== 0 && precision === gluShaderUtil.precision.PRECISION_LOWP)
1584                         continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
1586                     caseName = gluShaderUtil.getDataTypeName(dataType) + '_' + gluShaderUtil.getPrecisionName(precision);
1588                     linearCaseGroup.addChild(new es3fShaderDerivateTests.LinearDerivateCase(caseName, '', function_, dataType, precision, hint, surfaceType, numSamples, source));
1589                 }
1590             }
1592             // Fbo cases
1593             for (var caseNdx = 0; caseNdx < s_fboConfigs.length; caseNdx++) {
1594                 fboGroup = tcuTestCase.newTest(s_fboConfigs[caseNdx].name, 'Derivate usage when rendering into FBO');
1595                 source = s_linearDerivateCases[0].source; // use source from .linear group
1596                 surfaceType = s_fboConfigs[caseNdx].surfaceType;
1597                 numSamples = s_fboConfigs[caseNdx].numSamples;
1598                 functionGroup.addChild(fboGroup);
1600                 for (var vecSize = 1; vecSize <= 4; vecSize++)
1601                 for (var precNdx in gluShaderUtil.precision) {
1602                     dataType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT;
1603                     precision = gluShaderUtil.precision[precNdx];
1604                     hint = gl.DONT_CARE;
1606                     if (surfaceType !== es3fShaderDerivateTests.SurfaceType.FLOAT_FBO && precision === gluShaderUtil.precision.PRECISION_LOWP)
1607                         continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1609                     caseName = gluShaderUtil.getDataTypeName(dataType) + '_' + gluShaderUtil.getPrecisionName(precision);
1611                     fboGroup.addChild(new es3fShaderDerivateTests.LinearDerivateCase(caseName, '', function_, dataType, precision, hint, surfaceType, numSamples, source));
1612                 }
1613             }
1615             // .fastest, .nicest
1616             for (var hintCaseNdx = 0; hintCaseNdx < s_hints.length; hintCaseNdx++) {
1617                 /** @type {tcuTestCase.DeqpTest} */ var hintGroup = tcuTestCase.newTest(s_hints[hintCaseNdx].name, 'Shader derivate hints');
1618                 source = s_linearDerivateCases[0].source; // use source from .linear group
1619                 hint = s_hints[hintCaseNdx].hint;
1620                 functionGroup.addChild(hintGroup);
1622                 for (var fboCaseNdx = 0; fboCaseNdx < s_hintFboConfigs.length; fboCaseNdx++) {
1623                     fboGroup = tcuTestCase.newTest(s_hintFboConfigs[fboCaseNdx].name, '');
1624                     surfaceType = s_hintFboConfigs[fboCaseNdx].surfaceType;
1625                     numSamples = s_hintFboConfigs[fboCaseNdx].numSamples;
1626                     hintGroup.addChild(fboGroup);
1628                     for (var vecSize = 1; vecSize <= 4; vecSize++)
1629                     for (var precNdx in gluShaderUtil.precision) {
1630                         dataType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT;
1631                         precision = gluShaderUtil.precision[precNdx];
1633                         if (surfaceType !== es3fShaderDerivateTests.SurfaceType.FLOAT_FBO && precision === gluShaderUtil.precision.PRECISION_LOWP)
1634                             continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1636                         caseName = gluShaderUtil.getDataTypeName(dataType) + '_' + gluShaderUtil.getPrecisionName(precision);
1638                         fboGroup.addChild(new es3fShaderDerivateTests.LinearDerivateCase(caseName, '', function_, dataType, precision, hint, surfaceType, numSamples, source));
1639                     }
1640                 }
1641             }
1643             // .texture
1644             /** @type {tcuTestCase.DeqpTest} */ var textureGroup = tcuTestCase.newTest('texture', 'Derivate of texture lookup result');
1645             functionGroup.addChild(textureGroup);
1647             for (var texCaseNdx = 0; texCaseNdx < s_textureConfigs.length; texCaseNdx++) {
1648                 /** @type {tcuTestCase.DeqpTest} */ var caseGroup = tcuTestCase.newTest(s_textureConfigs[texCaseNdx].name, '');
1649                 surfaceType = s_textureConfigs[texCaseNdx].surfaceType;
1650                 numSamples = s_textureConfigs[texCaseNdx].numSamples;
1651                 hint = s_textureConfigs[texCaseNdx].hint;
1652                 textureGroup.addChild(caseGroup);
1654                 for (var vecSize = 1; vecSize <= 4; vecSize++)
1655                 for (var precNdx in gluShaderUtil.precision) {
1656                     dataType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT;
1657                     precision = gluShaderUtil.precision[precNdx];
1659                     if (surfaceType !== es3fShaderDerivateTests.SurfaceType.FLOAT_FBO && precision === gluShaderUtil.precision.PRECISION_LOWP)
1660                         continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
1662                     caseName = gluShaderUtil.getDataTypeName(dataType) + '_' + gluShaderUtil.getPrecisionName(precision);
1664                     caseGroup.addChild(new es3fShaderDerivateTests.TextureDerivateCase(caseName, '', function_, dataType, precision, hint, surfaceType, numSamples));
1665                 }
1666             }
1667         }
1668     };
1670     /**
1671      * Run test
1672      * @param {WebGL2RenderingContext} context
1673      */
1674     es3fShaderDerivateTests.run = function(context, range) {
1675         gl = context;
1676         //Set up Test Root parameters
1677         var state = tcuTestCase.runner;
1678         state.setRoot(new es3fShaderDerivateTests.ShaderDerivateTests());
1680         //Set up name and description of this test series.
1681         setCurrentTestName(state.testCases.fullName());
1682         description(state.testCases.getDescription());
1684         try {
1685             if (range)
1686                 state.setRange(range);
1687             //Run test cases
1688             tcuTestCase.runTestCases();
1689         }
1690         catch (err) {
1691             testFailedOptions('Failed to es3fShaderDerivateTests.run tests', false);
1692             tcuTestCase.runner.terminate();
1693         }
1694     };