// FboCompletenessTests 'use strict'; goog.provide('functional.gles3.es3fFboCompletenessTests'); goog.require('framework.common.tcuTestCase'); goog.require('modules.shared.glsFboCompletenessTests'); goog.require('modules.shared.glsFboUtil'); goog.scope(function() { var es3fFboCompletenessTests = functional.gles3.es3fFboCompletenessTests; var glsFboUtil = modules.shared.glsFboUtil; var glsFboCompletenessTests = modules.shared.glsFboCompletenessTests; var tcuTestCase = framework.common.tcuTestCase; es3fFboCompletenessTests.initGlDependents = function(gl) { if (!(gl = gl || window.gl)) throw new Error('Invalid gl object'); /** * @type {Array} */ es3fFboCompletenessTests.s_es3ColorRenderables = [ // GLES3, 4.4.4: "An internal format is color-renderable if it is one of // the formats from table 3.12 noted as color-renderable..." gl.R8, gl.RG8, gl.RGB8, gl.RGB565, gl.RGBA4, gl.RGB5_A1, gl.RGBA8, gl.RGB10_A2, gl.RGB10_A2UI, gl.SRGB8_ALPHA8, gl.R8I, gl.R8UI, gl.R16I, gl.R16UI, gl.R32I, gl.R32UI, gl.RG8I, gl.RG8UI, gl.RG16I, gl.RG16UI, gl.RG32I, gl.RG32UI, gl.RGBA81, gl.RGBA8UI, gl.RGB16I, gl.RGBA16UI, gl.RGBA32I, gl.RGBA32UI ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3UnsizedColorRenderables = [ // "...or if it is unsized format RGBA or RGB." // See Table 3.3 in GLES3. glsFboUtil.formatkey(gl.RGBA, gl.UNSIGNED_BYTE), glsFboUtil.formatkey(gl.RGBA, gl.UNSIGNED_SHORT_4_4_4_4), glsFboUtil.formatkey(gl.RGBA, gl.UNSIGNED_SHORT_5_5_5_1), glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_BYTE), glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_SHORT_5_6_5) ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3DepthRenderables = [ // GLES3, 4.4.4: "An internal format is depth-renderable if it is one of // the formats from table 3.13." gl.DEPTH_COMPONENT16, gl.DEPTH_COMPONENT24, gl.DEPTH_COMPONENT32F, gl.DEPTH24_STENCIL8, gl.DEPTH32F_STENCIL8 ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3StencilRboRenderables = [ // GLES3, 4.4.4: "An internal format is stencil-renderable if it is // STENCIL_INDEX8..." gl.STENCIL_INDEX8 ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3StencilRenderables = [ // "...or one of the formats from table 3.13 whose base internal format is // DEPTH_STENCIL." gl.DEPTH24_STENCIL8, gl.DEPTH32F_STENCIL8 ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3TextureFloatFormats = [ gl.RGBA32F, gl.RGBA16F, gl.R11F_G11F_B10F, gl.RG32F, gl.RG16F, gl.R32F, gl.R16F, gl.RGBA16F, gl.RGB16F, gl.RG16F, gl.R16F ]; /** * @type {Array} */ es3fFboCompletenessTests.s_es3Formats = [ [ ( glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.COLOR_RENDERABLE | glsFboUtil.FormatFlags.TEXTURE_VALID ), glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3UnsizedColorRenderables) ], [ ( glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.COLOR_RENDERABLE | glsFboUtil.FormatFlags.RENDERBUFFER_VALID | glsFboUtil.FormatFlags.TEXTURE_VALID ), glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3ColorRenderables) ], [ ( glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.DEPTH_RENDERABLE | glsFboUtil.FormatFlags.RENDERBUFFER_VALID | glsFboUtil.FormatFlags.TEXTURE_VALID ), glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3DepthRenderables) ], [ ( glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.STENCIL_RENDERABLE | glsFboUtil.FormatFlags.RENDERBUFFER_VALID ), glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3StencilRboRenderables) ], [ ( glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.STENCIL_RENDERABLE | glsFboUtil.FormatFlags.RENDERBUFFER_VALID | glsFboUtil.FormatFlags.TEXTURE_VALID ), glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3StencilRenderables) ], // These are not color-renderable in vanilla ES3, but we need to mark them // as valid for textures, since EXT_color_buffer_(half_)float brings in // color-renderability and only renderbuffer-validity. [ glsFboUtil.FormatFlags.TEXTURE_VALID, glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3TextureFloatFormats) ] ]; // gl.EXT_color_buffer_float es3fFboCompletenessTests.s_extColorBufferFloatFormats = [ gl.RGBA32F, gl.RGBA16F, gl.R11F_G11F_B10F, gl.RG32F, gl.RG16F, gl.R32F, gl.R16F ]; // gl.OES_texture_stencil8 es3fFboCompletenessTests.s_extOESTextureStencil8 = [ gl.STENCIL_INDEX8 ]; es3fFboCompletenessTests.s_es3ExtFormats = [{ extensions: 'gl.EXT_color_buffer_float', flags: glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.COLOR_RENDERABLE | glsFboUtil.FormatFlags.RENDERBUFFER_VALID, formats: new glsFboUtil.Range(es3fFboCompletenessTests.s_extColorBufferFloatFormats) }, { extensions: 'gl.OES_texture_stencil8', flags: glsFboUtil.FormatFlags.REQUIRED_RENDERABLE | glsFboUtil.FormatFlags.STENCIL_RENDERABLE | glsFboUtil.FormatFlags.TEXTURE_VALID, formats: new glsFboUtil.Range(es3fFboCompletenessTests.s_extOESTextureStencil8) } ]; glsFboCompletenessTests.initGlDependents(gl); }; /** * @constructor * @extends {glsFboUtil.Checker} */ es3fFboCompletenessTests.ES3Checker = function() { glsFboUtil.Checker.call(this, gl); /** @type {number} */ this.m_numSamples = -1; // GLsizei /** @type {number} */ this.m_depthStencilImage = 0; // GLuint /** @type {number} */ this.m_depthStencilType = gl.NONE; }; es3fFboCompletenessTests.ES3Checker.prototype = Object.create(glsFboUtil.Checker.prototype); es3fFboCompletenessTests.ES3Checker.prototype.constructor = es3fFboCompletenessTests.ES3Checker; es3fFboCompletenessTests.ES3Checker.prototype.check = function(attPoint, att, image) { var imgSamples = glsFboUtil.imageNumSamples(image); if (this.m_numSamples == -1) { this.m_numSamples = imgSamples; } else { // GLES3: "The value of RENDERBUFFER_SAMPLES is the same for all attached // renderbuffers and, if the attached images are a mix of renderbuffers // and textures, the value of RENDERBUFFER_SAMPLES is zero." // // On creating a renderbuffer: "If _samples_ is zero, then // RENDERBUFFER_SAMPLES is set to zero. Otherwise [...] the resulting // value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or // equal to _samples_ and no more than the next larger sample count // supported by the implementation." // Either all attachments are zero-sample renderbuffers and/or // textures, or none of them are. this.addFBOStatus( (this.m_numSamples == 0) == (imgSamples == 0), gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE ); // If the attachments requested a different number of samples, the // implementation is allowed to report this as incomplete. However, it // is also possible that despite the different requests, the // implementation allocated the same number of samples to both. Hence // reporting the framebuffer as complete is also legal. this.addPotentialFBOStatus( this.m_numSamples == imgSamples, gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE ); } // "Depth and stencil attachments, if present, are the same image." if (attPoint == gl.DEPTH_ATTACHMENT || attPoint == gl.STENCIL_ATTACHMENT) { if (this.m_depthStencilImage == 0) { this.m_depthStencilImage = att.imageName; this.m_depthStencilType = glsFboUtil.attachmentType(att); } else { this.addFBOStatus( this.m_depthStencilImage == att.imageName && this.m_depthStencilType == glsFboUtil.attachmentType(att), gl.FRAMEBUFFER_UNSUPPORTED ); } } }; /** * @typedef {{textureKind: number, numLayers: number, attachmentLayer: number}} */ es3fFboCompletenessTests.numLayersParamsT; /** * @param {number} textureKind * @param {number} numLayers * @param {number} attachmentLayer * @return {es3fFboCompletenessTests.numLayersParamsT} */ es3fFboCompletenessTests.numLayersParams = function(textureKind, numLayers, attachmentLayer) { if (typeof(attachmentLayer) == 'undefined') { textureKind = 0; numLayers = 0; attachmentLayer = 0; } return { textureKind: textureKind, //< gl.TEXTURE_3D or gl.TEXTURE_2D_ARRAY numLayers: numLayers, //< Number of layers in texture attachmentLayer: attachmentLayer //< Layer referenced by attachment }; }; /** * es3fFboCompletenessTests.numLayersParams.getName * @param {es3fFboCompletenessTests.numLayersParamsT} params * @return {string} */ es3fFboCompletenessTests.numLayersParams.getName = function(params) { return ( (params.textureKind == gl.TEXTURE_3D ? '3d' : '2darr') + '_' + params.numLayers + '_' + params.attachmentLayer ); }; /** * es3fFboCompletenessTests.numLayersParams.getDescription * @param {es3fFboCompletenessTests.numLayersParamsT} params * @return {string} */ es3fFboCompletenessTests.numLayersParams.getDescription = function(params) { return ( (params.textureKind == gl.TEXTURE_3D ? '3D Texture' : '2D Array Texture') + ', ' + params.numLayers + ' layers, ' + 'attached layer ' + params.attachmentLayer + '.' ); }; // string, string, glsFboCompleteness::context, params. /** * @constructor * @extends {glsFboCompletenessTests.TestBase} * @param {string} name * @param {string} desc * @param {glsFboCompletenessTests.Context} ctx * @param {es3fFboCompletenessTests.numLayersParamsT} params */ es3fFboCompletenessTests.NumLayersTest = function(name, desc, ctx, params) { glsFboCompletenessTests.TestBase.call(this, name, desc, params); this.m_ctx = ctx; }; es3fFboCompletenessTests.NumLayersTest.prototype = Object.create(glsFboCompletenessTests.TestBase.prototype); es3fFboCompletenessTests.NumLayersTest.prototype.constructor = es3fFboCompletenessTests.NumLayersTest; es3fFboCompletenessTests.NumLayersTest.prototype.build = function(builder, gl) { if (!(gl = gl || window.gl)) throw new Error('Invalid gl object'); var target = gl.COLOR_ATTACHMENT0; var texCfg = builder.makeConfig( function(kind) { switch (kind) { case gl.TEXTURE_3D: return glsFboUtil.Texture3D; case gl.TEXTURE_2D_ARRAY: return glsFboUtil.Texture2DArray; default: throw new Error('Impossible case'); } }(this.m_params.textureKind) ); texCfg.internalFormat = this.getDefaultFormat(target, gl.TEXTURE, gl); texCfg.width = 64; texCfg.height = 64; texCfg.numLayers = this.m_params.numLayers; var tex = builder.glCreateTexture(texCfg); var att = builder.makeConfig(glsFboUtil.TextureLayerAttachment); att.layer = this.m_params.attachmentLayer; att.imageName = tex; builder.glAttach(target, att); // return tcuTestCase.IterateResult.STOP; }; //es3fFboCompletenessTests.NumLayersTest.prototype.isExecutable = function() { // return false; //}; /** * @enum */ es3fFboCompletenessTests.e_samples = { NONE: -2, TEXTURE: -1 }; /** * @typedef {{numSamples: Array}} */ es3fFboCompletenessTests.numSamplesParamsT; /** * @param {number} colour * @param {number} depth * @param {number} stencil * @return {es3fFboCompletenessTests.numSamplesParamsT} */ es3fFboCompletenessTests.numSamplesParams = function(colour, depth, stencil) { var ret = { numSamples: new Array(3) }; if (colour !== undefined) { ret.numSamples[0] = colour; if (depth !== undefined) { ret.numSamples[1] = depth; if (stencil !== undefined) { ret.numSamples[2] = stencil; } } } return ret; }; /** * @param {es3fFboCompletenessTests.numSamplesParamsT} params * @return {string} */ es3fFboCompletenessTests.numSamplesParams.getName = function(params) { var out = ''; var first = true; for (var i = 0; i < 3; ++i) { if (first) first = false; else out += '_'; switch (params.numSamples[i]) { case es3fFboCompletenessTests.e_samples.NONE: out += 'none'; break; case es3fFboCompletenessTests.e_samples.TEXTURE: out += 'tex'; break; default: out += 'rbo'; break; } } return out; }; /** * @param {es3fFboCompletenessTests.numSamplesParamsT} params * @return {string} */ es3fFboCompletenessTests.numSamplesParams.getDescription = function(params) { var out = ''; var names = ['color', 'depth', 'stencil']; var first = true; for (var i = 0; i < 3; ++i) { if (first) first = false; else out += ', '; if (params.numSamples[i] == es3fFboCompletenessTests.e_samples.TEXTURE) { out += 'texture ' + names[i] + ' attachment'; } else { out += params.numSamples[i] + '-sample renderbuffer ' + names[i] + ' attachment'; } } return out; }; /** * @constructor * @extends {glsFboCompletenessTests.TestBase} * @param {string} name * @param {string} desc * @param {glsFboCompletenessTests.Context} ctx * @param {es3fFboCompletenessTests.numSamplesParamsT} params */ es3fFboCompletenessTests.NumSamplesTest = function(name, desc, ctx, params) { glsFboCompletenessTests.TestBase.call(this, name, desc, params); this.m_ctx = ctx; }; es3fFboCompletenessTests.NumSamplesTest.prototype = Object.create(glsFboCompletenessTests.TestBase.prototype); es3fFboCompletenessTests.NumSamplesTest.prototype.constructor = es3fFboCompletenessTests.NumSamplesTest; es3fFboCompletenessTests.NumSamplesTest.prototype.build = function(builder, gl) { if (!(gl = gl || window.gl)) throw new Error('Invalid gl object'); var s_targets = [ gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.DEPTH_ATTACHMENT ]; // Non-integer formats for each attachment type. // \todo [2013-12-17 lauri] Add fixed/floating/integer metadata for formats so // we can pick one smartly or maybe try several. var s_formats = [ gl.RGBA8, gl.RGB565, gl.DEPTH_COMPONENT24 ]; var l = s_targets.length; if (this.m_params.numSamples.length != l) throw new Error('Wrong number of params.'); for (var i = 0; i < l; ++i) { var target = s_targets[i]; var fmt = new glsFboUtil.ImageFormat(s_formats[i], gl.NONE); var ns = this.m_params.numSamples[i]; if (ns == es3fFboCompletenessTests.e_samples.NONE) continue; if (ns == es3fFboCompletenessTests.e_samples.TEXTURE) { this.attachTargetToNew(target, gl.TEXTURE, fmt, 64, 64, builder, gl); } else { var rboCfg = builder.makeConfig(glsFboUtil.Renderbuffer); rboCfg.internalFormat = fmt; rboCfg.width = rboCfg.height = 64; rboCfg.numSamples = ns; var rbo = builder.glCreateRbo(rboCfg); // Implementations do not necessarily support sample sizes greater than 1. if (builder.getError() == gl.INVALID_OPERATION) { throw new Error('Unsupported number of samples.'); } var att = builder.makeConfig(glsFboUtil.RenderbufferAttachment); att.imageName = rbo; builder.glAttach(target, att); } } return true; }; es3fFboCompletenessTests.init = function() { //(testCtx, renderCtx, factory) { var fboCtx = new glsFboCompletenessTests.Context(null, gl, function() { return new es3fFboCompletenessTests.ES3Checker(); }); fboCtx.addFormats(glsFboUtil.rangeArray(es3fFboCompletenessTests.s_es3Formats)); /** @const @type {tcuTestCase.DeqpTest} */ var testGroup = tcuTestCase.runner.testCases; testGroup.addChild(fboCtx.createRenderableTests(gl)); testGroup.addChild(fboCtx.createAttachmentTests(gl)); testGroup.addChild(fboCtx.createSizeTests(gl)); /** @type {tcuTestCase.DeqpTest} */ var layerTests = tcuTestCase.newTest('layer', 'Tests for layer attachments'); /** @static */ var s_layersParams = [ es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_2D_ARRAY, 1, 0), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_2D_ARRAY, 1, 3), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_2D_ARRAY, 4, 3), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_2D_ARRAY, 4, 15), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_3D, 1, 0), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_3D, 1, 15), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_3D, 4, 15), es3fFboCompletenessTests.numLayersParams(gl.TEXTURE_3D, 64, 15) ]; for (var i = 0; i < s_layersParams.length; ++i) { var name = 'name'; var desc = 'desc'; layerTests.addChild(new es3fFboCompletenessTests.NumLayersTest( es3fFboCompletenessTests.numLayersParams.getName(s_layersParams[i]), es3fFboCompletenessTests.numLayersParams.getDescription(s_layersParams[i]), fboCtx, s_layersParams[i] )); } testGroup.addChild(layerTests); /** @type {tcuTestCase.DeqpTest} */ var sampleTests = tcuTestCase.newTest('sample', 'Tests for multisample attachments'); // some short hand var samples = es3fFboCompletenessTests.e_samples; // sample tests /** @static */ var s_samplesParams = [ es3fFboCompletenessTests.numSamplesParams(0, samples.NONE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(1, samples.NONE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(2, samples.NONE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(0, samples.TEXTURE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(1, samples.TEXTURE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(2, samples.TEXTURE, samples.NONE), es3fFboCompletenessTests.numSamplesParams(2, 1, samples.NONE), es3fFboCompletenessTests.numSamplesParams(2, 2, samples.NONE), es3fFboCompletenessTests.numSamplesParams(0, 0, samples.TEXTURE), es3fFboCompletenessTests.numSamplesParams(1, 2, 0), es3fFboCompletenessTests.numSamplesParams(2, 2, 0), es3fFboCompletenessTests.numSamplesParams(1, 1, 1), es3fFboCompletenessTests.numSamplesParams(1, 2, 4) ]; for (var i = 0; i < s_samplesParams.length; ++i) { var name = 'name'; var desc = 'desc'; sampleTests.addChild(new es3fFboCompletenessTests.NumSamplesTest( es3fFboCompletenessTests.numSamplesParams.getName(s_samplesParams[i]), es3fFboCompletenessTests.numSamplesParams.getDescription(s_samplesParams[i]), fboCtx, s_samplesParams[i] )); } testGroup.addChild(sampleTests); }; es3fFboCompletenessTests.run = function() { var testName = 'completeness'; var testDescription = 'Completeness tests'; var state = tcuTestCase.runner; state.testName = testName; state.testCases = tcuTestCase.newTest(testName, testDescription, null); //Set up name and description of this test series. setCurrentTestName(testName); description(testDescription); try { es3fFboCompletenessTests.init(); tcuTestCase.runner.runCallback(tcuTestCase.runTestCases); } catch (err) { bufferedLogToConsole(err); tcuTestCase.runner.terminate(); } }; });