Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fFragmentOutputTests.js
blobb27eee7a6e2579d37943c90353d06f7c0b1f4098
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.es3fFragmentOutputTests');
23 goog.require('framework.common.tcuImageCompare');
24 goog.require('framework.common.tcuTestCase');
25 goog.require('framework.common.tcuTexture');
26 goog.require('framework.common.tcuTextureUtil');
27 goog.require('framework.delibs.debase.deMath');
28 goog.require('framework.delibs.debase.deRandom');
29 goog.require('framework.opengl.gluShaderProgram');
30 goog.require('framework.opengl.gluShaderUtil');
31 goog.require('framework.opengl.gluTextureUtil');
32 goog.require('functional.gles3.es3fFboTestUtil');
34 goog.scope(function() {
36 var es3fFragmentOutputTests = functional.gles3.es3fFragmentOutputTests;
37 var gluShaderProgram = framework.opengl.gluShaderProgram;
38 var es3fFboTestUtil = functional.gles3.es3fFboTestUtil;
39 var gluShaderUtil = framework.opengl.gluShaderUtil;
40 var deRandom = framework.delibs.debase.deRandom;
41 var tcuTestCase = framework.common.tcuTestCase;
42 var gluTextureUtil = framework.opengl.gluTextureUtil;
43 var tcuTexture = framework.common.tcuTexture;
44 var tcuTextureUtil = framework.common.tcuTextureUtil;
45 var deMath = framework.delibs.debase.deMath;
46 var tcuImageCompare = framework.common.tcuImageCompare;
48     /** @type {WebGL2RenderingContext} */ var gl;
50     var DE_ASSERT = function(x) {
51         if (!x)
52             throw new Error('Assert failed');
53     };
55     /**
56      * es3fFragmentOutputTests.BufferSpec. Constructs the es3fFragmentOutputTests.BufferSpec object
57      * @constructor
58      * @param {WebGLRenderingContextBase.GLenum} format_
59      * @param {number} width_
60      * @param {number} height_
61      * @param {number} samples_
62      */
63     es3fFragmentOutputTests.BufferSpec = function(format_, width_, height_, samples_) {
64         this.format = format_;
65         this.width = width_;
66         this.height = height_;
67         this.samples = samples_;
68     };
70     /**
71      * es3fFragmentOutputTests.FragmentOutput. Constructs the es3fFragmentOutputTests.FragmentOutput object
72      * @constructor
73      * @param {gluShaderUtil.DataType} type_
74      * @param {gluShaderUtil.precision} precision_
75      * @param {number} location_
76      * @param {number=} arrayLength_
77      */
78     es3fFragmentOutputTests.FragmentOutput = function(type_, precision_, location_, arrayLength_) {
79         this.type = type_;
80         this.precision = precision_;
81         this.location = location_;
82         this.arrayLength = arrayLength_ || 0;
83     };
85     /**
86      * es3fFragmentOutputTests.FragmentOutputCase. Constructs the es3fFragmentOutputTests.FragmentOutputCase object
87      * @constructor
88      * @extends {tcuTestCase.DeqpTest}
89      * @param {string} name
90      * @param {string} description
91      * @param {Array<es3fFragmentOutputTests.BufferSpec>} fboSpec
92      * @param {Array<es3fFragmentOutputTests.FragmentOutput>} outputs
93      * @return {Object} The currently modified object
94      */
95     es3fFragmentOutputTests.FragmentOutputCase = function(name, description, fboSpec, outputs) {
96         tcuTestCase.DeqpTest.call(this, name, description);
97         /** @type {Array<es3fFragmentOutputTests.BufferSpec>} */ this.m_fboSpec = fboSpec;
98         /** @type {Array<es3fFragmentOutputTests.FragmentOutput>} */ this.m_outputs = outputs;
99         /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
100         /** @type {WebGLFramebuffer} */ this.m_framebuffer = null;
102         /** @type {WebGLRenderbuffer} */ this.m_renderbuffer = null;
103     };
105     es3fFragmentOutputTests.FragmentOutputCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
106     es3fFragmentOutputTests.FragmentOutputCase.prototype.constructor = es3fFragmentOutputTests.FragmentOutputCase;
108     /**
109      * es3fFragmentOutputTests.createProgram. Returns a ShaderProgram object
110      * @param {Array<es3fFragmentOutputTests.FragmentOutput>} outputs
111      * @return {gluShaderProgram.ShaderProgram} program
112      */
113     es3fFragmentOutputTests.createProgram = function(outputs) {
115         var vtx = '';
116         var frag = '';
118         vtx = '#version 300 es\n' + 'in highp vec4 a_position;\n';
119         frag = '#version 300 es\n';
121     /** @type {es3fFragmentOutputTests.FragmentOutput} */ var output = null;
122     /** @type {boolean} */ var isArray = false;
123      // Input-output declarations.
124         for (var outNdx = 0; outNdx < outputs.length; outNdx++) {
125             output = outputs[outNdx];
126             isArray = output.arrayLength > 0;
127             /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(output.type);
128             /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(output.precision);
129             /** @type {boolean} */ var isFloat = gluShaderUtil.isDataTypeFloatOrVec(output.type);
130             /** @type {string} */ var interp = isFloat ? 'smooth' : 'flat';
132             if (isArray) {
133                 for (var elemNdx = 0; elemNdx < output.arrayLength; elemNdx++) {
134                     vtx += 'in ' + precName + ' ' + typeName + ' in' + outNdx + '_' + elemNdx + ';\n' +
135                     interp + ' out ' + precName + ' ' + typeName + ' var' + outNdx + '_' + elemNdx + ';\n';
136                     frag += interp + ' in ' + precName + ' ' + typeName + ' var' + outNdx + '_' + elemNdx + ';\n';
137                 }
138                 frag += 'layout(location = ' + output.location + ') out ' + precName + ' ' + typeName + ' out' + outNdx + '[' + output.arrayLength + '];\n';
139             } else {
140                 vtx += 'in ' + precName + ' ' + typeName + ' in' + outNdx + ';\n' +
141                 interp + ' out ' + precName + ' ' + typeName + ' var' + outNdx + ';\n';
142                 frag += interp + ' in ' + precName + ' ' + typeName + ' var' + outNdx + ';\n' +
143                 'layout(location = ' + output.location + ') out ' + precName + ' ' + typeName + ' out' + outNdx + ';\n';
144             }
145         }
147         vtx += '\nvoid main()\n{\n';
148         frag += '\nvoid main()\n{\n';
150         vtx += ' gl_Position = a_position;\n';
152         // Copy body
153         for (var outNdx = 0; outNdx < outputs.length; outNdx++) {
154             output = outputs[outNdx];
155             isArray = output.arrayLength > 0;
157             if (isArray) {
158                 for (var elemNdx = 0; elemNdx < output.arrayLength; elemNdx++) {
159                     vtx += '\tvar' + outNdx + '_' + elemNdx + ' = in' + outNdx + '_' + elemNdx + ';\n';
160                     frag += '\tout' + outNdx + '[' + elemNdx + '] = var' + outNdx + '_' + elemNdx + ';\n';
161                 }
162             } else {
163                 vtx += '\tvar' + outNdx + ' = in' + outNdx + ';\n';
164                 frag += '\tout' + outNdx + ' = var' + outNdx + ';\n';
165             }
166         }
168         vtx += '}\n';
169         frag += '}\n';
171         /** @type {gluShaderProgram.ShaderProgram} */
172         var program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
173         return program;
174     };
176     es3fFragmentOutputTests.FragmentOutputCase.prototype.init = function() {
177         // Check that all attachments are supported
178         for (var iter = 0; iter < this.m_fboSpec.length; ++iter) {
179             if (!gluTextureUtil.isSizedFormatColorRenderable(this.m_fboSpec[iter].format))
180                 throw new Error('Unsupported attachment format');
181         }
183         DE_ASSERT(!this.m_program);
184         this.m_program = es3fFragmentOutputTests.createProgram(this.m_outputs);
186        // log << *m_program;
187         if (!this.m_program.isOk())
188             throw new Error('Compile failed. Program no created');
190         /*
191         // Print render target info to log.
192         log << TestLog::Section("Framebuffer", "Framebuffer configuration");
194         for (int ndx = 0; ndx < (int)m_fboSpec.size(); ndx++)
195             log << TestLog::Message << "COLOR_ATTACHMENT" << ndx << ": "
196                                     << glu::getPixelFormatStr(m_fboSpec[ndx].format) << ", "
197                                     << m_fboSpec[ndx].width << "x" << m_fboSpec[ndx].height << ", "
198                                     << m_fboSpec[ndx].samples << " samples"
199                 << TestLog::EndMessage;
201         log << TestLog::EndSection;*/
203         // Create framebuffer.
204         this.m_framebuffer = gl.createFramebuffer();
205         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
207         for (var bufNdx = 0; bufNdx < /* m_renderbuffers.size() */ this.m_fboSpec.length; bufNdx++) {
208             this.m_renderbuffer = gl.createRenderbuffer();
209             /** @type {es3fFragmentOutputTests.BufferSpec} */ var bufSpec = this.m_fboSpec[bufNdx];
210             /** @type {number} */ var attachment = gl.COLOR_ATTACHMENT0 + bufNdx;
212             gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
214             gl.renderbufferStorageMultisample(gl.RENDERBUFFER, bufSpec.samples, bufSpec.format, bufSpec.width, bufSpec.height);
215             gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, this.m_renderbuffer);
216         }
217         /** @type {number} */ var fboStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
219         if (fboStatus == gl.FRAMEBUFFER_UNSUPPORTED)
220             throw new Error('Framebuffer not supported');
221         else if (fboStatus != gl.FRAMEBUFFER_COMPLETE)
222             throw new Error('Incomplete framebuffer');
223             // throw tcu::TestError((string("Incomplete framebuffer: ") + glu::getFramebufferStatusStr(fboStatus), "", __FILE__, __LINE__);
225         // gl.bindRenderbuffer(gl.RENDERBUFFER, null); // TODO: maybe needed?
226         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
227     };
229     es3fFragmentOutputTests.FragmentOutputCase.prototype.deinit = function() {
230         // TODO: implement?
231     };
233     /**
234      * es3fFragmentOutputTests.getMinSize.
235      * @param {Array<es3fFragmentOutputTests.BufferSpec>} fboSpec
236      * @return {Array<number>} minSize
237      */
238     es3fFragmentOutputTests.getMinSize = function(fboSpec) {
239         /** @type {Array<number>} */ var minSize = [0x7fffffff, 0x7fffffff];
240         for (var i = 0; i < fboSpec.length; i++) {
241             minSize[0] = Math.min(minSize[0], fboSpec[i].width);
242             minSize[1] = Math.min(minSize[1], fboSpec[i].height);
243         }
244         return minSize;
245     };
247     /**
248      * es3fFragmentOutputTests.getNumInputVectors. Returns the length of the array of all the outputs (es3fFragmentOutputTests.FragmentOutput object)
249      * @param {Array<es3fFragmentOutputTests.FragmentOutput>} outputs
250      * @return {number} numVecs
251      */
252     es3fFragmentOutputTests.getNumInputVectors = function(outputs) {
253         /** @type {number} */ var numVecs = 0;
254         for (var i = 0; i < outputs.length; i++)
255             numVecs += (outputs[i].arrayLength > 0 ? outputs[i].arrayLength : 1);
256         return numVecs;
257     };
259     /**
260      * es3fFragmentOutputTests.getFloatRange
261      * @param {gluShaderUtil.precision} precision
262      * @return {Array<number>} Vec2
263      */
264     es3fFragmentOutputTests.getFloatRange = function(precision) {
265         /** @type {Array<Array<number>>} */
266         var ranges = // Vec2
267         [
268             [-2.0, 2.0],
269             [-16000.0, 16000.0],
270             [-1e35, 1e35]
271         ];
272         // DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
273         // DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
274         return ranges[precision];
275     };
277     /**
278      * es3fFragmentOutputTests.getIntRange
279      * @param {gluShaderUtil.precision} precision
280      * @return {Array<number>} IVec2
281      */
282     es3fFragmentOutputTests.getIntRange = function(precision) {
283         /** @type {Array<Array<number>>} */
284         var ranges = // IVec2
285         [
286             [-(1 << 7), (1 << 7) - 1],
287             [-(1 << 15), (1 << 15) - 1],
288             [-0x80000000, 0x7fffffff]
289         ];
290         // DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
291         // DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
292         return ranges[precision];
293     };
295     /**
296      * es3fFragmentOutputTests.getUintRange
297      * @param {gluShaderUtil.precision} precision
298      * @return {Array<number>} UVec2
299      */
300     es3fFragmentOutputTests.getUintRange = function(precision) {
301         /** @type {Array<Array<number>>} */
302         var ranges = // UVec2
303         [
304             [0, (1 << 8) - 1],
305             [0, (1 << 16) - 1],
306             [0, 0xffffffff]
307         ];
308         // DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
309         // DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
310         return ranges[precision];
312     };
314     /**
315      * es3fFragmentOutputTests.readVec4
316      * @param {Array<number>} ptr
317      * @param {number} index
318      * @param {number} numComponents
319      * @return {Array<number>} Vec4
320      */
321     es3fFragmentOutputTests.readVec4 = function(ptr, index, numComponents) {
322         DE_ASSERT(numComponents >= 1);
323         return [
324                 ptr[index + 0],
325                 numComponents >= 2 ? ptr[index + 1] : 0.0,
326                 numComponents >= 3 ? ptr[index + 2] : 0.0,
327                 numComponents >= 4 ? ptr[index + 3] : 0.0
328                 ];
329     };
331     /**
332      * es3fFragmentOutputTests.readIVec4
333      * @param {Array<number>} ptr
334      * @param {number} numComponents
335      * @return {Array<number>} IVec4
336      */
337     es3fFragmentOutputTests.readIVec4 = function(ptr, index, numComponents) {
338         DE_ASSERT(numComponents >= 1);
339         return [
340                 ptr[index + 0],
341                 numComponents >= 2 ? ptr[index + 1] : 0,
342                 numComponents >= 3 ? ptr[index + 2] : 0,
343                 numComponents >= 4 ? ptr[index + 3] : 0
344                 ];
345     };
347     /**
348      * es3fFragmentOutputTests.renderFloatReference
349      * @param {tcuTexture.PixelBufferAccess} dst
350      * @param {number} gridWidth
351      * @param {number} gridHeight
352      * @param {number} numComponents
353      * @param {Array<number>} vertices
354      */
355     es3fFragmentOutputTests.renderFloatReference = function(dst, gridWidth, gridHeight, numComponents, vertices) {
357         /** @type {boolean} */ var isSRGB = dst.getFormat().order == tcuTexture.ChannelOrder.sRGB || dst.getFormat().order == tcuTexture.ChannelOrder.sRGBA;
358         /** @type {number} */ var cellW = dst.getWidth() / (gridWidth - 1);
359         /** @type {number} */ var cellH = dst.getHeight() / (gridHeight - 1);
361         for (var y = 0; y < dst.getHeight(); y++) {
362             for (var x = 0; x < dst.getWidth(); x++) {
363                 /** @type {number} */ var cellX = deMath.clamp(Math.floor(x / cellW), 0, gridWidth - 2);
364                 /** @type {number} */ var cellY = deMath.clamp(Math.floor(y / cellH), 0, gridHeight - 2);
365                 /** @type {number} */ var xf = (x - cellX * cellW + 0.5) / cellW;
366                 /** @type {number} */ var yf = (y - cellY * cellH + 0.5) / cellH;
368                 /** @type {Array<number>} */ var v00 = es3fFragmentOutputTests.readVec4(vertices, ((cellY + 0) * gridWidth + cellX + 0) * numComponents, numComponents); // Vec4
369                 /** @type {Array<number>} */ var v01 = es3fFragmentOutputTests.readVec4(vertices, ((cellY + 1) * gridWidth + cellX + 0) * numComponents, numComponents); // Vec4
370                 /** @type {Array<number>} */ var v10 = es3fFragmentOutputTests.readVec4(vertices, ((cellY + 0) * gridWidth + cellX + 1) * numComponents, numComponents); // Vec4
371                 /** @type {Array<number>} */ var v11 = es3fFragmentOutputTests.readVec4(vertices, ((cellY + 1) * gridWidth + cellX + 1) * numComponents, numComponents); // Vec4
373                 /** @type {boolean} */ var tri = xf + yf >= 1.0;
374                 /** @type {Array<number>} */ var v0 = tri ? v11 : v00; // Vec4&
375                 /** @type {Array<number>} */ var v1 = tri ? v01 : v10; // Vec4&
376                 /** @type {Array<number>} */ var v2 = tri ? v10 : v01; // Vec4&
377                 /** @type {number} */ var s = tri ? 1.0 - xf : xf;
378                 /** @type {number} */ var t = tri ? 1.0 - yf : yf;
379                 /** @type {Array<number>} */ var color = deMath.add(v0, deMath.add(deMath.multiply((deMath.subtract(v1, v0)), [s, s, s, s]), deMath.multiply((deMath.subtract(v2, v0)), [t, t, t, t]))); // Vec4
381                 dst.setPixel(isSRGB ? tcuTextureUtil.linearToSRGB(color) : color, x, y);
382             }
383         }
384     };
386     /**
387      * es3fFragmentOutputTests.renderIntReference
388      * @param {tcuTexture.PixelBufferAccess} dst
389      * @param {number} gridWidth
390      * @param {number} gridHeight
391      * @param {number} numComponents
392      * @param {Array<number>} vertices
393      */
394     es3fFragmentOutputTests.renderIntReference = function(dst, gridWidth, gridHeight, numComponents, vertices) {
396         /** @type {number} */ var cellW = dst.getWidth() / (gridWidth - 1);
397         /** @type {number} */ var cellH = dst.getHeight() / (gridHeight - 1);
399         for (var y = 0; y < dst.getHeight(); y++) {
400             for (var x = 0; x < dst.getWidth(); x++) {
401                 /** @type {number} */ var cellX = deMath.clamp(Math.floor(x / cellW), 0, gridWidth - 2);
402                 /** @type {number} */ var cellY = deMath.clamp(Math.floor(y / cellH), 0, gridHeight - 2);
403                 /** @type {Array<number>} */ var c = es3fFragmentOutputTests.readIVec4(vertices, (cellY * gridWidth + cellX + 1) * numComponents, numComponents); // IVec4
405                 dst.setPixelInt(c, x, y);
406             }
407         }
408     };
410     /**
411      * es3fFragmentOutputTests.s_swizzles
412      * @return {Array<Array<number>>}
413      */
414     es3fFragmentOutputTests.s_swizzles = function() {
415         var mat_swizzles = [
416             [0, 1, 2, 3],
417             [1, 2, 3, 0],
418             [2, 3, 0, 1],
419             [3, 0, 1, 2],
420             [3, 2, 1, 0],
421             [2, 1, 0, 3],
422             [1, 0, 3, 2],
423             [0, 3, 2, 1]
424         ];
426         return mat_swizzles;
427     };
429     /**
430      * es3fFragmentOutputTests.swizzleVec. Returns an Array from a position contained in the Array es3fFragmentOutputTests.s_swizzles []
431      * @param {Array<number>} vec
432      * @param {number} swzNdx
433      * @return {Array<number>} Swizzled array
434      */
435     es3fFragmentOutputTests.swizzleVec = function(vec, swzNdx) {
436     /** @type {Array<number>} */ var swz = es3fFragmentOutputTests.s_swizzles()[swzNdx % es3fFragmentOutputTests.s_swizzles().length];
438         return deMath.swizzle(vec, swz);
439     };
441     /**
442      * es3fFragmentOutputTests.AttachmentData struct class
443      * @constructor
444      * @return {Object}
445      */
446     es3fFragmentOutputTests.AttachmentData = function() {
447         return {
448         /** @type {tcuTexture.TextureFormat} */ format: null, //!< Actual format of attachment.
449         /** @type {tcuTexture.TextureFormat} */ referenceFormat: null, //!< Used for reference rendering.
450         /** @type {tcuTexture.TextureFormat} */ readFormat: null,
451         /** @type {number} */ numWrittenChannels: 0,
452         /** @type {gluShaderUtil.precision} */ outPrecision: gluShaderUtil.precision.PRECISION_LOWP,
453         /** @type {ArrayBuffer} */ renderedData: null,
454         /** @type {ArrayBuffer} */ referenceData: null
455         };
456     };
458     es3fFragmentOutputTests.FragmentOutputCase.prototype.iterate = function() {
459         // Compute grid size & index list.
460         /** @type {number} */ var minCellSize = 8;
461         /** @type {Array<number>} */ var minBufSize = es3fFragmentOutputTests.getMinSize(this.m_fboSpec); // IVec2
462         /** @type {number} */ var gridWidth = deMath.clamp(Math.floor(minBufSize[0] / minCellSize), 1, 255) + 1;
463         /** @type {number} */ var gridHeight = deMath.clamp(Math.floor(minBufSize[1] / minCellSize), 1, 255) + 1;
464         /** @type {number} */ var numVertices = gridWidth * gridHeight;
465         /** @type {number} */ var numQuads = (gridWidth - 1) * (gridHeight - 1);
466         /** @type {number} */ var numIndices = numQuads * 6;
468         /** @type {number} */ var numInputVecs = es3fFragmentOutputTests.getNumInputVectors(this.m_outputs);
469         /** @type {Array<Array<number>>} */ var inputs = []; // originally vector<vector<deUint32>
471         for (var inputNdx = 0; inputNdx < numInputVecs; inputNdx++)
472             inputs[inputNdx] = []; // inputs.length = numInputVecs;
474         /** @type {Array<number>} */ var positions = []; // originally vector<float>
475         /** @type {Array<number>} */ var indices = []; // originally vector<deUint16>
477         /** @type {number} */ var readAlignment = 4;
478         /** @type {number} */ var viewportW = minBufSize[0];
479         /** @type {number} */ var viewportH = minBufSize[1];
480         /** @type {number} */ var numAttachments = this.m_fboSpec.length;
482         /** @type {Array<number>} */ var drawBuffers = []; // originally vector<deUint32>
483         /** @type {Array<es3fFragmentOutputTests.AttachmentData>} */ var attachments = [];
484         /** @type {number} */ var attachmentW;
485         /** @type {number} */ var attachmentH;
487         // Initialize attachment data.
488         for (var ndx = 0; ndx < numAttachments; ndx++) {
489             /** @type {tcuTexture.TextureFormat} */ var texFmt = gluTextureUtil.mapGLInternalFormat(this.m_fboSpec[ndx].format);
490             /** @type {tcuTexture.TextureChannelClass} */ var chnClass = tcuTexture.getTextureChannelClass(texFmt.type);
491             /** @type {boolean} */ var isFixedPoint = (chnClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT ||
492                                                               chnClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT);
494             // \note Fixed-point formats use float reference to enable more accurate result verification.
495             /** @type {tcuTexture.TextureFormat} */ var refFmt = isFixedPoint ? new tcuTexture.TextureFormat(texFmt.order, tcuTexture.ChannelType.FLOAT) : texFmt;
496             /** @type {tcuTexture.TextureFormat} */ var readFmt = es3fFboTestUtil.getFramebufferReadFormat(texFmt);
497             attachmentW = this.m_fboSpec[ndx].width;
498             attachmentH = this.m_fboSpec[ndx].height;
500             drawBuffers[ndx] = gl.COLOR_ATTACHMENT0 + ndx;
501             attachments[ndx] = new es3fFragmentOutputTests.AttachmentData();
502             attachments[ndx].format = texFmt;
503             attachments[ndx].readFormat = readFmt;
504             attachments[ndx].referenceFormat = refFmt;
505             attachments[ndx].renderedData = new ArrayBuffer(readFmt.getPixelSize() * attachmentW * attachmentH);
506             attachments[ndx].referenceData = new ArrayBuffer(refFmt.getPixelSize() * attachmentW * attachmentH);
507         }
509         // Initialize indices.
510         for (var quadNdx = 0; quadNdx < numQuads; quadNdx++) {
511             /** @type {number} */ var quadY = Math.floor(quadNdx / (gridWidth - 1));
512             /** @type {number} */ var quadX = quadNdx - quadY * (gridWidth - 1);
514             indices[quadNdx * 6 + 0] = quadX + quadY * gridWidth;
515             indices[quadNdx * 6 + 1] = quadX + (quadY + 1) * gridWidth;
516             indices[quadNdx * 6 + 2] = quadX + quadY * gridWidth + 1;
517             indices[quadNdx * 6 + 3] = indices[quadNdx * 6 + 1];
518             indices[quadNdx * 6 + 4] = quadX + (quadY + 1) * gridWidth + 1;
519             indices[quadNdx * 6 + 5] = indices[quadNdx * 6 + 2];
520         }
522         /** @type {number} */ var xf = 0;
523         /** @type {number} */ var yf = 0;
524         for (var y = 0; y < gridHeight; y++) {
525             for (var x = 0; x < gridWidth; x++) {
526                 xf = x / (gridWidth - 1);
527                 yf = y / (gridHeight - 1);
529                 positions[(y * gridWidth + x) * 4 + 0] = 2.0 * xf - 1.0;
530                 positions[(y * gridWidth + x) * 4 + 1] = 2.0 * yf - 1.0;
531                 positions[(y * gridWidth + x) * 4 + 2] = 0.0;
532                 positions[(y * gridWidth + x) * 4 + 3] = 1.0;
533             }
534         }
535         /** @type {es3fFragmentOutputTests.FragmentOutput} */ var output;
536         /** @type {boolean} */ var isArray;
537         /** @type {boolean} */ var isFloat;
538         /** @type {boolean} */ var isInt;
539         /** @type {boolean} */ var isUint;
540         /** @type {number} */ var numVecs;
541         /** @type {number} */ var numScalars;
543         var curInVec = 0;
544         for (var outputNdx = 0; outputNdx < this.m_outputs.length; outputNdx++) {
545             output = this.m_outputs[outputNdx];
546             isFloat = gluShaderUtil.isDataTypeFloatOrVec(output.type);
547             isInt = gluShaderUtil.isDataTypeIntOrIVec(output.type);
548             isUint = gluShaderUtil.isDataTypeUintOrUVec(output.type);
549             numVecs = output.arrayLength > 0 ? output.arrayLength : 1;
550             numScalars = gluShaderUtil.getDataTypeScalarSize(output.type);
552             for (var vecNdx = 0; vecNdx < numVecs; vecNdx++) {
553                 inputs[curInVec].length = numVertices * numScalars;
555                 // Record how many outputs are written in attachment.
556                 DE_ASSERT(output.location + vecNdx < attachments.length);
557                 attachments[output.location + vecNdx].numWrittenChannels = numScalars;
558                 attachments[output.location + vecNdx].outPrecision = output.precision;
560                 /** @type {Array<number>} */ var range = null;
561                 /** @type {Array<number>} */ var minVal = null;
562                 /** @type {Array<number>} */ var maxVal = null;
563                 /** @type {Array<number>} */ var fmtBits = null;
564                 /** @type {Array<number>} */ var fmtMaxVal = [];
565                 /** @type {Array<number>} */ var rangeDiv = null;
566                 /** @type {Array<number>} */ var step = [];
567                 /** @type {number} */ var ix = 0;
568                 /** @type {number} */ var iy = 0;
569                 /** @type {Array<number>} */ var c = null;
570                 /** @type {number} */ var pos = 0;
571                if (isFloat) {
572                     range = es3fFragmentOutputTests.getFloatRange(output.precision); // Vec2
573                     minVal = [range[0], range[0], range[0], range[0]]; // Vec4
574                     maxVal = [range[1], range[1], range[1], range[1]]; // Vec4
576                     if (deMath.deInBounds32(output.location + vecNdx, 0, attachments.length)) {
577                     // \note Floating-point precision conversion is not well-defined. For that reason we must
578                     // limit value range to intersection of both data type and render target value ranges.
579                     /** @type {tcuTextureUtil.TextureFormatInfo} */ var fmtInfo = tcuTextureUtil.getTextureFormatInfo(attachments[output.location + vecNdx].format);
580                         minVal = deMath.max(minVal, fmtInfo.valueMin);
581                         maxVal = deMath.min(maxVal, fmtInfo.valueMax);
582                     }
584                     bufferedLogToConsole('out ' + curInVec + ' value range: ' + minVal + ' -> ' + maxVal);
586                     for (var y = 0; y < gridHeight; y++) {
587                         for (var x = 0; x < gridWidth; x++) {
588                             xf = x / (gridWidth - 1);
589                             yf = y / (gridHeight - 1);
590                             /** @type {number} */ var f0 = (xf + yf) * 0.5;
591                             /** @type {number} */ var f1 = 0.5 + (xf - yf) * 0.5;
593                             /** @type {Array<number>} */ var f = es3fFragmentOutputTests.swizzleVec([f0, f1, 1.0 - f0, 1.0 - f1], curInVec); // Vec4
594                             c = deMath.add(minVal, deMath.multiply(deMath.subtract(maxVal, minVal), f)); // Vec4
596                             pos = (y * gridWidth + x) * numScalars;
598                             for (var ndx = 0; ndx < numScalars; ndx++)
599                                 inputs[curInVec][pos + ndx] = c[ndx];
600                         }
601                     }
602                 } else if (isInt) {
603                     range = es3fFragmentOutputTests.getIntRange(output.precision); // IVec2
604                     minVal = [range[0], range[0], range[0], range[0]]; // IVec4
605                     maxVal = [range[1], range[1], range[1], range[1]]; // IVec4
607                     if (deMath.deInBounds32(output.location + vecNdx, 0, attachments.length)) {
608                         // Limit to range of output format as conversion mode is not specified.
609                         fmtBits = tcuTextureUtil.getTextureFormatBitDepth(attachments[output.location + vecNdx].format); // IVec4
610                         /** @type {Array<boolean>} */ var isZero = deMath.lessThanEqual(fmtBits, [0, 0, 0, 0]); // BVec4, array of booleans, size = 4
612                         /** @type {Array<number>} */ var fmtMinVal = []; // IVec4
614                         for (var i = 0; i < 4; i++) {
616                             // const IVec4 fmtMinVal = (-(tcu::Vector<deInt64, 4>(1) << (fmtBits - 1 ).cast<deInt64>())).asInt();
617                             fmtMinVal[i] = -1 * Math.pow(2, fmtBits[i] - 1); // TODO: check implementation, original above
618                             // const IVec4 fmtMaxVal = ((tcu::Vector<deInt64, 4>(1) << (fmtBits - 1 ).cast<deInt64>()) - deInt64(1)).asInt();
619                             fmtMaxVal[i] = Math.pow(2, fmtBits[i] - 1) - 1; // TODO: check implementation, original above
620                         }
622                         minVal = tcuTextureUtil.select(minVal, deMath.max(minVal, fmtMinVal), isZero);
623                         maxVal = tcuTextureUtil.select(maxVal, deMath.min(maxVal, fmtMaxVal), isZero);
624                     }
626                     bufferedLogToConsole('out ' + curInVec + ' value range: ' + minVal + ' -> ' + maxVal);
628                     rangeDiv = es3fFragmentOutputTests.swizzleVec([gridWidth - 1, gridHeight - 1, gridWidth - 1, gridHeight - 1], curInVec); // IVec4
629                     for (var i = 0; i < 4; i++) {
630                         // const IVec4 step = ((maxVal.cast<deInt64>() - minVal.cast<deInt64>()) / (rangeDiv.cast<deInt64>())).asInt();
631                         step[i] = Math.floor((maxVal[i] - minVal[i]) / rangeDiv[i]); // TODO: check with the above line of code
632                     }
634                     for (var y = 0; y < gridHeight; y++) {
635                         for (var x = 0; x < gridWidth; x++) {
636                             ix = gridWidth - x - 1;
637                             iy = gridHeight - y - 1;
638                             c = deMath.add(minVal, deMath.multiply(step, es3fFragmentOutputTests.swizzleVec([x, y, ix, iy], curInVec))); // IVec4
640                             pos = (y * gridWidth + x) * numScalars;
642                             for (var ndx = 0; ndx < numScalars; ndx++)
643                                 inputs[curInVec][pos + ndx] = c[ndx];
644                         }
645                     }
646                 } else if (isUint) {
647                     range = es3fFragmentOutputTests.getUintRange(output.precision); // UVec2
648                     maxVal = [range[1], range[1], range[1], range[1]]; // UVec4
650                     if (deMath.deInBounds32(output.location + vecNdx, 0, attachments.length)) {
651                         // Limit to range of output format as conversion mode is not specified.
652                         fmtBits = tcuTextureUtil.getTextureFormatBitDepth(attachments[output.location + vecNdx].format); // IVec4
654                         for (var i = 0; i < 4; i++) {
655                             fmtMaxVal[i] = Math.pow(2, fmtBits[i]) - 1;
656                         }
658                         maxVal = deMath.min(maxVal, fmtMaxVal);
659                     }
661                     bufferedLogToConsole('out ' + curInVec + ' value range: ' + minVal + ' -> ' + maxVal);
663                     rangeDiv = es3fFragmentOutputTests.swizzleVec([gridWidth - 1, gridHeight - 1, gridWidth - 1, gridHeight - 1], curInVec); // IVec4
665                     for (var stepPos = 0; stepPos < maxVal.length; stepPos++) {
666                         step[stepPos] = Math.floor(maxVal[stepPos] / rangeDiv[stepPos]);
667                     }
669                     DE_ASSERT(range[0] == 0);
671                     for (var y = 0; y < gridHeight; y++) {
672                         for (var x = 0; x < gridWidth; x++) {
673                             ix = gridWidth - x - 1;
674                             iy = gridHeight - y - 1;
675                             c = deMath.multiply(step, es3fFragmentOutputTests.swizzleVec([x, y, ix, iy], curInVec)); // UVec4
676                             pos = (y * gridWidth + x) * numScalars;
678                             DE_ASSERT(deMath.boolAll(deMath.lessThanEqual(c, maxVal))); // TODO: sometimes crashes here, condition not asserted
680                             for (var ndx = 0; ndx < numScalars; ndx++)
681                                 inputs[curInVec][pos + ndx] = c[ndx];
682                         }
683                     }
684                 } else
685                     DE_ASSERT(false);
687                 curInVec += 1;
688             }
689         }
691         // Render using gl.
692         gl.useProgram(this.m_program.getProgram());
693         gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
694         gl.viewport(0, 0, viewportW, viewportH);
695         gl.drawBuffers(drawBuffers);
696         gl.disable(gl.DITHER); // Dithering causes issues with unorm formats. Those issues could be worked around in threshold, but it makes validation less accurate.
698         /** @type {WebGLBuffer} */ var buffer = null;
699         /** @type {string} */ var name;
700         curInVec = 0;
701         for (var outputNdx = 0; outputNdx < this.m_outputs.length; outputNdx++) {
702             output = this.m_outputs[outputNdx];
703             isArray = output.arrayLength > 0;
704             isFloat = gluShaderUtil.isDataTypeFloatOrVec(output.type);
705             isInt = gluShaderUtil.isDataTypeIntOrIVec(output.type);
706             isUint = gluShaderUtil.isDataTypeUintOrUVec(output.type);
707             /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(output.type);
708             /** @type {number} */ var glScalarType = isFloat ? /* gluShaderUtil.DataType.FLOAT */ gl.FLOAT :
709                                                      isInt ? /* gluShaderUtil.DataType.INT */ gl.INT :
710                                                      isUint ? /* gluShaderUtil.DataType.UINT */ gl.UNSIGNED_INT : /* gluShaderUtil.DataType.INVALID */ gl.NONE;
711             numVecs = isArray ? output.arrayLength : 1;
713             for (var vecNdx = 0; vecNdx < numVecs; vecNdx++) {
714                 name = 'in' + outputNdx + (isArray ? '_' + vecNdx : '');
715                 /** @type {number} */ var loc = gl.getAttribLocation(this.m_program.getProgram(), name);
717                 if (loc >= 0) {
718                     buffer = gl.createBuffer();
719                     gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
721                     gl.enableVertexAttribArray(loc);
722                     if (isFloat) {
723                         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(inputs[curInVec]), gl.STATIC_DRAW);
724                         // KHRONOS WebGL 1.0 specification:
725                         // void vertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
726                         gl.vertexAttribPointer(loc, scalarSize, glScalarType, false, 0, 0); // offset = 0
727                     } else {
728                         gl.bufferData(gl.ARRAY_BUFFER, new Int32Array(inputs[curInVec]), gl.STATIC_DRAW);
729                         // KHRONOS WebGL 2.0 specification:
730                         // void vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
731                         gl.vertexAttribIPointer(loc, scalarSize, glScalarType, 0, 0); // offset = 0
732                     }
733                 } else
734                     bufferedLogToConsole('Warning: No location for attribute "' + name + '" found.');
736                 curInVec += 1;
737             }
738         }
740         /** @type {number} */ var posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
741         // TCU_CHECK(posLoc >= 0);
742         buffer = gl.createBuffer();
743         gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
744         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
746         gl.enableVertexAttribArray(posLoc);
747         gl.vertexAttribPointer(posLoc, 4, gl.FLOAT, false, 0, 0); // offset = 0
749         /** @type {WebGLBuffer} */ var indexObject = gl.createBuffer();
750         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
751         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
753         gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0); // offset = 0
755         // Render reference images.
757         var curInNdx = 0;
758         for (var outputNdx = 0; outputNdx < this.m_outputs.length; outputNdx++) {
759             output = this.m_outputs[outputNdx];
760             isArray = output.arrayLength > 0;
761             isFloat = gluShaderUtil.isDataTypeFloatOrVec(output.type);
762             isInt = gluShaderUtil.isDataTypeIntOrIVec(output.type);
763             isUint = gluShaderUtil.isDataTypeUintOrUVec(output.type);
764             scalarSize = gluShaderUtil.getDataTypeScalarSize(output.type);
765             numVecs = isArray ? output.arrayLength : 1;
767             for (var vecNdx = 0; vecNdx < numVecs; vecNdx++) {
768                 /** @type {number} */ var location = output.location + vecNdx;
769                 /** @type {Array<number>} */ var inputData = inputs[curInNdx];
771                 DE_ASSERT(deMath.deInBounds32(location, 0, this.m_fboSpec.length));
773                 /** @type {number} */ var bufW = this.m_fboSpec[location].width;
774                 /** @type {number} */ var bufH = this.m_fboSpec[location].height;
775                 /** @type {Object} */ var descriptor = {
776                         format: attachments[location].referenceFormat,
777                         width: bufW,
778                         height: bufH,
779                         depth: 1,
780                         data: attachments[location].referenceData // ArrayBuffer
781                 };
782                 /** @type {tcuTexture.PixelBufferAccess} */ var buf = new tcuTexture.PixelBufferAccess(descriptor);
783                 /** @type {tcuTexture.PixelBufferAccess} */ var viewportBuf = tcuTextureUtil.getSubregion(buf, 0, 0, 0, viewportW, viewportH, 1);
785                 if (isInt || isUint)
786                     es3fFragmentOutputTests.renderIntReference(viewportBuf, gridWidth, gridHeight, scalarSize, inputData);
787                 else if (isFloat)
788                     es3fFragmentOutputTests.renderFloatReference(viewportBuf, gridWidth, gridHeight, scalarSize, inputData);
789                 else
790                     DE_ASSERT(false);
792                 curInNdx += 1;
793             }
794         }
796         // Compare all images.
797         /** @type {boolean} */ var allLevelsOk = true;
798         for (var attachNdx = 0; attachNdx < numAttachments; attachNdx++) {
799             attachmentW = this.m_fboSpec[attachNdx].width;
800             attachmentH = this.m_fboSpec[attachNdx].height;
801             /** @type {number} */ var numValidChannels = attachments[attachNdx].numWrittenChannels;
802             /** @type {Array<boolean>} */ var cmpMask = [numValidChannels >= 1, numValidChannels >= 2, numValidChannels >= 3, numValidChannels >= 4];
803             /** @type {gluShaderUtil.precision} */ var outPrecision = attachments[attachNdx].outPrecision;
804             /** @type {tcuTexture.TextureFormat} */ var format = attachments[attachNdx].format;
805             /** @type {Object} */
806             var renderedDescriptor = {
807                     format: attachments[attachNdx].readFormat,
808                     width: attachmentW,
809                     height: attachmentH,
810                     depth: 1,
811                     rowPitch: deMath.deAlign32(attachments[attachNdx].readFormat.getPixelSize() * attachmentW, readAlignment),
812                     slicePitch: 0,
813                     data: attachments[attachNdx].renderedData // ArrayBuffer
814             };
815             /** @type {tcuTexture.PixelBufferAccess} */ var rendered = new tcuTexture.PixelBufferAccess(renderedDescriptor);
816             /** @type {gluTextureUtil.TransferFormat} */ var transferFmt = gluTextureUtil.getTransferFormat(attachments[attachNdx].readFormat);
817             gl.readBuffer(gl.COLOR_ATTACHMENT0 + attachNdx);
818             gl.readPixels(0, 0, attachmentW, attachmentH, transferFmt.format, transferFmt.dataType, rendered.getDataPtr());
820             /** @type {Object} */
821             var referenceDescriptor = {
822                     format: attachments[attachNdx].referenceFormat,
823                     width: attachmentW,
824                     height: attachmentH,
825                     depth: 1,
826                     data: attachments[attachNdx].referenceData // ArrayBuffer
827             };
828             /** @type {tcuTexture.ConstPixelBufferAccess} */ var reference = new tcuTexture.ConstPixelBufferAccess(referenceDescriptor);
829             /** @type {tcuTexture.TextureChannelClass} */ var texClass = tcuTexture.getTextureChannelClass(format.type);
830             /** @type {boolean} */ var isOk = true;
831             name = 'Attachment ' + attachNdx;
832             /** @type {string} */ var desc = 'Color attachment ' + attachNdx;
833             /** @type {Array<number>} */ var threshold;
835             bufferedLogToConsole('Attachment ' + attachNdx + ': ' + numValidChannels + ' channels have defined values and used for comparison');
837             switch (texClass) {
838                 case tcuTexture.TextureChannelClass.FLOATING_POINT: {
839                     /** @type {Array<number>} */ var formatThreshold = []; // UVec4 //!< Threshold computed based on format.
840                     formatThreshold.length = 4;
841                     /** @type {number} */ var precThreshold = 0; // deUint32 //!< Threshold computed based on output type precision
842                     /** @type {Array<number>} */ var finalThreshold = []; // UVec4
843                     finalThreshold.length = 4;
845                     switch (format.type) {
846                         case tcuTexture.ChannelType.FLOAT:
847                             formatThreshold = [4, 4, 4, 4]; // UVec4
848                             break;
849                         case tcuTexture.ChannelType.HALF_FLOAT:
850                             formatThreshold = [(1 << 13) + 4, (1 << 13) + 4, (1 << 13) + 4, (1 << 13) + 4]; // UVec4
851                             break;
852                         case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV:
853                             formatThreshold = [(1 << 17) + 4, (1 << 17) + 4, (1 << 18) + 4, 4]; // UVec4
854                             break;
855                         default:
856                             DE_ASSERT(false);
857                             break;
858                     }
860                     switch (outPrecision) {
861                         case gluShaderUtil.precision.PRECISION_LOWP:
862                             precThreshold = (1 << 21);
863                             break;
864                         case gluShaderUtil.precision.PRECISION_MEDIUMP:
865                             precThreshold = (1 << 13);
866                             break;
867                         case gluShaderUtil.precision.PRECISION_HIGHP:
868                             precThreshold = 0;
869                             break;
870                         default:
871                             DE_ASSERT(false);
872                     }
874                     finalThreshold = tcuTextureUtil.select(
875                                     deMath.max(formatThreshold, [precThreshold, precThreshold, precThreshold, precThreshold]),
876                                     [0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff], // C++ version: UVec4(~0u) bitwise not, all bits in the integer will be flipped
877                                     cmpMask);
879                     isOk = tcuImageCompare.floatUlpThresholdCompare(name, desc, reference, rendered, finalThreshold /*, tcu::COMPARE_LOG_RESULT*/);
880                     break;
881                 }
883                 case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: {
884                     // \note glReadPixels() allows only 8 bits to be read. This means that RGB10_A2 will loose some
885                     // bits in the process and it must be taken into account when computing threshold.
886                     /** @type {Array<number>} */ var bits = deMath.min([8, 8, 8, 8], tcuTextureUtil.getTextureFormatBitDepth(format)); // IVec4
888                     /** @type {Array<number>} */ var baseThreshold = []; // Vec4
889                     baseThreshold.length = 4;
890                     for (var inc = 0; inc < baseThreshold.length; inc++) {
891                         // TODO: check the operation below: baseThreshold = 1.0f / ((IVec4(1) << bits)-1).asFloat();
892                         baseThreshold[inc] = 1.0 / ((1 << bits[inc]) - 1);
893                     }
895                     threshold = tcuTextureUtil.select(baseThreshold, [2.0, 2.0, 2.0, 2.0], cmpMask); // Vec4
897                     isOk = tcuImageCompare.floatThresholdCompare(name, desc, reference, rendered, threshold/*, tcu::COMPARE_LOG_RESULT*/);
898                     break;
899                 }
901                 case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
902                 case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: {
903                     // The C++ dEQP code uses ~0u but ~0 is -1 in Javascript
904                     var UINT_MAX = Math.pow(2.0, 32.0) - 1;
905                     threshold = tcuTextureUtil.select(
906                                     [0, 0, 0, 0],
907                                     [UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX],
908                                     cmpMask
909                                     ); // UVec4
910                     isOk = tcuImageCompare.intThresholdCompare(name, desc, reference, rendered, threshold/*, tcu::COMPARE_LOG_RESULT*/);
911                     break;
912                 }
914                 default:
915                     testFailedOptions('Unsupported comparison', true);
916                     break;
917             }
919             if (!isOk)
920                 allLevelsOk = false;
921         }
923         if (numAttachments > 1) {
924             if (allLevelsOk)
925                 testPassed('Image comparison passed for ' +  numAttachments + ' attachments');
926             else
927                 testFailed('Image comparison failed for some of ' +  numAttachments + ' attachments');
928         } else {
929             if (allLevelsOk)
930                 testPassed('Image comparison passed');
931             else
932                 testFailed('Image comparison failed');
933         }
935         return tcuTestCase.IterateResult.STOP;
936     };
938     /**
939      * es3fFragmentOutputTests.createRandomCase. Constructs the es3fFragmentOutputTests.createRandomCase, child class of es3fFragmentOutputTests.FragmentOutputCase
940      * @constructor
941      * @param {number} minRenderTargets
942      * @param {number} maxRenderTargets
943      * @param {number} seed
944      * @return {es3fFragmentOutputTests.FragmentOutputCase} The currently modified object
945      */
946     es3fFragmentOutputTests.createRandomCase = function(minRenderTargets, maxRenderTargets, seed, colorBufferFloatSupported) {
948         /** @type {Array<gluShaderUtil.DataType>} */
949         var outputTypes = [
950                            gluShaderUtil.DataType.FLOAT,
951                            gluShaderUtil.DataType.FLOAT_VEC2,
952                            gluShaderUtil.DataType.FLOAT_VEC3,
953                            gluShaderUtil.DataType.FLOAT_VEC4,
954                            gluShaderUtil.DataType.INT,
955                            gluShaderUtil.DataType.INT_VEC2,
956                            gluShaderUtil.DataType.INT_VEC3,
957                            gluShaderUtil.DataType.INT_VEC4,
958                            gluShaderUtil.DataType.UINT,
959                            gluShaderUtil.DataType.UINT_VEC2,
960                            gluShaderUtil.DataType.UINT_VEC3,
961                            gluShaderUtil.DataType.UINT_VEC4
962                            ];
964         /** @type {Array<gluShaderUtil.precision>} */
965         var precisions = [
966                           gluShaderUtil.precision.PRECISION_LOWP,
967                           gluShaderUtil.precision.PRECISION_MEDIUMP,
968                           gluShaderUtil.precision.PRECISION_HIGHP
969                           ];
971         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
972         var floatFormats = [
973                             gl.RGBA32F,
974                             gl.RGBA16F,
975                             gl.R11F_G11F_B10F,
976                             gl.RG32F,
977                             gl.RG16F,
978                             gl.R32F,
979                             gl.R16F,
980                             gl.RGBA8,
981                             gl.SRGB8_ALPHA8,
982                             gl.RGB10_A2,
983                             gl.RGBA4,
984                             gl.RGB5_A1,
985                             gl.RGB8,
986                             gl.RGB565,
987                             gl.RG8,
988                             gl.R8
989                             ];
991         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
992         var colorBufferFloatFormats = [
993                                        gl.RGBA32F,
994                                        gl.RGBA16F,
995                                        gl.R11F_G11F_B10F,
996                                        gl.RG32F,
997                                        gl.RG16F,
998                                        gl.R32F,
999                                        gl.R16F
1000         ];
1003         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1004         var intFormats = [
1005                             gl.RGBA32I,
1006                             gl.RGBA16I,
1007                             gl.RGBA8I,
1008                             gl.RG32I,
1009                             gl.RG16I,
1010                             gl.RG8I,
1011                             gl.R32I,
1012                             gl.R16I,
1013                             gl.R8I
1014                             ];
1016         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1017         var uintFormats = [
1018                            gl.RGBA32UI,
1019                            gl.RGBA16UI,
1020                            gl.RGBA8UI,
1021                            gl.RGB10_A2UI,
1022                            gl.RG32UI,
1023                            gl.RG16UI,
1024                            gl.RG8UI,
1025                            gl.R32UI,
1026                            gl.R16UI,
1027                            gl.R8UI
1028                            ];
1030         /** @type {deRandom.Random} */ var rnd = new deRandom.Random(seed);
1031         /** @type {Array<es3fFragmentOutputTests.FragmentOutput>} */ var outputs = [];
1032         /** @type {Array<es3fFragmentOutputTests.BufferSpec>} */ var targets = [];
1033         /** @type {Array<gluShaderUtil.DataType>} */ var outTypes = [];
1035         /** @type {number} */ var numTargets = rnd.getInt(minRenderTargets, maxRenderTargets);
1036         /** @type {number} */ var width = 128; // \todo [2012-04-10 pyry] Separate randomized sizes per target?
1037         /** @type {number} */ var height = 64;
1038         /** @type {number} */ var samples = 0;
1040         // Compute outputs.
1041         /** @type {number} */ var curLoc = 0;
1042         while (curLoc < numTargets) {
1043             /** @type {boolean} */ var useArray = rnd.getFloat() < 0.3;
1044             /** @type {number} */ var maxArrayLen = numTargets - curLoc;
1045             /** @type {number} */ var arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 0;
1046             /** @type {Array<gluShaderUtil.DataType>} */ var basicTypeArray = rnd.choose(outputTypes, undefined, 1);
1047             /** @type {gluShaderUtil.DataType} */ var basicType = basicTypeArray[0];
1048             /** @type {Array<gluShaderUtil.precision>} */ var precisionArray = rnd.choose(precisions, undefined, 1);
1049             /** @type {gluShaderUtil.precision} */ var precision = precisionArray[0];
1050             /** @type {number} */ var numLocations = useArray ? arrayLen : 1;
1052             outputs.push(new es3fFragmentOutputTests.FragmentOutput(basicType, precision, curLoc, arrayLen));
1054             for (var ndx = 0; ndx < numLocations; ndx++)
1055                 outTypes.push(basicType);
1057             curLoc += numLocations;
1058         }
1059         DE_ASSERT(curLoc == numTargets);
1060         DE_ASSERT(outTypes.length == numTargets);
1062         // Compute buffers.
1063         while (targets.length < numTargets) {
1064             /** @type {gluShaderUtil.DataType} */ var outType = outTypes[targets.length];
1065             /** @type {boolean} */ var isFloat = gluShaderUtil.isDataTypeFloatOrVec(outType);
1066             /** @type {boolean} */ var isInt = gluShaderUtil.isDataTypeIntOrIVec(outType);
1067             /** @type {boolean} */ var isUint = gluShaderUtil.isDataTypeUintOrUVec(outType);
1068             /** @type {Array} */ var formatArray = [];
1069             /** @type {number} */ var format = 0;
1071             if (isFloat) {
1072                 formatArray = rnd.choose(floatFormats, undefined, 1);
1073                 format = formatArray[0];
1074                 if (colorBufferFloatFormats.indexOf(format) >= 0 && !colorBufferFloatSupported)
1075                     return null;
1076             } else if (isInt) {
1077                 formatArray = rnd.choose(intFormats, undefined, 1);
1078                 format = formatArray[0];
1079             } else if (isUint) {
1080                 formatArray = rnd.choose(uintFormats, undefined, 1);
1081                 format = formatArray[0];
1082             } else
1083                 DE_ASSERT(false);
1085             targets.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1086         }
1088         return new es3fFragmentOutputTests.FragmentOutputCase(seed.toString(), '', targets, outputs);
1090     };
1092     es3fFragmentOutputTests.init = function(gl) {
1093         var state = tcuTestCase.runner;
1094         state.testCases = tcuTestCase.newTest('fragment_outputs', 'Top level');
1095         /** @const @type {tcuTestCase.DeqpTest} */ var testGroup = state.testCases;
1097         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1098         var requiredFloatFormats = [
1099             gl.RGBA32F,
1100             gl.RGBA16F,
1101             gl.R11F_G11F_B10F,
1102             gl.RG32F,
1103             gl.RG16F,
1104             gl.R32F,
1105             gl.R16F
1106         ];
1108         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1109         var requiredFixedFormats = [
1110             gl.RGBA8,
1111             gl.SRGB8_ALPHA8,
1112             gl.RGB10_A2,
1113             gl.RGBA4,
1114             gl.RGB5_A1,
1115             gl.RGB8,
1116             gl.RGB565,
1117             gl.RG8,
1118             gl.R8
1119         ];
1121         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1122         var requiredIntFormats = [
1123             gl.RGBA32I,
1124             gl.RGBA16I,
1125             gl.RGBA8I,
1126             gl.RG32I,
1127             gl.RG16I,
1128             gl.RG8I,
1129             gl.R32I,
1130             gl.R16I,
1131             gl.R8I
1132         ];
1134         /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1135         var requiredUintFormats = [
1136             gl.RGBA32UI,
1137             gl.RGBA16UI,
1138             gl.RGBA8UI,
1139             gl.RGB10_A2UI,
1140             gl.RG32UI,
1141             gl.RG16UI,
1142             gl.RG8UI,
1143             gl.R32UI,
1144             gl.R16UI,
1145             gl.R8UI
1146         ];
1148         /** @type {Array<gluShaderUtil.precision>} */
1149         var precisions = [
1151             gluShaderUtil.precision.PRECISION_LOWP,
1152             gluShaderUtil.precision.PRECISION_MEDIUMP,
1153             gluShaderUtil.precision.PRECISION_HIGHP
1155         ];
1157      // .basic.
1159         /** @const @type {number} */ var width = 64;
1160         /** @const @type {number} */ var height = 64;
1161         /** @const @type {number} */ var samples = 0;
1162         /** @type {Array<es3fFragmentOutputTests.BufferSpec>} */ var fboSpec = null;
1163         /** @type {gluShaderUtil.precision} */ var prec;
1164         /** @type {string} */ var precName;
1166     // .float
1167         if (gl.getExtension('EXT_color_buffer_float')) {
1168             /** @type {tcuTestCase.DeqpTest} */ var floatGroup = tcuTestCase.newTest('basic.float', 'Floating-point output tests');
1169             testGroup.addChild(floatGroup);
1171             for (var fmtNdx = 0; fmtNdx < requiredFloatFormats.length; fmtNdx++) {
1172                 var format = requiredFloatFormats[fmtNdx];
1173                 var fmtName = es3fFboTestUtil.getFormatName(format);
1174                 fboSpec = [];
1176                 fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1178                 for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1179                     prec = precisions[precNdx];
1180                     precName = gluShaderUtil.getPrecisionName(prec);
1182                     // NOTE: Eliminated original OutputVec and toVec(), as it only returned an element of the outputs array in OutputVec
1183                     floatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_float', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT, prec, 0)]));
1184                     floatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC2, prec, 0)]));
1185                     floatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC3, prec, 0)]));
1186                     floatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC4, prec, 0)]));
1187                 }
1188             }
1189         }
1191         // .fixed
1192         /** @type {tcuTestCase.DeqpTest} */ var fixedGroup = tcuTestCase.newTest('basic.fixed', 'Fixed-point output tests');
1193         testGroup.addChild(fixedGroup);
1194         for (var fmtNdx = 0; fmtNdx < requiredFixedFormats.length; fmtNdx++) {
1195             var format = requiredFixedFormats[fmtNdx];
1196             var fmtName = es3fFboTestUtil.getFormatName(format);
1197             fboSpec = [];
1199             fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1201             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1202                 prec = precisions[precNdx];
1203                 precName = gluShaderUtil.getPrecisionName(prec);
1205                 fixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_float', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT, prec, 0)]));
1206                 fixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC2, prec, 0)]));
1207                 fixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC3, prec, 0)]));
1208                 fixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC4, prec, 0)]));
1209             }
1210         }
1212         // .int
1213         /** @type {tcuTestCase.DeqpTest} */ var intGroup = tcuTestCase.newTest('basic.int', 'Integer output tests');
1214         testGroup.addChild(intGroup);
1215         for (var fmtNdx = 0; fmtNdx < requiredIntFormats.length; fmtNdx++) {
1216             var format = requiredIntFormats[fmtNdx];
1217             var fmtName = es3fFboTestUtil.getFormatName(format);
1218             fboSpec = [];
1220             fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1222             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1223                 prec = precisions[precNdx];
1224                 precName = gluShaderUtil.getPrecisionName(prec);
1226                 intGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_int', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT, prec, 0)]));
1227                 intGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC2, prec, 0)]));
1228                 intGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC3, prec, 0)]));
1229                 intGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC4, prec, 0)]));
1230             }
1231         }
1233         // .uint
1234         /** @type {tcuTestCase.DeqpTest} */ var uintGroup = tcuTestCase.newTest('basic.uint', 'Usigned integer output tests');
1235         testGroup.addChild(uintGroup);
1236         for (var fmtNdx = 0; fmtNdx < requiredUintFormats.length; fmtNdx++) {
1237             var format = requiredUintFormats[fmtNdx];
1238             var fmtName = es3fFboTestUtil.getFormatName(format);
1239             fboSpec = [];
1241             fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1243             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1244                 prec = precisions[precNdx];
1245                 precName = gluShaderUtil.getPrecisionName(prec);
1247                 uintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uint', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT, prec, 0)]));
1248                 uintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC2, prec, 0)]));
1249                 uintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC3, prec, 0)]));
1250                 uintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC4, prec, 0)]));
1252             }
1253         }
1255      // .array
1257         /** @type {number} */ var numTargets = 3;
1259         // .float
1260         if (gl.getExtension('EXT_color_buffer_float')) {
1261             /** @type {tcuTestCase.DeqpTest} */ var arrayFloatGroup = tcuTestCase.newTest('array.float', 'Floating-point output tests');
1262             testGroup.addChild(arrayFloatGroup);
1263             for (var fmtNdx = 0; fmtNdx < requiredFloatFormats.length; fmtNdx++) {
1264                 var format = requiredFloatFormats[fmtNdx];
1265                 var fmtName = es3fFboTestUtil.getFormatName(format);
1266                 fboSpec = [];
1268                 for (var ndx = 0; ndx < numTargets; ndx++)
1269                     fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1271                 for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1272                     prec = precisions[precNdx];
1273                     precName = gluShaderUtil.getPrecisionName(prec);
1275                     arrayFloatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_float', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT, prec, 0, numTargets)]));
1276                     arrayFloatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC2, prec, 0, numTargets)]));
1277                     arrayFloatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC3, prec, 0, numTargets)]));
1278                     arrayFloatGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC4, prec, 0, numTargets)]));
1279                 }
1280             }
1281         }
1283         // .fixed
1284         /** @type {tcuTestCase.DeqpTest} */ var arrayFixedGroup = tcuTestCase.newTest('array.fixed', 'Fixed-point output tests');
1285         testGroup.addChild(arrayFixedGroup);
1286         for (var fmtNdx = 0; fmtNdx < requiredFixedFormats.length; fmtNdx++) {
1287             var format = requiredFixedFormats[fmtNdx];
1288             var fmtName = es3fFboTestUtil.getFormatName(format);
1289             fboSpec = [];
1291             for (var ndx = 0; ndx < numTargets; ndx++)
1292                 fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1294             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1295                 prec = precisions[precNdx];
1296                 precName = gluShaderUtil.getPrecisionName(prec);
1298                 arrayFixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_float', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT, prec, 0, numTargets)]));
1299                 arrayFixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC2, prec, 0, numTargets)]));
1300                 arrayFixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC3, prec, 0, numTargets)]));
1301                 arrayFixedGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_vec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.FLOAT_VEC4, prec, 0, numTargets)]));
1302             }
1303         }
1305         // .int
1306         /** @type {tcuTestCase.DeqpTest} */ var arrayIntGroup = tcuTestCase.newTest('array.int', 'Integer output tests');
1307         testGroup.addChild(arrayIntGroup);
1308         for (var fmtNdx = 0; fmtNdx < requiredIntFormats.length; fmtNdx++) {
1309             var format = requiredIntFormats[fmtNdx];
1310             var fmtName = es3fFboTestUtil.getFormatName(format);
1311             fboSpec = [];
1313             for (var ndx = 0; ndx < numTargets; ndx++)
1314                 fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1316             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1317                 prec = precisions[precNdx];
1318                 precName = gluShaderUtil.getPrecisionName(prec);
1320                 arrayIntGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_int', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT, prec, 0, numTargets)]));
1321                 arrayIntGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC2, prec, 0, numTargets)]));
1322                 arrayIntGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC3, prec, 0, numTargets)]));
1323                 arrayIntGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_ivec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.INT_VEC4, prec, 0, numTargets)]));
1324             }
1325         }
1327         // .uint
1328         /** @type {tcuTestCase.DeqpTest} */ var arrayUintGroup = tcuTestCase.newTest('array.uint', 'Usigned integer output tests');
1329         testGroup.addChild(arrayUintGroup);
1330         for (var fmtNdx = 0; fmtNdx < requiredUintFormats.length; fmtNdx++) {
1331             var format = requiredUintFormats[fmtNdx];
1332             var fmtName = es3fFboTestUtil.getFormatName(format);
1333             fboSpec = [];
1335             for (var ndx = 0; ndx < numTargets; ndx++)
1336                 fboSpec.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1338             for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
1339                 prec = precisions[precNdx];
1340                 precName = gluShaderUtil.getPrecisionName(prec);
1342                 arrayUintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uint', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT, prec, 0, numTargets)]));
1343                 arrayUintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec2', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC2, prec, 0, numTargets)]));
1344                 arrayUintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec3', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC3, prec, 0, numTargets)]));
1345                 arrayUintGroup.addChild(new es3fFragmentOutputTests.FragmentOutputCase(fmtName + '_' + precName + '_uvec4', '', fboSpec, [new es3fFragmentOutputTests.FragmentOutput(gluShaderUtil.DataType.UINT_VEC4, prec, 0, numTargets)]));
1346             }
1347         }
1349     // .random
1351         /** @type {Array<tcuTestCase.DeqpTest>} */ var randomGroup = [];
1352         var numRandomGroups = 3;
1353         for (var ii = 0; ii < numRandomGroups; ++ii) {
1354             randomGroup[ii] = tcuTestCase.newTest('random', 'Random fragment output cases');
1355             testGroup.addChild(randomGroup[ii]);
1356         }
1358         /** @type {boolean} */ var colorBufferFloatSupported = (gl.getExtension('EXT_color_buffer_float') != null);
1359         for (var seed = 0; seed < 100; seed++) {
1360             var test = es3fFragmentOutputTests.createRandomCase(2, 4, seed, colorBufferFloatSupported);
1361             if (test !== null) {
1362                 randomGroup[seed % numRandomGroups].addChild(test);
1363             }
1364         }
1366     };
1368     /**
1369      * Create and execute the test cases
1370      */
1371     es3fFragmentOutputTests.run = function(context, range) {
1372         gl = context;
1373       //Set up Test Root parameters
1374         var testName = 'fragment_output';
1375         var testDescription = 'Fragment Output Tests';
1376         var state = tcuTestCase.runner;
1378         state.testName = testName;
1379         state.testCases = tcuTestCase.newTest(testName, testDescription, null);
1381       //Set up name and description of this test series.
1382         setCurrentTestName(testName);
1383         description(testDescription);
1385         try {
1386             es3fFragmentOutputTests.init(gl);
1387             if (range)
1388                 state.setRange(range);
1389             tcuTestCase.runTestCases();
1390         } catch (err) {
1391             testFailedOptions('Failed to es3fFragmentOutputTests.run tests', false);
1392             bufferedLogToConsole(err);
1393             tcuTestCase.runner.terminate();
1394         }
1396     };