es3fFboMultisampleTests.js (16699B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ 20 21 'use strict'; 22 goog.provide('functional.gles3.es3fFboMultisampleTests'); 23 goog.require('framework.common.tcuImageCompare'); 24 goog.require('framework.common.tcuRGBA'); 25 goog.require('framework.common.tcuSurface'); 26 goog.require('framework.common.tcuTestCase'); 27 goog.require('framework.common.tcuTexture'); 28 goog.require('framework.common.tcuTextureUtil'); 29 goog.require('framework.delibs.debase.deMath'); 30 goog.require('framework.delibs.debase.deRandom'); 31 goog.require('framework.opengl.gluTextureUtil'); 32 goog.require('framework.referencerenderer.rrUtil'); 33 goog.require('functional.gles3.es3fFboTestCase'); 34 goog.require('functional.gles3.es3fFboTestUtil'); 35 36 goog.scope(function() { 37 38 var es3fFboMultisampleTests = functional.gles3.es3fFboMultisampleTests; 39 var es3fFboTestCase = functional.gles3.es3fFboTestCase; 40 var es3fFboTestUtil = functional.gles3.es3fFboTestUtil; 41 var tcuTestCase = framework.common.tcuTestCase; 42 var tcuSurface = framework.common.tcuSurface; 43 var tcuRGBA = framework.common.tcuRGBA; 44 var tcuImageCompare = framework.common.tcuImageCompare; 45 var tcuTexture = framework.common.tcuTexture; 46 var tcuTextureUtil = framework.common.tcuTextureUtil; 47 var deRandom = framework.delibs.debase.deRandom; 48 var deMath = framework.delibs.debase.deMath; 49 var gluTextureUtil = framework.opengl.gluTextureUtil; 50 var rrUtil = framework.referencerenderer.rrUtil; 51 52 /** @type {WebGL2RenderingContext} */ var gl; 53 54 var DE_ASSERT = function(x) { 55 if (!x) 56 throw new Error('Assert failed'); 57 }; 58 59 /** 60 * @constructor 61 * @extends {es3fFboTestCase.FboTestCase} 62 * @param {string} name 63 * @param {string} desc 64 * @param {number} colorFormat 65 * @param {number} depthStencilFormat 66 * @param {Array<number>} size 67 * @param {number} numSamples 68 */ 69 es3fFboMultisampleTests.BasicFboMultisampleCase = function(name, desc, colorFormat, depthStencilFormat, size, numSamples) { 70 es3fFboTestCase.FboTestCase.call(this, name, desc); 71 /** @type {number} */ this.m_colorFormat = colorFormat; 72 /** @type {number} */ this.m_depthStencilFormat = depthStencilFormat; 73 /** @type {Array<number>} */ this.m_size = size; 74 /** @type {number} */ this.m_numSamples = numSamples; 75 }; 76 77 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype = Object.create(es3fFboTestCase.FboTestCase.prototype); 78 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype.constructor = es3fFboMultisampleTests.BasicFboMultisampleCase; 79 80 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype.preCheck = function() { 81 this.checkFormatSupport(this.m_colorFormat); 82 if (!this.checkSampleCount(this.m_colorFormat, this.m_numSamples)) 83 return false; 84 85 if (this.m_depthStencilFormat != gl.NONE) { 86 this.checkFormatSupport(this.m_depthStencilFormat); 87 if (!this.checkSampleCount(this.m_depthStencilFormat, this.m_numSamples)) 88 return false; 89 } 90 return true; // No exception thrown 91 }; 92 93 /** 94 * @param {tcuSurface.Surface} dst 95 */ 96 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype.render = function(dst) { 97 var ctx = this.getCurrentContext(); 98 /** @type {tcuTexture.TextureFormat} */ var colorFmt = gluTextureUtil.mapGLInternalFormat(this.m_colorFormat); 99 /** @type {tcuTexture.TextureFormat} */ var depthStencilFmt = this.m_depthStencilFormat != gl.NONE ? gluTextureUtil.mapGLInternalFormat(this.m_depthStencilFormat) : new tcuTexture.TextureFormat(null, null); 100 /** @type {tcuTextureUtil.TextureFormatInfo} */ var colorFmtInfo = tcuTextureUtil.getTextureFormatInfo(colorFmt); 101 /** @type {boolean} */ var depth = depthStencilFmt.order == tcuTexture.ChannelOrder.D || depthStencilFmt.order == tcuTexture.ChannelOrder.DS; 102 /** @type {boolean} */ var stencil = depthStencilFmt.order == tcuTexture.ChannelOrder.S || depthStencilFmt.order == tcuTexture.ChannelOrder.DS; 103 /** @type {es3fFboTestUtil.GradientShader} */ var gradShader = new es3fFboTestUtil.GradientShader(es3fFboTestUtil.getFragmentOutputType(colorFmt)); 104 /** @type {es3fFboTestUtil.FlatColorShader} */ var flatShader = new es3fFboTestUtil.FlatColorShader(es3fFboTestUtil.getFragmentOutputType(colorFmt)); 105 var gradShaderID = this.getCurrentContext().createProgram(gradShader); 106 var flatShaderID = this.getCurrentContext().createProgram(flatShader); 107 var msaaFbo = null; 108 var resolveFbo = null; 109 var msaaColorRbo = null; 110 var resolveColorRbo = null; 111 var msaaDepthStencilRbo = null; 112 var resolveDepthStencilRbo = null; 113 114 // Create framebuffers. 115 msaaColorRbo = ctx.createRenderbuffer(); 116 ctx.bindRenderbuffer(gl.RENDERBUFFER, msaaColorRbo); 117 ctx.renderbufferStorageMultisample(gl.RENDERBUFFER, this.m_numSamples, this.m_colorFormat, this.m_size[0], this.m_size[1]); 118 119 if (depth || stencil) { 120 msaaDepthStencilRbo = ctx.createRenderbuffer(); 121 ctx.bindRenderbuffer(gl.RENDERBUFFER, msaaDepthStencilRbo); 122 ctx.renderbufferStorageMultisample(gl.RENDERBUFFER, this.m_numSamples, this.m_depthStencilFormat, this.m_size[0], this.m_size[1]); 123 } 124 125 msaaFbo = ctx.createFramebuffer(); 126 ctx.bindFramebuffer(gl.FRAMEBUFFER, msaaFbo); 127 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaColorRbo); 128 if (depth) 129 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, msaaDepthStencilRbo); 130 if (stencil) 131 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, msaaDepthStencilRbo); 132 133 this.checkError(); 134 this.checkFramebufferStatus(gl.FRAMEBUFFER); 135 136 resolveColorRbo = ctx.createRenderbuffer(); 137 ctx.bindRenderbuffer(gl.RENDERBUFFER, resolveColorRbo); 138 ctx.renderbufferStorageMultisample(gl.RENDERBUFFER, 0, this.m_colorFormat, this.m_size[0], this.m_size[1]); 139 140 if (depth || stencil) { 141 resolveDepthStencilRbo = ctx.createRenderbuffer(); 142 ctx.bindRenderbuffer(gl.RENDERBUFFER, resolveDepthStencilRbo); 143 ctx.renderbufferStorageMultisample(gl.RENDERBUFFER, 0, this.m_depthStencilFormat, this.m_size[0], this.m_size[1]); 144 } 145 146 resolveFbo = ctx.createFramebuffer(); 147 ctx.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo); 148 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, resolveColorRbo); 149 if (depth) 150 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, resolveDepthStencilRbo); 151 if (stencil) 152 ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, resolveDepthStencilRbo); 153 154 this.checkError(); 155 this.checkFramebufferStatus(gl.FRAMEBUFFER); 156 157 ctx.bindFramebuffer(gl.FRAMEBUFFER, msaaFbo); 158 ctx.viewport(0, 0, this.m_size[0], this.m_size[1]); 159 160 // Clear depth and stencil buffers. 161 ctx.clearBufferfi(gl.DEPTH_STENCIL, 0, 1.0, 0); 162 163 // Fill MSAA fbo with gradient, depth = [-1..1] 164 ctx.enable(gl.DEPTH_TEST); 165 gradShader.setGradient(this.getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax); 166 167 rrUtil.drawQuad(this.getCurrentContext(), gradShaderID, [-1.0, -1.0, -1.0], [1.0, 1.0, 1.0]); 168 169 // Render random-colored quads. 170 /** @const {number} */ var numQuads = 8; 171 172 // The choice of random seed affects the correctness of the tests, 173 // because there are some boundary conditions which aren't handled 174 // correctly even in the C++ dEQP tests. 175 /** @type {deRandom.Random} */ var rnd = new deRandom.Random(7); 176 177 ctx.depthFunc(gl.ALWAYS); 178 ctx.enable(gl.STENCIL_TEST); 179 ctx.stencilFunc(gl.ALWAYS, 0, 0xff); 180 ctx.stencilOp(gl.KEEP, gl.KEEP, gl.INCR); 181 182 for (var ndx = 0; ndx < numQuads; ndx++) { 183 /** @type {number} */ var r = rnd.getFloat(); 184 /** @type {number} */ var g = rnd.getFloat(); 185 /** @type {number} */ var b = rnd.getFloat(); 186 /** @type {number} */ var a = rnd.getFloat(); 187 /** @type {number} */ var x0 = rnd.getFloat(-1.0, 1.0); 188 /** @type {number} */ var y0 = rnd.getFloat(-1.0, 1.0); 189 /** @type {number} */ var z0 = rnd.getFloat(-1.0, 1.0); 190 /** @type {number} */ var x1 = rnd.getFloat(-1.0, 1.0); 191 /** @type {number} */ var y1 = rnd.getFloat(-1.0, 1.0); 192 /** @type {number} */ var z1 = rnd.getFloat(-1.0, 1.0); 193 194 flatShader.setColor(this.getCurrentContext(), flatShaderID, deMath.add(deMath.multiply([r, g, b, a], deMath.subtract(colorFmtInfo.valueMax, colorFmtInfo.valueMin)), colorFmtInfo.valueMin)); 195 rrUtil.drawQuad(this.getCurrentContext(), flatShaderID, [x0, y0, z0], [x1, y1, z1]); 196 } 197 198 ctx.disable(gl.DEPTH_TEST); 199 ctx.disable(gl.STENCIL_TEST); 200 this.checkError(); 201 202 // Resolve using glBlitFramebuffer(). 203 ctx.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFbo); 204 ctx.blitFramebuffer(0, 0, this.m_size[0], this.m_size[1], 0, 0, this.m_size[0], this.m_size[1], gl.COLOR_BUFFER_BIT | (depth ? gl.DEPTH_BUFFER_BIT : 0) | (stencil ? gl.STENCIL_BUFFER_BIT : 0), gl.NEAREST); 205 206 ctx.bindFramebuffer(gl.READ_FRAMEBUFFER, resolveFbo); 207 208 /** @type {number} */ var numSteps; 209 /** @type {number} */ var step; 210 /** @type {number} */ var d; 211 /** @type {number} */ var c; 212 /** @type {number} */ var s; 213 if (depth) { 214 // Visualize depth. 215 numSteps = 8; 216 step = 2.0 / numSteps; 217 ctx.enable(gl.DEPTH_TEST); 218 ctx.depthFunc(gl.LESS); 219 ctx.depthMask(false); 220 ctx.colorMask(false, false, true, false); 221 222 for (var ndx = 0; ndx < numSteps; ndx++) { 223 d = -1.0 + step * ndx; 224 c = ndx / (numSteps - 1); 225 226 flatShader.setColor(this.getCurrentContext(), flatShaderID, deMath.add(deMath.multiply([0.0, 0.0, c, 1.0], deMath.subtract(colorFmtInfo.valueMax, colorFmtInfo.valueMin)), colorFmtInfo.valueMin)); 227 rrUtil.drawQuad(this.getCurrentContext(), flatShaderID, [-1.0, -1.0, d], [1.0, 1.0, d]); 228 } 229 230 ctx.disable(gl.DEPTH_TEST); 231 } 232 233 if (stencil) { 234 // Visualize stencil. 235 numSteps = 4; 236 step = 1; 237 238 ctx.enable(gl.STENCIL_TEST); 239 ctx.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); 240 ctx.colorMask(false, true, false, false); 241 242 for (var ndx = 0; ndx < numSteps; ndx++) { 243 s = step * ndx; 244 c = ndx / (numSteps - 1); 245 246 ctx.stencilFunc(gl.EQUAL, s, 0xff); 247 248 flatShader.setColor(this.getCurrentContext(), flatShaderID, deMath.add(deMath.multiply([0.0, c, 0.0, 1.0], deMath.subtract(colorFmtInfo.valueMax, colorFmtInfo.valueMin)), colorFmtInfo.valueMin)); 249 rrUtil.drawQuad(this.getCurrentContext(), flatShaderID, [-1.0, -1.0, 0.0], [1.0, 1.0, 0.0]); 250 } 251 252 ctx.disable(gl.STENCIL_TEST); 253 } 254 255 this.readPixelsUsingFormat(dst, 0, 0, this.m_size[0], this.m_size[1], colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias); 256 }; 257 258 /** 259 * @param {tcuSurface.Surface} reference 260 * @param {tcuSurface.Surface} result 261 * @return {boolean} 262 */ 263 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype.colorCompare = function(reference, result) { 264 /** @const {tcuRGBA.RGBA} */ var threshold = tcuRGBA.max(es3fFboTestUtil.getFormatThreshold(this.m_colorFormat), tcuRGBA.newRGBAComponents(12, 12, 12, 12)); 265 return tcuImageCompare.bilinearCompare('Result', 'Image comparison result', reference.getAccess(), result.getAccess(), threshold, tcuImageCompare.CompareLogMode.RESULT); 266 }; 267 268 /** 269 * @param {tcuSurface.Surface} reference 270 * @param {tcuSurface.Surface} result 271 * @return {boolean} 272 */ 273 es3fFboMultisampleTests.BasicFboMultisampleCase.prototype.compare = function(reference, result) { 274 if (this.m_depthStencilFormat != gl.NONE) 275 return es3fFboTestCase.FboTestCase.prototype.compare(reference, result); // FboTestCase.compare 276 else 277 return this.colorCompare(reference, result); 278 }; 279 280 /** 281 * @constructor 282 * @extends {tcuTestCase.DeqpTest} 283 */ 284 es3fFboMultisampleTests.FboMultisampleTests = function() { 285 tcuTestCase.DeqpTest.call(this, 'msaa', 'Multisample FBO tests'); 286 }; 287 288 es3fFboMultisampleTests.FboMultisampleTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype); 289 es3fFboMultisampleTests.FboMultisampleTests.prototype.constructor = es3fFboMultisampleTests.FboMultisampleTests; 290 291 es3fFboMultisampleTests.FboMultisampleTests.prototype.init = function() { 292 /** @const {Array<number>} */ var colorFormats = [ 293 // RGBA formats 294 gl.RGBA8, 295 gl.SRGB8_ALPHA8, 296 gl.RGB10_A2, 297 gl.RGBA4, 298 gl.RGB5_A1, 299 300 // RGB formats 301 gl.RGB8, 302 gl.RGB565, 303 304 // RG formats 305 gl.RG8, 306 307 // R formats 308 gl.R8, 309 310 // gl.EXT_color_buffer_float 311 // Multi-sample floating-point color buffers can be optional supported, see https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/ 312 gl.RGBA32F, 313 gl.RGBA16F, 314 gl.R11F_G11F_B10F, 315 gl.RG32F, 316 gl.RG16F, 317 gl.R32F, 318 gl.R16F 319 ]; 320 321 /** @const {Array<number>} */ var depthStencilFormats = [ 322 gl.DEPTH_COMPONENT32F, 323 gl.DEPTH_COMPONENT24, 324 gl.DEPTH_COMPONENT16, 325 gl.DEPTH32F_STENCIL8, 326 gl.DEPTH24_STENCIL8, 327 gl.STENCIL_INDEX8 328 ]; 329 330 /** @const {Array<number>} */ var sampleCounts = [2, 4, 8]; 331 332 for (var sampleCntNdx in sampleCounts) { 333 /** @type {number} */ var samples = sampleCounts[sampleCntNdx]; 334 /** @type {tcuTestCase.DeqpTest} */ 335 var sampleCountGroup = tcuTestCase.newTest(samples + '_samples', ''); 336 this.addChild(sampleCountGroup); 337 338 // Color formats. 339 for (var fmtNdx in colorFormats) 340 sampleCountGroup.addChild(new es3fFboMultisampleTests.BasicFboMultisampleCase(es3fFboTestUtil.getFormatName(colorFormats[fmtNdx]), '', colorFormats[fmtNdx], gl.NONE, [119, 131], samples)); 341 342 // Depth/stencil formats. 343 for (var fmtNdx in depthStencilFormats) 344 sampleCountGroup.addChild(new es3fFboMultisampleTests.BasicFboMultisampleCase(es3fFboTestUtil.getFormatName(depthStencilFormats[fmtNdx]), '', gl.RGBA8, depthStencilFormats[fmtNdx], [119, 131], samples)); 345 } 346 }; 347 348 es3fFboMultisampleTests.run = function(context, range) { 349 gl = context; 350 //Set up root Test 351 var state = tcuTestCase.runner; 352 353 var test = new es3fFboMultisampleTests.FboMultisampleTests(); 354 var testName = test.fullName(); 355 var testDescription = test.getDescription(); 356 357 state.testName = testName; 358 state.setRoot(test); 359 //Set up name and description of this test series. 360 setCurrentTestName(testName); 361 description(testDescription); 362 363 try { 364 //Create test cases 365 test.init(); 366 if (range) 367 state.setRange(range); 368 //Run test cases 369 tcuTestCase.runTestCases(); 370 } 371 catch (err) { 372 testFailedOptions('Failed to es3fFboMultisampleTests.run tests', false); 373 tcuTestCase.runner.terminate(); 374 } 375 }; 376 377 });