1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the 'License');
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an 'AS IS' BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 goog.provide('functional.gles3.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
78 es3fShaderDerivateTests.DerivateFunc = {
87 es3fShaderDerivateTests.SurfaceType = {
88 DEFAULT_FRAMEBUFFER: 0,
90 FLOAT_FBO: 2 // \note Uses RGBA32UI fbo actually, since FP rendertargets are not in core spec.
96 es3fShaderDerivateTests.VerificationLogging = {
102 * @param {es3fShaderDerivateTests.DerivateFunc} func
105 es3fShaderDerivateTests.getDerivateFuncName = function(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.');
115 * @param {es3fShaderDerivateTests.DerivateFunc} func
118 es3fShaderDerivateTests.getDerivateFuncCaseName = function(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.');
128 * @param {?gluShaderUtil.DataType} type
129 * @return {Array<boolean>}
131 es3fShaderDerivateTests.getDerivateMask = function(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.');
142 * @param {tcuTexture.ConstPixelBufferAccess} surface
143 * @param {Array<number>} derivScale
144 * @param {Array<number>} derivBias
147 * @return {Array<number>}
149 es3fShaderDerivateTests.readDerivate = function(surface, derivScale, derivBias, x, y) {
150 return deMath.divide(deMath.subtract(surface.getPixel(x, y), derivBias), derivScale);
154 * @param {Array<number>} v
155 * @return {Array<number>}
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()];
165 * @param {number} value
166 * @param {number} numAccurateBits
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();
178 * @param {?gluShaderUtil.precision} precision
181 es3fShaderDerivateTests.getNumMantissaBits = function(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;
187 throw new Error('Precision not supported: ' + precision);
192 * @param {?gluShaderUtil.precision} precision
195 es3fShaderDerivateTests.getMinExponent = function(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;
201 throw new Error('Precision not supported: ' + precision);
206 * @param {number} exp
207 * @param {number} numMantissaBits
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();
218 assertMsgOptions(numMantissaBits === 0, 'numMantissaBits must equal to 0.', false, true);
219 return (new tcuFloat.deFloat()).construct(1, exp, (1 << 23)).getValue()
224 * @param {number} value
225 * @param {number} numMantissaBits
228 es3fShaderDerivateTests.getSingleULPForValue = function(value, numMantissaBits) {
229 /** @type {number} */ var exp = (new tcuFloat.deFloat().deFloatNumber(value)).exponent();
230 return es3fShaderDerivateTests.getSingleULPForExponent(exp, numMantissaBits);
234 * @param {number} value
235 * @param {number} minExponent
236 * @param {number} numAccurateBits
239 es3fShaderDerivateTests.convertFloorFlushToZero = function(value, minExponent, numAccurateBits) {
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;
248 if (value > 0.0 && (new tcuFloat.deFloat().deFloatNumber(value)).exponent() < minExponent) {
249 // flush to zero if possible
252 // just mask away non-representable bits
253 return (new tcuFloat.deFloat()).construct(1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).getValue();
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);
260 // value is representable, no need to do anything
268 * @param {number} value
269 * @param {number} minExponent
270 * @param {number} numAccurateBits
273 es3fShaderDerivateTests.convertCeilFlushToZero = function(value, minExponent, numAccurateBits) {
274 return -es3fShaderDerivateTests.convertFloorFlushToZero(-value, minExponent, numAccurateBits);
278 * @param {number} value
279 * @param {number} numUlps
280 * @param {number} numMantissaBits
283 es3fShaderDerivateTests.addErrorUlp = function(value, numUlps, numMantissaBits) {
284 return value + numUlps * es3fShaderDerivateTests.getSingleULPForValue(value, numMantissaBits);
288 * @param {?gluShaderUtil.precision} precision
289 * @param {Array<number>} valueMin
290 * @param {Array<number>} valueMax
291 * @param {Array<number>} expectedDerivate
292 * @return {Array<number>}
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(
303 [baseBits, baseBits, baseBits, baseBits],
305 -es3fShaderDerivateTests.INTERPOLATION_LOST_BITS),
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])];
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
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)),
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);
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;
371 es3fShaderDerivateTests.Linear2DFunctionEvaluator = function() {
372 /** @type {tcuMatrix.Matrix} */ this.matrix = new tcuMatrix.Matrix(4, 3);
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);
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
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 )
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
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))
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))
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)));
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()) {
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())) +
491 '\tDerivative value range:\n' +
492 '\t\tMin: ' + finalResultRange.lo() + '\n' +
493 '\t\tMax: ' + finalResultRange.hi() + '\n');
496 anyComponentFailed = true;
500 if (anyComponentFailed)
501 errorMask.setPixel(red, x, y);
504 if (numFailedPixels >= es3fShaderDerivateTests.MAX_FAILED_MESSAGES)
505 bufferedLogToConsole('...');
507 if (numFailedPixels > 0)
508 bufferedLogToConsole('FAIL: found ' + numFailedPixels + ' failed pixels');
510 return numFailedPixels === 0;
515 * @extends {tcuTestCase.DeqpTest}
516 * @param {string} name
517 * @param {string} description
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);
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) {};
550 * @param {?gluShaderUtil.DataType} coordType
551 * @param {?gluShaderUtil.precision} precision
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' +
564 ' gl_Position = a_position;\n' +
565 ' v_coord = a_coord;\n' +
568 /** @type {Object} */ var vertexParams = {};
570 vertexParams['PRECISION'] = gluShaderUtil.getPrecisionName(precision);
571 vertexParams['DATATYPE'] = gluShaderUtil.getDataTypeName(coordType);
573 return tcuStringTemplate.specialize(vertexTmpl, vertexParams);
577 * @return {Array<number>}
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];
585 return [es3fShaderDerivateTests.FBO_WIDTH, es3fShaderDerivateTests.FBO_HEIGHT];
589 * @return {tcuTestCase.IterateResult}
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);
606 assertMsgOptions(false, 'Compile failed', false, true);
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);
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);
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' +
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));
635 /** @type {Array<number>} */ var positions = [
636 -1.0, -1.0, 0.0, 1.0,
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]
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)
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);
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);
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);
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);
676 throw new Error('Invalid channelclass ' + fmtClass);
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]);
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));
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));
701 case gluShaderUtil.DataType.FLOAT_VEC4:
702 gl.uniform4fv(scaleLoc, this.m_derivScale);
703 gl.uniform4fv(biasLoc, this.m_derivBias);
707 throw new Error('Data Type not supported: ' + this.m_dataType);
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));
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
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);
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);
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);
754 throw new Error('Surface Type not supported: ' + this.m_surfaceType);
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());
766 tcuLogImage.logImage('Rendered', 'Rendered image', result.getAccess());
767 tcuLogImage.logImage('ErrorMask', 'Error mask', errorMask.getAccess());
768 testFailedOptions('Fail', false);
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;
782 * @return {Array<number>}
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];
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];
804 * @extends {es3fShaderDerivateTests.TriangleDerivateCase}
805 * @param {string} name
806 * @param {string} description
807 * @param {es3fShaderDerivateTests.DerivateFunc} func
808 * @param {gluShaderUtil.DataType} type
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;
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' +
830 ' ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n' +
831 ' o_color = ${CAST_TO_OUTPUT};\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)' :
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];
854 * @param {tcuTexture.ConstPixelBufferAccess} result
855 * @param {tcuTexture.PixelBufferAccess} errorMask
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);
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
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;
887 this.m_surfaceType = surfaceType;
888 this.m_numSamples = numSamples;
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);
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))';
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)';
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.];
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.];
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];
938 throw new Error('Precision not supported: ' + this.m_precision);
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];
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);
955 case es3fShaderDerivateTests.DerivateFunc.DFDY:
956 this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dy);
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)));
964 throw new Error('Derivate Function not supported: ' + this.m_func);
967 this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
972 * @param {tcuTexture.ConstPixelBufferAccess} result
973 * @param {tcuTexture.PixelBufferAccess} errorMask
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.');
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_);
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);
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
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;
1065 this.m_surfaceType = surfaceType;
1066 this.m_numSamples = numSamples;
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;
1076 es3fShaderDerivateTests.TextureDerivateCase.prototype.init = function() {
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' +
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' +
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' :
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))';
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)';
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.];
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.];
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];
1141 throw new Error(false, 'Precision not supported:' + this.m_precision);
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);
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];
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);
1185 case es3fShaderDerivateTests.DerivateFunc.DFDY:
1186 this.m_derivScale = deMath.divide([0.5, 0.5, 0.5, 0.5], dy);
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)));
1194 throw new Error('Derivate Function not supported: ' + this.m_func);
1197 this.m_derivBias = [0.0, 0.0, 0.0, 0.0];
1202 * @param {WebGLProgram} program
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);
1218 * @param {tcuTexture.PixelBufferAccess} result
1219 * @param {tcuTexture.PixelBufferAccess} errorMask
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.');
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_);
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);
1288 * @extends {tcuTestCase.DeqpTest}
1290 es3fShaderDerivateTests.ShaderDerivateTests = function() {
1291 tcuTestCase.DeqpTest.call(this, 'derivate', 'Derivate Function Tests');
1294 es3fShaderDerivateTests.ShaderDerivateTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
1295 es3fShaderDerivateTests.ShaderDerivateTests.prototype.constructor = es3fShaderDerivateTests.ShaderDerivateTests
1300 * @param {string} name
1301 * @param {es3fShaderDerivateTests.DerivateFunc} func
1302 * @param {gluShaderUtil.DataType} dataType_
1303 * @param {gluShaderUtil.precision} precision_
1305 es3fShaderDerivateTests.FunctionSpec = function(name, func, dataType_, precision_) {
1307 this.function_ = func;
1308 this.dataType = dataType_;
1309 this.precision = precision_;
1312 es3fShaderDerivateTests.ShaderDerivateTests.prototype.init = function() {
1313 var testGroup = tcuTestCase.runner.testCases;
1317 * @param {string} name
1318 * @param {string} description
1319 * @param {string} source
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;
1327 /** @type {Array<LinearDerivateCase>} */
1328 var s_linearDerivateCases = [
1329 new LinearDerivateCase(
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' +
1339 ' ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1340 ' o_color = ${CAST_TO_OUTPUT};\n' +
1342 new LinearDerivateCase(
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' +
1351 '${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n' +
1353 ' return ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1356 'void main (void)\n' +
1358 ' ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n' +
1359 ' o_color = ${CAST_TO_OUTPUT};\n' +
1361 new LinearDerivateCase(
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' +
1371 ' ${PRECISION} ${DATATYPE} res;\n' +
1373 ' res = ${FUNC}(-v_coord) * u_scale + u_bias;\n' +
1375 ' res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1376 ' o_color = ${CAST_TO_OUTPUT};\n' +
1378 new LinearDerivateCase(
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' +
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' +
1394 new LinearDerivateCase(
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' +
1404 ' ${PRECISION} ${DATATYPE} res;\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' +
1410 ' o_color = ${CAST_TO_OUTPUT};\n' +
1412 new LinearDerivateCase(
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' +
1423 ' ${PRECISION} ${DATATYPE} res;\n' +
1425 ' res = ${FUNC}(v_coord) * u_scale + u_bias;\n' +
1427 ' res = ${FUNC}(-v_coord) * u_scale + u_bias;\n' +
1428 ' o_color = ${CAST_TO_OUTPUT};\n' +
1430 new LinearDerivateCase(
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' +
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' +
1447 new LinearDerivateCase(
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' +
1458 ' ${PRECISION} ${DATATYPE} res;\n' +
1459 ' switch (ui_one)\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' +
1464 ' o_color = ${CAST_TO_OUTPUT};\n' +
1471 * @param {string} name
1472 * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1473 * @param {number} numSamples
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;
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)
1491 * @param {string} name
1492 * @param {number} hint
1494 var Hint = function(name, hint) {
1495 /** @type {string} */ this.name = name;
1496 /** @type {number} */ this.hint = hint;
1499 /** @type {Array<Hint>} */ var s_hints = [
1500 new Hint('fastest', gl.FASTEST),
1501 new Hint('nicest', gl.NICEST)
1507 * @param {string} name
1508 * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1509 * @param {number} numSamples
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;
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)
1526 * @param {string} name
1527 * @param {es3fShaderDerivateTests.SurfaceType} surfaceType
1528 * @param {number} numSamples
1529 * @param {number} hint
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;
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)
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));
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;
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));
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));
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));
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));
1672 * @param {WebGL2RenderingContext} context
1674 es3fShaderDerivateTests.run = function(context, range) {
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());
1686 state.setRange(range);
1688 tcuTestCase.runTestCases();
1691 testFailedOptions('Failed to es3fShaderDerivateTests.run tests', false);
1692 tcuTestCase.runner.terminate();