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.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) {
52 throw new Error('Assert failed');
56 * es3fFragmentOutputTests.BufferSpec. Constructs the es3fFragmentOutputTests.BufferSpec object
58 * @param {WebGLRenderingContextBase.GLenum} format_
59 * @param {number} width_
60 * @param {number} height_
61 * @param {number} samples_
63 es3fFragmentOutputTests.BufferSpec = function(format_, width_, height_, samples_) {
64 this.format = format_;
66 this.height = height_;
67 this.samples = samples_;
71 * es3fFragmentOutputTests.FragmentOutput. Constructs the es3fFragmentOutputTests.FragmentOutput object
73 * @param {gluShaderUtil.DataType} type_
74 * @param {gluShaderUtil.precision} precision_
75 * @param {number} location_
76 * @param {number=} arrayLength_
78 es3fFragmentOutputTests.FragmentOutput = function(type_, precision_, location_, arrayLength_) {
80 this.precision = precision_;
81 this.location = location_;
82 this.arrayLength = arrayLength_ || 0;
86 * es3fFragmentOutputTests.FragmentOutputCase. Constructs the es3fFragmentOutputTests.FragmentOutputCase object
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
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;
105 es3fFragmentOutputTests.FragmentOutputCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
106 es3fFragmentOutputTests.FragmentOutputCase.prototype.constructor = es3fFragmentOutputTests.FragmentOutputCase;
109 * es3fFragmentOutputTests.createProgram. Returns a ShaderProgram object
110 * @param {Array<es3fFragmentOutputTests.FragmentOutput>} outputs
111 * @return {gluShaderProgram.ShaderProgram} program
113 es3fFragmentOutputTests.createProgram = function(outputs) {
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';
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';
138 frag += 'layout(location = ' + output.location + ') out ' + precName + ' ' + typeName + ' out' + outNdx + '[' + output.arrayLength + '];\n';
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';
147 vtx += '\nvoid main()\n{\n';
148 frag += '\nvoid main()\n{\n';
150 vtx += ' gl_Position = a_position;\n';
153 for (var outNdx = 0; outNdx < outputs.length; outNdx++) {
154 output = outputs[outNdx];
155 isArray = output.arrayLength > 0;
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';
163 vtx += '\tvar' + outNdx + ' = in' + outNdx + ';\n';
164 frag += '\tout' + outNdx + ' = var' + outNdx + ';\n';
171 /** @type {gluShaderProgram.ShaderProgram} */
172 var program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
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');
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');
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);
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);
229 es3fFragmentOutputTests.FragmentOutputCase.prototype.deinit = function() {
234 * es3fFragmentOutputTests.getMinSize.
235 * @param {Array<es3fFragmentOutputTests.BufferSpec>} fboSpec
236 * @return {Array<number>} minSize
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);
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
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);
260 * es3fFragmentOutputTests.getFloatRange
261 * @param {gluShaderUtil.precision} precision
262 * @return {Array<number>} Vec2
264 es3fFragmentOutputTests.getFloatRange = function(precision) {
265 /** @type {Array<Array<number>>} */
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];
278 * es3fFragmentOutputTests.getIntRange
279 * @param {gluShaderUtil.precision} precision
280 * @return {Array<number>} IVec2
282 es3fFragmentOutputTests.getIntRange = function(precision) {
283 /** @type {Array<Array<number>>} */
284 var ranges = // IVec2
286 [-(1 << 7), (1 << 7) - 1],
287 [-(1 << 15), (1 << 15) - 1],
288 [-0x80000000, 0x7fffffff]
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];
296 * es3fFragmentOutputTests.getUintRange
297 * @param {gluShaderUtil.precision} precision
298 * @return {Array<number>} UVec2
300 es3fFragmentOutputTests.getUintRange = function(precision) {
301 /** @type {Array<Array<number>>} */
302 var ranges = // UVec2
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];
315 * es3fFragmentOutputTests.readVec4
316 * @param {Array<number>} ptr
317 * @param {number} index
318 * @param {number} numComponents
319 * @return {Array<number>} Vec4
321 es3fFragmentOutputTests.readVec4 = function(ptr, index, numComponents) {
322 DE_ASSERT(numComponents >= 1);
325 numComponents >= 2 ? ptr[index + 1] : 0.0,
326 numComponents >= 3 ? ptr[index + 2] : 0.0,
327 numComponents >= 4 ? ptr[index + 3] : 0.0
332 * es3fFragmentOutputTests.readIVec4
333 * @param {Array<number>} ptr
334 * @param {number} numComponents
335 * @return {Array<number>} IVec4
337 es3fFragmentOutputTests.readIVec4 = function(ptr, index, numComponents) {
338 DE_ASSERT(numComponents >= 1);
341 numComponents >= 2 ? ptr[index + 1] : 0,
342 numComponents >= 3 ? ptr[index + 2] : 0,
343 numComponents >= 4 ? ptr[index + 3] : 0
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
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);
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
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);
411 * es3fFragmentOutputTests.s_swizzles
412 * @return {Array<Array<number>>}
414 es3fFragmentOutputTests.s_swizzles = function() {
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
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);
442 * es3fFragmentOutputTests.AttachmentData struct class
446 es3fFragmentOutputTests.AttachmentData = function() {
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
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);
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];
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;
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;
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;
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);
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];
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
622 minVal = tcuTextureUtil.select(minVal, deMath.max(minVal, fmtMinVal), isZero);
623 maxVal = tcuTextureUtil.select(maxVal, deMath.min(maxVal, fmtMaxVal), isZero);
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
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];
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;
658 maxVal = deMath.min(maxVal, fmtMaxVal);
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]);
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];
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;
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);
718 buffer = gl.createBuffer();
719 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
721 gl.enableVertexAttribArray(loc);
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
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
734 bufferedLogToConsole('Warning: No location for attribute "' + name + '" found.');
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.
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,
780 data: attachments[location].referenceData // ArrayBuffer
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);
786 es3fFragmentOutputTests.renderIntReference(viewportBuf, gridWidth, gridHeight, scalarSize, inputData);
788 es3fFragmentOutputTests.renderFloatReference(viewportBuf, gridWidth, gridHeight, scalarSize, inputData);
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,
811 rowPitch: deMath.deAlign32(attachments[attachNdx].readFormat.getPixelSize() * attachmentW, readAlignment),
813 data: attachments[attachNdx].renderedData // ArrayBuffer
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,
826 data: attachments[attachNdx].referenceData // ArrayBuffer
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');
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
849 case tcuTexture.ChannelType.HALF_FLOAT:
850 formatThreshold = [(1 << 13) + 4, (1 << 13) + 4, (1 << 13) + 4, (1 << 13) + 4]; // UVec4
852 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV:
853 formatThreshold = [(1 << 17) + 4, (1 << 17) + 4, (1 << 18) + 4, 4]; // UVec4
860 switch (outPrecision) {
861 case gluShaderUtil.precision.PRECISION_LOWP:
862 precThreshold = (1 << 21);
864 case gluShaderUtil.precision.PRECISION_MEDIUMP:
865 precThreshold = (1 << 13);
867 case gluShaderUtil.precision.PRECISION_HIGHP:
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
879 isOk = tcuImageCompare.floatUlpThresholdCompare(name, desc, reference, rendered, finalThreshold /*, tcu::COMPARE_LOG_RESULT*/);
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);
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*/);
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(
907 [UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX],
910 isOk = tcuImageCompare.intThresholdCompare(name, desc, reference, rendered, threshold/*, tcu::COMPARE_LOG_RESULT*/);
915 testFailedOptions('Unsupported comparison', true);
923 if (numAttachments > 1) {
925 testPassed('Image comparison passed for ' + numAttachments + ' attachments');
927 testFailed('Image comparison failed for some of ' + numAttachments + ' attachments');
930 testPassed('Image comparison passed');
932 testFailed('Image comparison failed');
935 return tcuTestCase.IterateResult.STOP;
939 * es3fFragmentOutputTests.createRandomCase. Constructs the es3fFragmentOutputTests.createRandomCase, child class of es3fFragmentOutputTests.FragmentOutputCase
941 * @param {number} minRenderTargets
942 * @param {number} maxRenderTargets
943 * @param {number} seed
944 * @return {es3fFragmentOutputTests.FragmentOutputCase} The currently modified object
946 es3fFragmentOutputTests.createRandomCase = function(minRenderTargets, maxRenderTargets, seed, colorBufferFloatSupported) {
948 /** @type {Array<gluShaderUtil.DataType>} */
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
964 /** @type {Array<gluShaderUtil.precision>} */
966 gluShaderUtil.precision.PRECISION_LOWP,
967 gluShaderUtil.precision.PRECISION_MEDIUMP,
968 gluShaderUtil.precision.PRECISION_HIGHP
971 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
991 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
992 var colorBufferFloatFormats = [
1003 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1016 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
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;
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;
1059 DE_ASSERT(curLoc == numTargets);
1060 DE_ASSERT(outTypes.length == numTargets);
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;
1072 formatArray = rnd.choose(floatFormats, undefined, 1);
1073 format = formatArray[0];
1074 if (colorBufferFloatFormats.indexOf(format) >= 0 && !colorBufferFloatSupported)
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];
1085 targets.push(new es3fFragmentOutputTests.BufferSpec(format, width, height, samples));
1088 return new es3fFragmentOutputTests.FragmentOutputCase(seed.toString(), '', targets, outputs);
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 = [
1108 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1109 var requiredFixedFormats = [
1121 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1122 var requiredIntFormats = [
1134 /** @type {Array<WebGLRenderingContextBase.GLenum>} */
1135 var requiredUintFormats = [
1148 /** @type {Array<gluShaderUtil.precision>} */
1151 gluShaderUtil.precision.PRECISION_LOWP,
1152 gluShaderUtil.precision.PRECISION_MEDIUMP,
1153 gluShaderUtil.precision.PRECISION_HIGHP
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;
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);
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)]));
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);
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)]));
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);
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)]));
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);
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)]));
1257 /** @type {number} */ var numTargets = 3;
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);
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)]));
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);
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)]));
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);
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)]));
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);
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)]));
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]);
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);
1369 * Create and execute the test cases
1371 es3fFragmentOutputTests.run = function(context, range) {
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);
1386 es3fFragmentOutputTests.init(gl);
1388 state.setRange(range);
1389 tcuTestCase.runTestCases();
1391 testFailedOptions('Failed to es3fFragmentOutputTests.run tests', false);
1392 bufferedLogToConsole(err);
1393 tcuTestCase.runner.terminate();