/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES Utilities * ------------------------------------------------ * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ 'use strict'; goog.provide('functional.gles3.es3fFboColorbufferTests'); goog.require('framework.common.tcuSurface'); goog.require('framework.common.tcuTestCase'); goog.require('framework.common.tcuTexture'); goog.require('framework.opengl.gluTextureUtil'); goog.require('functional.gles3.es3fFboTestCase'); goog.require('functional.gles3.es3fFboTestUtil'); goog.require('framework.common.tcuRGBA'); goog.require('framework.delibs.debase.deRandom'); goog.require('framework.common.tcuImageCompare'); goog.require('framework.common.tcuTextureUtil'); goog.require('framework.referencerenderer.rrUtil'); goog.require('framework.delibs.debase.deMath'); goog.require('framework.opengl.gluShaderUtil'); goog.scope(function() { var es3fFboColorbufferTests = functional.gles3.es3fFboColorbufferTests; var es3fFboTestCase = functional.gles3.es3fFboTestCase; var es3fFboTestUtil = functional.gles3.es3fFboTestUtil; var tcuTestCase = framework.common.tcuTestCase; var tcuSurface = framework.common.tcuSurface; var tcuTexture = framework.common.tcuTexture; var gluTextureUtil = framework.opengl.gluTextureUtil; var tcuRGBA = framework.common.tcuRGBA; var deRandom = framework.delibs.debase.deRandom; var tcuImageCompare = framework.common.tcuImageCompare; var tcuTextureUtil = framework.common.tcuTextureUtil; var rrUtil = framework.referencerenderer.rrUtil; var deMath = framework.delibs.debase.deMath; var gluShaderUtil = framework.opengl.gluShaderUtil; /** @type {WebGL2RenderingContext} */ var gl; /** @const*/ var MIN_THRESHOLD = new tcuRGBA.RGBA([12, 12, 12, 12]); let canvasWH = 256; let texPotSize = [128, 128, 5]; let texNpotSizeA = [129, 117]; let texNpotSizeB = [99, 128]; if (tcuTestCase.isQuickMode()) { canvasWH = 32; texPotSize = [16, 16, 5]; texNpotSizeA = [12, 11]; texNpotSizeB = [9, 16]; } const texW = texPotSize[0]; const texH = texPotSize[1]; var setParentClass = function(child, parent) { child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; }; /** * @param {deRandom.Random} rnd * @param {Array} minVal * @param {Array} maxVal * @return {Array} */ es3fFboColorbufferTests.randomVector = function(rnd, minVal, maxVal) { var res = []; for (var ndx = 0; ndx < minVal.length; ndx++) res[ndx] = rnd.getFloat(minVal[ndx], maxVal[ndx]); return res; }; /** * @param {deRandom.Random} rnd * @return {Array} */ es3fFboColorbufferTests.generateRandomColor = function(rnd) { var retVal = []; for (var i = 0; i < 3; ++i) retVal[i] = rnd.getFloat(); retVal[3] = 1; return retVal; }; /** * @constructor * @extends {es3fFboTestCase.FboTestCase} * @param {string} name * @param {string} desc * @param {number} format */ es3fFboColorbufferTests.FboColorbufferCase = function(name, desc, format) { es3fFboTestCase.FboTestCase.call(this, name, desc); this.m_format = format; }; setParentClass(es3fFboColorbufferTests.FboColorbufferCase, es3fFboTestCase.FboTestCase); /** * @param {tcuSurface.Surface} reference * @param {tcuSurface.Surface} result * @return {boolean} */ es3fFboColorbufferTests.FboColorbufferCase.prototype.compare = function(reference, result) { /** @type {tcuRGBA.RGBA} */ var threshold = tcuRGBA.max(es3fFboTestUtil.getFormatThreshold(this.m_format), MIN_THRESHOLD); bufferedLogToConsole('Comparing images, threshold: ' + threshold); return tcuImageCompare.bilinearCompare('Result', 'Image comparison result', reference.getAccess(), result.getAccess(), threshold); }; /** * Deinit. Clear some GL state variables */ es3fFboColorbufferTests.FboColorbufferCase.prototype.deinit = function() { // Texture state { // Only TEXTURE0 and TEXTURE1 are used in this test var numTexUnits = 2; for (var ndx = 0; ndx < numTexUnits; ndx++) { gl.activeTexture(gl.TEXTURE0 + ndx); // Reset 2D texture gl.bindTexture(gl.TEXTURE_2D, null); // Reset cube map texture gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); // Reset 2D array texture gl.bindTexture(gl.TEXTURE_2D_ARRAY, null); // Reset 3D texture gl.bindTexture(gl.TEXTURE_3D, null); } gl.activeTexture(gl.TEXTURE0); } // Pixel operations { gl.disable(gl.SCISSOR_TEST); gl.disable(gl.BLEND); } // Framebuffer control { gl.clearColor(0.0, 0.0, 0.0, 0.0); } }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} format * @param {number} width * @param {number} height */ es3fFboColorbufferTests.FboColorClearCase = function(name, desc, format, width, height) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, format); this.m_width = width; this.m_height = height; }; setParentClass(es3fFboColorbufferTests.FboColorClearCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboColorClearCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_format); return true; // No exception thrown }; es3fFboColorbufferTests.FboColorClearCase.prototype.render = function(dst) { var ctx = this.getCurrentContext(); var fboFormat = gluTextureUtil.mapGLInternalFormat(this.m_format); var fmtClass = tcuTexture.getTextureChannelClass(fboFormat.type); var fmtInfo = tcuTextureUtil.getTextureFormatInfo(fboFormat); var rnd = new deRandom.Random(17); var numClears = 16; var fbo = ctx.createFramebuffer(); var rbo = ctx.createRenderbuffer(); ctx.bindRenderbuffer(gl.RENDERBUFFER, rbo); ctx.renderbufferStorage(gl.RENDERBUFFER, this.m_format, this.m_width, this.m_height); this.checkError(); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); ctx.viewport(0, 0, this.m_width, this.m_height); // Initialize to transparent black. switch (fmtClass) { case tcuTexture.TextureChannelClass.FLOATING_POINT: case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: ctx.clearBufferfv(gl.COLOR, 0, new Float32Array(4)); break; case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: ctx.clearBufferuiv(gl.COLOR, 0, new Uint32Array(4)); break; case tcuTexture.TextureChannelClass.SIGNED_INTEGER: ctx.clearBufferiv(gl.COLOR, 0, new Int32Array(4)); break; default: throw new Error('Invalid channelclass ' + fmtClass); } // Do random scissored clears. ctx.enable(gl.SCISSOR_TEST); for (var ndx = 0; ndx < numClears; ndx++) { var x = rnd.getInt(0, this.m_width - 1); var y = rnd.getInt(0, this.m_height - 1); var w = rnd.getInt(1, this.m_width - x); var h = rnd.getInt(1, this.m_height - y); var color = es3fFboColorbufferTests.randomVector(rnd, fmtInfo.valueMin, fmtInfo.valueMax); ctx.scissor(x, y, w, h); switch (fmtClass) { case tcuTexture.TextureChannelClass.FLOATING_POINT: case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: ctx.clearBufferfv(gl.COLOR, 0, color); break; case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: ctx.clearBufferuiv(gl.COLOR, 0, color); break; case tcuTexture.TextureChannelClass.SIGNED_INTEGER: ctx.clearBufferiv(gl.COLOR, 0, color); break; default: throw new Error('Invalid channelclass ' + fmtClass); } } // Read results from renderbuffer. this.readPixelsUsingFormat(dst, 0, 0, this.m_width, this.m_height, fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias); this.checkError(); }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} tex0Fmt * @param {Array} tex0Size * @param {number} tex1Fmt * @param {Array} tex1Size */ es3fFboColorbufferTests.FboColorMultiTex2DCase = function(name, desc, tex0Fmt, tex0Size, tex1Fmt, tex1Size) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, tex0Fmt); this.m_tex0Fmt = tex0Fmt; this.m_tex0Size = tex0Size; this.m_tex1Fmt = tex1Fmt; this.m_tex1Size = tex1Size; }; setParentClass(es3fFboColorbufferTests.FboColorMultiTex2DCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboColorMultiTex2DCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_tex0Fmt); this.checkFormatSupport(this.m_tex1Fmt); return true; // No exception thrown }; es3fFboColorbufferTests.FboColorMultiTex2DCase.prototype.render = function(dst) { var ctx = this.getCurrentContext(); var texFmt0 = gluTextureUtil.mapGLInternalFormat(this.m_tex0Fmt); var texFmt1 = gluTextureUtil.mapGLInternalFormat(this.m_tex1Fmt); var fmtInfo0 = tcuTextureUtil.getTextureFormatInfo(texFmt0); var fmtInfo1 = tcuTextureUtil.getTextureFormatInfo(texFmt1); /** @type {es3fFboTestUtil.Texture2DShader} */ var texToFbo0Shader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], es3fFboTestUtil.getFragmentOutputType(texFmt0), deMath.subtract(fmtInfo0.valueMax, fmtInfo0.valueMin), fmtInfo0.valueMin); /** @type {es3fFboTestUtil.Texture2DShader} */ var texToFbo1Shader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], es3fFboTestUtil.getFragmentOutputType(texFmt1), deMath.subtract(fmtInfo1.valueMax, fmtInfo1.valueMin), fmtInfo1.valueMin); /** @type {es3fFboTestUtil.Texture2DShader} */ var multiTexShader = new es3fFboTestUtil.Texture2DShader( [gluTextureUtil.getSampler2DType(texFmt0), gluTextureUtil.getSampler2DType(texFmt1)], gluShaderUtil.DataType.FLOAT_VEC4); var texToFbo0ShaderID = ctx.createProgram(texToFbo0Shader); var texToFbo1ShaderID = ctx.createProgram(texToFbo1Shader); var multiTexShaderID = ctx.createProgram(multiTexShader); // Setup shaders multiTexShader.setTexScaleBias(0, deMath.scale(fmtInfo0.lookupScale, 0.5), deMath.scale(fmtInfo0.lookupBias, 0.5)); multiTexShader.setTexScaleBias(1, deMath.scale(fmtInfo1.lookupScale, 0.5), deMath.scale(fmtInfo1.lookupBias, 0.5)); texToFbo0Shader.setUniforms(ctx, texToFbo0ShaderID); texToFbo1Shader.setUniforms(ctx, texToFbo1ShaderID); multiTexShader.setUniforms(ctx, multiTexShaderID); var fbo0 = ctx.createFramebuffer(); var fbo1 = ctx.createFramebuffer(); var tex0 = ctx.createTexture(); var tex1 = ctx.createTexture(); for (var ndx = 0; ndx < 2; ndx++) { var transferFmt = gluTextureUtil.getTransferFormat(ndx ? texFmt1 : texFmt0); var format = ndx ? this.m_tex1Fmt : this.m_tex0Fmt; var isFilterable = gluTextureUtil.isGLInternalColorFormatFilterable(format); var size = ndx ? this.m_tex1Size : this.m_tex0Size; var fbo = ndx ? fbo1 : fbo0; var tex = ndx ? tex1 : tex0; ctx.bindTexture(gl.TEXTURE_2D, tex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); ctx.texImage2D(gl.TEXTURE_2D, 0, format, size[0], size[1], 0, transferFmt.format, transferFmt.dataType, null); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); } // Render textures to both framebuffers. for (var ndx = 0; ndx < 2; ndx++) { var format = gl.RGBA; var dataType = gl.UNSIGNED_BYTE; var tmpTex; var fbo = ndx ? fbo1 : fbo0; var viewport = ndx ? this.m_tex1Size : this.m_tex0Size; var data = new tcuTexture.TextureLevel(gluTextureUtil.mapGLTransferFormat(format, dataType), texW, texH, 1); if (ndx == 0) tcuTextureUtil.fillWithComponentGradients(data.getAccess(), [0, 0, 0, 0], [1, 1, 1, 1]); else tcuTextureUtil.fillWithGrid(data.getAccess(), 8, [0.2, 0.7, 0.1, 1.0], [0.7, 0.1, 0.5, 0.8]); tmpTex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D, tmpTex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ctx.texImage2D(gl.TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.viewport(0, 0, viewport[0], viewport[1]); rrUtil.drawQuad(ctx, ndx ? texToFbo1ShaderID : texToFbo0ShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); } // Render to framebuffer. ctx.bindFramebuffer(gl.FRAMEBUFFER, null); ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); ctx.activeTexture(gl.TEXTURE0); ctx.bindTexture(gl.TEXTURE_2D, tex0); ctx.activeTexture(gl.TEXTURE1); ctx.bindTexture(gl.TEXTURE_2D, tex1); rrUtil.drawQuad(ctx, multiTexShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); this.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} texFmt * @param {Array} texSize */ es3fFboColorbufferTests.FboColorTexCubeCase = function(name, desc, texFmt, texSize) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, texFmt); this.m_texSize = texSize; }; setParentClass(es3fFboColorbufferTests.FboColorTexCubeCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboColorTexCubeCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_format); return true; // No exception thrown }; es3fFboColorbufferTests.FboColorTexCubeCase.prototype.render = function(dst) { var ctx = this.getCurrentContext(); var texFmt = gluTextureUtil.mapGLInternalFormat(this.m_format); var fmtInfo = tcuTextureUtil.getTextureFormatInfo(texFmt); var cubeGLFaces = [ gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Z, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ]; var cubeTexFaces = [ tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z ]; var rnd = new deRandom.Random(21); /** @type {es3fFboTestUtil.Texture2DShader} */ var texToFboShader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], es3fFboTestUtil.getFragmentOutputType(texFmt), deMath.subtract(fmtInfo.valueMax, fmtInfo.valueMin), fmtInfo.valueMin); /** @type {es3fFboTestUtil.TextureCubeShader} */ var cubeTexShader = new es3fFboTestUtil.TextureCubeShader( gluTextureUtil.getSamplerCubeType(texFmt), gluShaderUtil.DataType.FLOAT_VEC4); var texToFboShaderID = ctx.createProgram(texToFboShader); var cubeTexShaderID = ctx.createProgram(cubeTexShader); // Setup shaders texToFboShader.setUniforms(ctx, texToFboShaderID); cubeTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. var fbos = []; var tex; var transferFmt = gluTextureUtil.getTransferFormat(texFmt); var isFilterable = gluTextureUtil.isGLInternalColorFormatFilterable(this.m_format); var size = this.m_texSize; tex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_CUBE_MAP, tex); ctx.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); ctx.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); // Generate an image and FBO for each cube face for (var ndx = 0; ndx < cubeGLFaces.length; ndx++) ctx.texImage2D(cubeGLFaces[ndx], 0, this.m_format, size[0], size[1], 0, transferFmt.format, transferFmt.dataType, null); this.checkError(); for (var ndx = 0; ndx < cubeGLFaces.length; ndx++) { var layerFbo = ctx.createFramebuffer(); ctx.bindFramebuffer(gl.FRAMEBUFFER, layerFbo); ctx.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, cubeGLFaces[ndx], tex, 0); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); fbos.push(layerFbo); } // Render test images to random cube faces var order = []; for (var n = 0; n < fbos.length; n++) order.push(n); rnd.shuffle(order); for (var ndx = 0; ndx < 4; ndx++) { var face = order[ndx]; var format = gl.RGBA; var dataType = gl.UNSIGNED_BYTE; var tmpTex; var fbo = fbos[face]; var viewport = this.m_texSize; var data = new tcuTexture.TextureLevel(gluTextureUtil.mapGLTransferFormat(format, dataType), texW, texH, 1); tcuTextureUtil.fillWithGrid(data.getAccess(), 8, es3fFboColorbufferTests.generateRandomColor(rnd), [0, 0, 0, 0]); tmpTex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D, tmpTex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ctx.texImage2D(gl.TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.viewport(0, 0, viewport[0], viewport[1]); rrUtil.drawQuad(ctx, texToFboShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); this.checkError(); // Render to framebuffer var p0 = [(ndx % 2) - 1.0, Math.floor(ndx / 2) - 1.0, 0.0]; var p1 = deMath.add(p0, [1.0, 1.0, 0.0]); ctx.bindFramebuffer(gl.FRAMEBUFFER, null); ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); ctx.activeTexture(gl.TEXTURE0); ctx.bindTexture(gl.TEXTURE_CUBE_MAP, tex); cubeTexShader.setFace(cubeTexFaces[face]); cubeTexShader.setUniforms(ctx, cubeTexShaderID); rrUtil.drawQuad(ctx, cubeTexShaderID, p0, p1); this.checkError(); } this.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} texFmt * @param {Array} texSize */ es3fFboColorbufferTests.FboColorTex2DArrayCase = function(name, desc, texFmt, texSize) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, texFmt); this.m_texSize = texSize; }; setParentClass(es3fFboColorbufferTests.FboColorTex2DArrayCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboColorTex2DArrayCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_format); return true; // No exception thrown }; es3fFboColorbufferTests.FboColorTex2DArrayCase.prototype.render = function(dst) { var ctx = this.getCurrentContext(); var texFmt = gluTextureUtil.mapGLInternalFormat(this.m_format); var fmtInfo = tcuTextureUtil.getTextureFormatInfo(texFmt); var rnd = new deRandom.Random(100); /** @type {es3fFboTestUtil.Texture2DShader} */ var texToFboShader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], es3fFboTestUtil.getFragmentOutputType(texFmt), deMath.subtract(fmtInfo.valueMax, fmtInfo.valueMin), fmtInfo.valueMin); /** @type {es3fFboTestUtil.Texture2DArrayShader} */ var arrayTexShader = new es3fFboTestUtil.Texture2DArrayShader( gluTextureUtil.getSampler2DArrayType(texFmt), gluShaderUtil.DataType.FLOAT_VEC4); var texToFboShaderID = ctx.createProgram(texToFboShader); var arrayTexShaderID = ctx.createProgram(arrayTexShader); // Setup textures texToFboShader.setUniforms(ctx, texToFboShaderID); arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. var fbos = []; var tex; var transferFmt = gluTextureUtil.getTransferFormat(texFmt); var isFilterable = gluTextureUtil.isGLInternalColorFormatFilterable(this.m_format); var size = this.m_texSize; tex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D_ARRAY, tex); ctx.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); ctx.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, isFilterable ? gl.LINEAR : gl.NEAREST); ctx.texImage3D(gl.TEXTURE_2D_ARRAY, 0, this.m_format, size[0], size[1], size[2], 0, transferFmt.format, transferFmt.dataType, null); // Generate an FBO for each layer for (var ndx = 0; ndx < this.m_texSize[2]; ndx++) { var layerFbo = ctx.createFramebuffer(); ctx.bindFramebuffer(gl.FRAMEBUFFER, layerFbo); ctx.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex, 0, ndx); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); fbos.push(layerFbo); } // Render test images to random texture layers var order = []; for (var n = 0; n < fbos.length; n++) order.push(n); rnd.shuffle(order); for (var ndx = 0; ndx < 4; ndx++) { var layer = order[ndx]; var format = gl.RGBA; var dataType = gl.UNSIGNED_BYTE; var fbo = fbos[layer]; var viewport = this.m_texSize; var data = new tcuTexture.TextureLevel(gluTextureUtil.mapGLTransferFormat(format, dataType), texW, texH, 1); tcuTextureUtil.fillWithGrid(data.getAccess(), 8, es3fFboColorbufferTests.generateRandomColor(rnd), [0, 0, 0, 0]); var tmpTex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D, tmpTex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ctx.texImage2D(gl.TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.viewport(0, 0, viewport[0], viewport[1]); rrUtil.drawQuad(ctx, texToFboShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); this.checkError(); // Render to framebuffer var p0 = [(ndx % 2) - 1.0, Math.floor(ndx / 2) - 1.0, 0.0]; var p1 = deMath.add(p0, [1.0, 1.0, 0.0]); debug('Layer:' + layer + ' rectangle: ' + p0 + ' ' + p1); ctx.bindFramebuffer(gl.FRAMEBUFFER, null); ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); ctx.activeTexture(gl.TEXTURE0); ctx.bindTexture(gl.TEXTURE_2D_ARRAY, tex); arrayTexShader.setLayer(layer); arrayTexShader.setUniforms(ctx, arrayTexShaderID); rrUtil.drawQuad(ctx, arrayTexShaderID, p0, p1); this.checkError(); } this.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} texFmt * @param {Array} texSize */ es3fFboColorbufferTests.FboColorTex3DCase = function(name, desc, texFmt, texSize) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, texFmt); this.m_texSize = texSize; }; setParentClass(es3fFboColorbufferTests.FboColorTex3DCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboColorTex3DCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_format); return true; // No exception thrown }; es3fFboColorbufferTests.FboColorTex3DCase.prototype.render = function(dst) { var ctx = this.getCurrentContext(); var texFmt = gluTextureUtil.mapGLInternalFormat(this.m_format); var fmtInfo = tcuTextureUtil.getTextureFormatInfo(texFmt); var rnd = new deRandom.Random(100); /** @type {es3fFboTestUtil.Texture2DShader} */ var texToFboShader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], es3fFboTestUtil.getFragmentOutputType(texFmt), deMath.subtract(fmtInfo.valueMax, fmtInfo.valueMin), fmtInfo.valueMin); /** @type {es3fFboTestUtil.Texture3DShader} */ var tdTexShader = new es3fFboTestUtil.Texture3DShader( gluTextureUtil.getSampler3D(texFmt), gluShaderUtil.DataType.FLOAT_VEC4); var texToFboShaderID = ctx.createProgram(texToFboShader); var tdTexShaderID = ctx.createProgram(tdTexShader); // Setup textures texToFboShader.setUniforms(ctx, texToFboShaderID); tdTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. var fbos = []; var tex;{ var transferFmt = gluTextureUtil.getTransferFormat(texFmt); var size = this.m_texSize; tex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_3D, tex); ctx.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); ctx.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); ctx.texImage3D(gl.TEXTURE_3D, 0, this.m_format, size[0], size[1], size[2], 0, transferFmt.format, transferFmt.dataType, null); // Generate an FBO for each layer for (var ndx = 0; ndx < this.m_texSize[2]; ndx++) { var layerFbo = ctx.createFramebuffer(); ctx.bindFramebuffer(gl.FRAMEBUFFER, layerFbo); ctx.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex, 0, ndx); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); fbos.push(layerFbo); } } // Render test images to random texture layers var order = []; for (var n = 0; n < fbos.length; n++) order.push(n); rnd.shuffle(order); for (var ndx = 0; ndx < 4; ndx++) { var layer = order[ndx]; var format = gl.RGBA; var dataType = gl.UNSIGNED_BYTE; var fbo = fbos[layer]; var viewport = this.m_texSize; var data = new tcuTexture.TextureLevel(gluTextureUtil.mapGLTransferFormat(format, dataType), texW, texH, 1); tcuTextureUtil.fillWithGrid(data.getAccess(), 8, es3fFboColorbufferTests.generateRandomColor(rnd), [0, 0, 0, 0]); var tmpTex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D, tmpTex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ctx.texImage2D(gl.TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.viewport(0, 0, viewport[0], viewport[1]); rrUtil.drawQuad(ctx, texToFboShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); this.checkError(); // Render to framebuffer var p0 = [(ndx % 2) - 1.0, Math.floor(ndx / 2) - 1.0, 0.0]; var p1 = deMath.add(p0, [1.0, 1.0, 0.0]); debug('Layer:' + layer + ' rectangle: ' + p0 + ' ' + p1); ctx.bindFramebuffer(gl.FRAMEBUFFER, null); ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); ctx.activeTexture(gl.TEXTURE0); ctx.bindTexture(gl.TEXTURE_3D, tex); tdTexShader.setDepth(layer / (this.m_texSize[2] - 1)); tdTexShader.setUniforms(ctx, tdTexShaderID); rrUtil.drawQuad(ctx, tdTexShaderID, p0, p1); this.checkError(); } this.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); }; /** * @constructor * @extends {es3fFboColorbufferTests.FboColorbufferCase} * @param {string} name * @param {string} desc * @param {number} format * @param {Array} size * @param {number} funcRGB * @param {number} funcAlpha * @param {number} srcRGB * @param {number} dstRGB * @param {number} srcAlpha * @param {number} dstAlpha */ es3fFboColorbufferTests.FboBlendCase = function(name, desc, format, size, funcRGB, funcAlpha, srcRGB, dstRGB, srcAlpha, dstAlpha) { es3fFboColorbufferTests.FboColorbufferCase.call(this, name, desc, format); this.m_size = size; this.m_funcRGB = funcRGB; this.m_funcAlpha = funcAlpha; this.m_srcRGB = srcRGB; this.m_dstRGB = dstRGB; this.m_srcAlpha = srcAlpha; this.m_dstAlpha = dstAlpha }; setParentClass(es3fFboColorbufferTests.FboBlendCase, es3fFboColorbufferTests.FboColorbufferCase); es3fFboColorbufferTests.FboBlendCase.prototype.preCheck = function() { this.checkFormatSupport(this.m_format); return true; // No exception thrown } es3fFboColorbufferTests.FboBlendCase.prototype.render = function(dst) { // \note Assumes floating-point or fixed-point format. var ctx = this.getCurrentContext(); var fboFmt = gluTextureUtil.mapGLInternalFormat(this.m_format); var fmtInfo = tcuTextureUtil.getTextureFormatInfo(fboFmt); /** @type {es3fFboTestUtil.Texture2DShader} */ var texShader = new es3fFboTestUtil.Texture2DShader( [gluShaderUtil.DataType.SAMPLER_2D], gluShaderUtil.DataType.FLOAT_VEC4); /** @type {es3fFboTestUtil.GradientShader} */ var gradShader = new es3fFboTestUtil.GradientShader(gluShaderUtil.DataType.FLOAT_VEC4); var texShaderID = ctx.createProgram(texShader); var gradShaderID = ctx.createProgram(gradShader); // Setup shaders texShader.setUniforms (ctx, texShaderID); gradShader.setGradient(ctx, gradShaderID, [0, 0, 0, 0], [1, 1, 1, 1]); var fbo = ctx.createFramebuffer(); var rbo = ctx.createRenderbuffer(); ctx.bindRenderbuffer(gl.RENDERBUFFER, rbo); ctx.renderbufferStorage(gl.RENDERBUFFER, this.m_format, this.m_size[0], this.m_size[1]); this.checkError(); ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); this.checkError(); this.checkFramebufferStatus(gl.FRAMEBUFFER); ctx.viewport(0, 0, this.m_size[0], this.m_size[1]); // Fill framebuffer with grid pattern. var format = gl.RGBA; var dataType = gl.UNSIGNED_BYTE; var data = new tcuTexture.TextureLevel(gluTextureUtil.mapGLTransferFormat(format, dataType), texW, texH, 1); tcuTextureUtil.fillWithGrid(data.getAccess(), 8, [0.2, 0.7, 0.1, 1.0], [0.7, 0.1, 0.5, 0.8]); var gridTex = ctx.createTexture(); ctx.bindTexture(gl.TEXTURE_2D, gridTex); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); ctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); ctx.texImage2D(gl.TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); rrUtil.drawQuad(ctx, texShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); this.checkError(); // Setup blend. ctx.enable(gl.BLEND); ctx.blendEquationSeparate(this.m_funcRGB, this.m_funcAlpha); ctx.blendFuncSeparate(this.m_srcRGB, this.m_dstRGB, this.m_srcAlpha, this.m_dstAlpha); // Render gradient with blend. rrUtil.drawQuad(ctx, gradShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); es3fFboTestUtil.readPixels(ctx, dst, 0, 0, this.m_size[0], this.m_size[1], fboFmt, [1, 1, 1, 1], [0, 0, 0, 0]); }; /** * @constructor * @extends {tcuTestCase.DeqpTest} */ es3fFboColorbufferTests.FboColorbufferTests = function() { tcuTestCase.DeqpTest.call(this, 'color', 'Colorbuffer tests'); }; setParentClass(es3fFboColorbufferTests.FboColorbufferTests, tcuTestCase.DeqpTest); es3fFboColorbufferTests.FboColorbufferTests.prototype.init = function() { var colorFormats = [ // RGBA formats gl.RGBA32I, gl.RGBA32UI, gl.RGBA16I, gl.RGBA16UI, gl.RGBA8, gl.RGBA8I, gl.RGBA8UI, gl.SRGB8_ALPHA8, gl.RGB10_A2, gl.RGB10_A2UI, gl.RGBA4, gl.RGB5_A1, // RGB formats gl.RGB8, gl.RGB565, // RG formats gl.RG32I, gl.RG32UI, gl.RG16I, gl.RG16UI, gl.RG8, gl.RG8I, gl.RG8UI, // R formats gl.R32I, gl.R32UI, gl.R16I, gl.R16UI, gl.R8, gl.R8I, gl.R8UI, // gl.EXT_color_buffer_float gl.RGBA32F, gl.RGBA16F, gl.R11F_G11F_B10F, gl.RG32F, gl.RG16F, gl.R32F, gl.R16F, // gl.EXT_color_buffer_half_float is not exposed in WebGL 2.0. // gl.RGB16F ]; // .clear var clearGroup = tcuTestCase.newTest("clear", "Color clears"); this.addChild(clearGroup); for (var ndx = 0; ndx < colorFormats.length; ndx++) { clearGroup.addChild(new es3fFboColorbufferTests.FboColorClearCase( es3fFboTestUtil.getFormatName(colorFormats[ndx]), "", colorFormats[ndx], texNpotSizeA[0], texNpotSizeA[1])); } var numGroups = 6; // .tex2d var tex2DGroup = []; for (var ii = 0; ii < numGroups; ++ii) { tex2DGroup[ii] = tcuTestCase.newTest("tex2d", "Texture 2D tests"); this.addChild(tex2DGroup[ii]); } for (var ndx = 0; ndx < colorFormats.length; ndx++) { tex2DGroup[ndx % numGroups].addChild(new es3fFboColorbufferTests.FboColorMultiTex2DCase( es3fFboTestUtil.getFormatName(colorFormats[ndx]), "", colorFormats[ndx], texNpotSizeA, colorFormats[ndx], texNpotSizeB)); } // .texcube var texCubeGroup = []; for (var ii = 0; ii < numGroups; ++ii) { texCubeGroup[ii] = tcuTestCase.newTest("texcube", "Texture cube map tests"); this.addChild(texCubeGroup[ii]); } for (var ndx = 0; ndx < colorFormats.length; ndx++) { texCubeGroup[ndx % numGroups].addChild(new es3fFboColorbufferTests.FboColorTexCubeCase( es3fFboTestUtil.getFormatName(colorFormats[ndx]), "", colorFormats[ndx], texPotSize)); } // .tex2darray var tex2DArrayGroup = []; for (var ii = 0; ii < numGroups; ++ii) { tex2DArrayGroup[ii] = tcuTestCase.newTest("tex2darray", "Texture 2D array tests"); this.addChild(tex2DArrayGroup[ii]); } for (var ndx = 0; ndx < colorFormats.length; ndx++) { tex2DArrayGroup[ndx % numGroups].addChild(new es3fFboColorbufferTests.FboColorTex2DArrayCase( es3fFboTestUtil.getFormatName(colorFormats[ndx]), "", colorFormats[ndx], texPotSize)); } // .tex3d var tex3DGroup = []; for (var ii = 0; ii < numGroups; ++ii) { tex3DGroup[ii] = tcuTestCase.newTest("tex3d", "Texture 3D tests"); this.addChild(tex3DGroup[ii]); } for (var ndx = 0; ndx < colorFormats.length; ndx++) { tex3DGroup[ndx % numGroups].addChild(new es3fFboColorbufferTests.FboColorTex3DCase( es3fFboTestUtil.getFormatName(colorFormats[ndx]), "", colorFormats[ndx], texPotSize)); } // .blend var blendGroup = tcuTestCase.newTest("blend", "Blending tests"); this.addChild(blendGroup); for (var ndx = 0; ndx < colorFormats.length; ndx++) { var format = colorFormats[ndx]; var texFmt = gluTextureUtil.mapGLInternalFormat(format); var fmtClass = tcuTexture.getTextureChannelClass(texFmt.type); var fmtName = es3fFboTestUtil.getFormatName(format); if (texFmt.type == tcuTexture.ChannelType.FLOAT || fmtClass == tcuTexture.TextureChannelClass.SIGNED_INTEGER || fmtClass == tcuTexture.TextureChannelClass.UNSIGNED_INTEGER) continue; // Blending is not supported. blendGroup.addChild(new es3fFboColorbufferTests.FboBlendCase(fmtName + "_src_over", "", format, texNpotSizeA, gl.FUNC_ADD, gl.FUNC_ADD, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)); } }; /** * Run test * @param {WebGL2RenderingContext} context */ es3fFboColorbufferTests.run = function(context, range) { gl = context; const canvas = gl.canvas; canvas.width = canvasWH; canvas.height = canvasWH; //Set up Test Root parameters var state = tcuTestCase.runner; state.setRoot(new es3fFboColorbufferTests.FboColorbufferTests()); //Set up name and description of this test series. setCurrentTestName(state.testCases.fullName()); description(state.testCases.getDescription()); try { if (range) state.setRange(range); //Run test cases tcuTestCase.runTestCases(); } catch (err) { testFailedOptions('Failed to es3fFboColorbufferTests.run tests', false); tcuTestCase.runner.terminate(); } }; });