es3fInstancedRenderingTests.js (40461B)
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.es3fInstancedRenderingTests'); 23 goog.require('framework.common.tcuImageCompare'); 24 goog.require('framework.common.tcuSurface'); 25 goog.require('framework.common.tcuTestCase'); 26 goog.require('framework.delibs.debase.deMath'); 27 goog.require('framework.delibs.debase.deRandom'); 28 goog.require('framework.delibs.debase.deString'); 29 goog.require('framework.opengl.gluShaderProgram'); 30 goog.require('framework.opengl.gluShaderUtil'); 31 goog.require('framework.opengl.gluTextureUtil'); 32 33 goog.scope(function() { 34 35 var es3fInstancedRenderingTests = functional.gles3.es3fInstancedRenderingTests; 36 var gluShaderUtil = framework.opengl.gluShaderUtil; 37 var gluShaderProgram = framework.opengl.gluShaderProgram; 38 var tcuTestCase = framework.common.tcuTestCase; 39 var tcuSurface = framework.common.tcuSurface; 40 var deString = framework.delibs.debase.deString; 41 var deRandom = framework.delibs.debase.deRandom; 42 var tcuImageCompare = framework.common.tcuImageCompare; 43 var gluTextureUtil = framework.opengl.gluTextureUtil; 44 var deMath = framework.delibs.debase.deMath; 45 46 /** @type {?WebGL2RenderingContext} */ var gl; 47 48 /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_WIDTH = 128; 49 /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_HEIGHT = 128; 50 51 /** @const @type {number} */ es3fInstancedRenderingTests.QUAD_GRID_SIZE = 127; 52 53 // Attribute divisors for the attributes defining the color's RGB components. 54 /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_R = 3; 55 /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_G = 2; 56 /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_B = 1; 57 58 /** @const @type {number} */es3fInstancedRenderingTests.OFFSET_COMPONENTS = 3; // \note Affects whether a float or a vecN is used in shader, but only first component is non-zero. 59 60 // Scale and bias values when converting float to integer, when attribute is of integer type. 61 /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_INT_SCALE = 100.0; 62 /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_INT_BIAS = -50.0; 63 /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_UINT_SCALE = 100.0; 64 /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_UINT_BIAS = 0.0; 65 66 var DE_ASSERT = function(expression) { 67 if (!expression) throw new Error('Assert failed'); 68 }; 69 70 es3fInstancedRenderingTests.TCU_FAIL = function(message) { 71 throw new Error(message); 72 }; 73 74 // es3fInstancedRenderingTests.InstancedRenderingCase 75 76 /** 77 * es3fInstancedRenderingTests.DrawFunction 78 * @enum {number} 79 */ 80 es3fInstancedRenderingTests.DrawFunction = { 81 FUNCTION_DRAW_ARRAYS_INSTANCED: 0, 82 FUNCTION_DRAW_ELEMENTS_INSTANCED: 1 83 }; 84 85 /** 86 * es3fInstancedRenderingTests.InstancingType 87 * @enum {number} 88 */ 89 es3fInstancedRenderingTests.InstancingType = { 90 TYPE_INSTANCE_ID: 0, 91 TYPE_ATTRIB_DIVISOR: 1, 92 TYPE_MIXED: 2 93 }; 94 95 /** 96 * es3fInstancedRenderingTests.InstancedRenderingCase class, inherits from TestCase class 97 * @constructor 98 * @extends {tcuTestCase.DeqpTest} 99 * @param {string} name 100 * @param {string} description 101 * @param {es3fInstancedRenderingTests.DrawFunction} drawFunction 102 * @param {es3fInstancedRenderingTests.InstancingType} instancingType 103 * @param {gluShaderUtil.DataType} rgbAttrType 104 * @param {number} numInstances 105 */ 106 es3fInstancedRenderingTests.InstancedRenderingCase = function(name, description, drawFunction, instancingType, rgbAttrType, numInstances) { 107 tcuTestCase.DeqpTest.call(this, name, description); 108 /** @type {es3fInstancedRenderingTests.DrawFunction} */ this.m_function = drawFunction; 109 /** @type {es3fInstancedRenderingTests.InstancingType} */ this.m_instancingType = instancingType; 110 /** @type {gluShaderUtil.DataType} */ this.m_rgbAttrType = rgbAttrType; 111 /** @type {number} */ this.m_numInstances = numInstances; 112 /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null; 113 /** @type {Array<number>} */ this.m_gridVertexPositions = []; 114 /** @type {Array<number>} */ this.m_gridIndices = []; 115 /** @type {Array<number>} */ this.m_instanceOffsets = []; 116 /** @type {Array<number>} */ this.m_instanceColorR = []; 117 /** @type {Array<number>} */ this.m_instanceColorG = []; 118 /** @type {Array<number>} */ this.m_instanceColorB = []; 119 }; 120 121 es3fInstancedRenderingTests.InstancedRenderingCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype); 122 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.constructor = es3fInstancedRenderingTests.InstancedRenderingCase; 123 124 /** 125 * Helper function that does biasing and scaling when converting float to integer. 126 * @param {Array<number>} vec 127 * @param {number} val 128 */ 129 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.pushVarCompAttrib = function(vec, val) { 130 var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType); 131 var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType); 132 var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType); 133 var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType); 134 if (isFloatCase || isMatCase) 135 vec.push(val); 136 else if (isIntCase) 137 vec.push(val * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS); 138 else if (isUintCase) 139 vec.push(val * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS); 140 else 141 throw new Error('Invalid attribute type.'); 142 }; 143 144 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.init = function() { 145 // Clear errors from previous tests 146 gl.getError(); 147 148 /** @type {boolean} */ var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType); 149 /** @type {boolean} */ var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType); 150 /** @type {boolean} */ var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType); 151 /** @type {boolean} */ var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType); 152 /** @type {number} */ var typeSize = gluShaderUtil.getDataTypeScalarSize(this.m_rgbAttrType); 153 /** @type {boolean} */ var isScalarCase = typeSize == 1; 154 /** @type {string} */ var swizzleFirst = isScalarCase ? '' : '.x'; 155 /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(this.m_rgbAttrType); 156 157 /** @type {string} */ var floatIntScaleStr = '(' + es3fInstancedRenderingTests.FLOAT_INT_SCALE.toFixed(3) + ')'; 158 /** @type {string} */ var floatIntBiasStr = '(' + es3fInstancedRenderingTests.FLOAT_INT_BIAS.toFixed(3) + ')'; 159 /** @type {string} */ var floatUintScaleStr = '(' + es3fInstancedRenderingTests.FLOAT_UINT_SCALE.toFixed(3) + ')'; 160 /** @type {string} */ var floatUintBiasStr = '(' + es3fInstancedRenderingTests.FLOAT_UINT_BIAS.toFixed(3) + ')'; 161 162 DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase); 163 164 // Generate shader. 165 // \note For case TYPE_MIXED, vertex position offset and color red component get their values from instance id, while green and blue get their values from instanced attributes. 166 167 /** @type {string} */ var numInstancesStr = this.m_numInstances.toString() + '.0'; 168 169 /** @type {string} */ var instanceAttribs = ''; 170 /** @type {string} */ var posExpression = ''; 171 /** @type {string} */ var colorRExpression = ''; 172 /** @type {string} */ var colorGExpression = ''; 173 /** @type {string} */ var colorBExpression = ''; 174 175 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) { 176 posExpression = 'a_position + vec4(float(gl_InstanceID) * 2.0 / ' + numInstancesStr + ', 0.0, 0.0, 0.0)'; 177 colorRExpression = 'float(gl_InstanceID)/' + numInstancesStr; 178 179 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID) { 180 colorGExpression = 'float(gl_InstanceID)*2.0/' + numInstancesStr; 181 colorBExpression = '1.0 - float(gl_InstanceID)/' + numInstancesStr; 182 } 183 } 184 185 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) { 186 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) { 187 posExpression = 'a_position + vec4(a_instanceOffset'; 188 189 DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4); 190 191 for (var i = 0; i < 4 - es3fInstancedRenderingTests.OFFSET_COMPONENTS; i++) 192 posExpression += ', 0.0'; 193 posExpression += ')'; 194 195 if (isFloatCase) 196 colorRExpression = 'a_instanceR' + swizzleFirst; 197 else if (isIntCase) 198 colorRExpression = '(float(a_instanceR' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr; 199 else if (isUintCase) 200 colorRExpression = '(float(a_instanceR' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr; 201 else if (isMatCase) 202 colorRExpression = 'a_instanceR[0][0]'; 203 else 204 DE_ASSERT(false); 205 206 instanceAttribs += 'in highp ' + (es3fInstancedRenderingTests.OFFSET_COMPONENTS == 1 ? 'float' : 'vec' + es3fInstancedRenderingTests.OFFSET_COMPONENTS.toString()) + ' a_instanceOffset;\n'; 207 instanceAttribs += 'in mediump ' + typeName + ' a_instanceR;\n'; 208 } 209 210 if (isFloatCase) { 211 colorGExpression = 'a_instanceG' + swizzleFirst; 212 colorBExpression = 'a_instanceB' + swizzleFirst; 213 } else if (isIntCase) { 214 colorGExpression = '(float(a_instanceG' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr; 215 colorBExpression = '(float(a_instanceB' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr; 216 } else if (isUintCase) { 217 colorGExpression = '(float(a_instanceG' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr; 218 colorBExpression = '(float(a_instanceB' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr; 219 } else if (isMatCase) { 220 colorGExpression = 'a_instanceG[0][0]'; 221 colorBExpression = 'a_instanceB[0][0]'; 222 } else 223 DE_ASSERT(false); 224 225 instanceAttribs += 'in mediump ' + typeName + ' a_instanceG;\n'; 226 instanceAttribs += 'in mediump ' + typeName + ' a_instanceB;\n'; 227 } 228 229 DE_ASSERT(!(posExpression.length == 0)); 230 DE_ASSERT(!(colorRExpression.length == 0)); 231 DE_ASSERT(!(colorGExpression.length == 0)); 232 DE_ASSERT(!(colorBExpression.length == 0)); 233 234 /** @type {string} */ var vertShaderSourceStr = 235 '#version 300 es\n' + 236 'in highp vec4 a_position;\n' + 237 instanceAttribs + 238 'out mediump vec4 v_color;\n' + 239 '\n' + 240 'void main()\n' + 241 ' {\n' + 242 ' gl_Position = ' + posExpression + ';\n' + 243 ' v_color.r = ' + colorRExpression + ';\n' + 244 ' v_color.g = ' + colorGExpression + ';\n' + 245 ' v_color.b = ' + colorBExpression + ';\n' + 246 ' v_color.a = 1.0;\n' + 247 '}\n'; 248 249 /** @type {string} */ var fragShaderSource = 250 '#version 300 es\n' + 251 'layout(location = 0) out mediump vec4 o_color;\n' + 252 'in mediump vec4 v_color;\n' + 253 '\n' + 254 'void main()\n' + 255 ' {\n' + 256 ' o_color = v_color;\n' + 257 '}\n'; 258 259 // Create shader program and log it. 260 261 DE_ASSERT(!this.m_program); 262 this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertShaderSourceStr, fragShaderSource)); 263 264 //tcu::TestLog& log = this.m_testCtx.getLog(); 265 //log << *m_program; 266 // TODO: bufferedLogToConsole? 267 //bufferedLogToConsole(this.m_program); 268 269 assertMsgOptions(this.m_program.isOk(), 'Failed to compile shader', false, true); 270 271 // Vertex shader attributes. 272 273 if (this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED) { 274 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>. 275 276 for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1; y++) 277 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1; x++) { 278 /** @type {number} */ var fx = -1.0 + x / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances; 279 /** @type {number} */ var fy = -1.0 + y / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0; 280 281 this.m_gridVertexPositions.push(fx); 282 this.m_gridVertexPositions.push(fy); 283 } 284 285 // Indices. 286 287 for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE; y++) 288 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE; x++) { 289 /** @type {number} */ var ndx00 = y * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x; 290 /** @type {number} */ var ndx10 = y * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x + 1; 291 /** @type {number} */ var ndx01 = (y + 1) * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x; 292 /** @type {number} */ var ndx11 = (y + 1) * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x + 1; 293 294 // Lower-left triangle of a quad. 295 this.m_gridIndices.push(ndx00); 296 this.m_gridIndices.push(ndx10); 297 this.m_gridIndices.push(ndx01); 298 299 // Upper-right triangle of a quad. 300 this.m_gridIndices.push(ndx11); 301 this.m_gridIndices.push(ndx01); 302 this.m_gridIndices.push(ndx10); 303 } 304 } else { 305 DE_ASSERT(this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED); 306 307 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>. 308 309 for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE; y++) 310 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE; x++) { 311 /** @type {number} */ var fx0 = -1.0 + (x + 0) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances; 312 /** @type {number} */ var fx1 = -1.0 + (x + 1) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances; 313 /** @type {number} */ var fy0 = -1.0 + (y + 0) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0; 314 /** @type {number} */ var fy1 = -1.0 + (y + 1) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0; 315 316 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1) 317 this.m_gridVertexPositions.push(fx0); 318 this.m_gridVertexPositions.push(fy0); 319 this.m_gridVertexPositions.push(fx1); 320 this.m_gridVertexPositions.push(fy0); 321 this.m_gridVertexPositions.push(fx0); 322 this.m_gridVertexPositions.push(fy1); 323 324 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0) 325 this.m_gridVertexPositions.push(fx1); 326 this.m_gridVertexPositions.push(fy1); 327 this.m_gridVertexPositions.push(fx0); 328 this.m_gridVertexPositions.push(fy1); 329 this.m_gridVertexPositions.push(fx1); 330 this.m_gridVertexPositions.push(fy0); 331 } 332 } 333 334 // Instanced attributes: position offset and color RGB components. 335 336 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) { 337 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) { 338 // Offsets are such that the vertical bars are drawn next to each other. 339 for (var i = 0; i < this.m_numInstances; i++) { 340 this.m_instanceOffsets.push(i * 2.0 / this.m_numInstances); 341 342 DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4); 343 344 for (var j = 0; j < es3fInstancedRenderingTests.OFFSET_COMPONENTS - 1; j++) 345 this.m_instanceOffsets.push(0.0); 346 } 347 348 /** @type {number} */ var rInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_R == 0 ? 0 : 1); 349 for (var i = 0; i < rInstances; i++) { 350 this.pushVarCompAttrib(this.m_instanceColorR, i / rInstances); 351 352 for (var j = 0; j < typeSize - 1; j++) 353 this.pushVarCompAttrib(this.m_instanceColorR, 0.0); 354 } 355 } 356 357 /** @type {number} */ var gInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_G == 0 ? 0 : 1); 358 for (var i = 0; i < gInstances; i++) { 359 this.pushVarCompAttrib(this.m_instanceColorG, i * 2.0 / gInstances); 360 361 for (var j = 0; j < typeSize - 1; j++) 362 this.pushVarCompAttrib(this.m_instanceColorG, 0.0); 363 } 364 365 /** @type {number} */ var bInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_B == 0 ? 0 : 1); 366 for (var i = 0; i < bInstances; i++) { 367 this.pushVarCompAttrib(this.m_instanceColorB, 1.0 - i / bInstances); 368 369 for (var j = 0; j < typeSize - 1; j++) 370 this.pushVarCompAttrib(this.m_instanceColorB, 0.0); 371 } 372 } 373 }; 374 375 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.deinit = function() { 376 var numVertexAttribArrays = /** @type{number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS)); 377 for (var idx = 0; idx < numVertexAttribArrays; idx++) { 378 gl.disableVertexAttribArray(idx); 379 gl.vertexAttribDivisor(idx, 0); 380 } 381 }; 382 383 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.iterate = function() { 384 /** @type {number} */ var width = Math.min(gl.drawingBufferWidth, es3fInstancedRenderingTests.MAX_RENDER_WIDTH); 385 /** @type {number} */ var height = Math.min(gl.drawingBufferHeight, es3fInstancedRenderingTests.MAX_RENDER_HEIGHT); 386 387 /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width; 388 /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height; 389 390 /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name)); 391 392 /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax); 393 /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax); 394 395 /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(width, height); 396 /** @type {tcuSurface.Surface} */ var resultImg = new tcuSurface.Surface(width, height); 397 398 // Draw result. 399 400 gl.viewport(xOffset, yOffset, width, height); 401 gl.clear(gl.COLOR_BUFFER_BIT); 402 403 this.setupAndRender(); 404 405 var resImg = resultImg.getAccess(); 406 var resImgTransferFormat = gluTextureUtil.getTransferFormat(resImg.getFormat()); 407 408 gl.readPixels(xOffset, yOffset, resImg.m_width, resImg.m_height, resImgTransferFormat.format, resImgTransferFormat.dataType, resultImg.m_pixels); 409 410 // Compute reference. 411 this.computeReference(referenceImg); 412 413 // Compare. 414 415 // Passing referenceImg.getAccess() and resultImg.getAccess() instead of referenceImg and resultImg 416 /** @type {boolean} */ var testOk = tcuImageCompare.fuzzyCompare('ComparisonResult', 'Image comparison result', referenceImg.getAccess(), resultImg.getAccess(), 0.05 /*, gluShaderUtil.COMPARE_LOG_RESULT*/); 417 418 assertMsgOptions(testOk, '', true, false); 419 420 return tcuTestCase.IterateResult.STOP; 421 }; 422 423 /** 424 * @param {Array<number>} attrPtr 425 * @param {number} location 426 * @param {number} divisor 427 */ 428 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.setupVarAttribPointer = function(attrPtr, location, divisor) { 429 /** @type {boolean} */ var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType); 430 /** @type {boolean} */ var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType); 431 /** @type {boolean} */ var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType); 432 /** @type {boolean} */ var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType); 433 /** @type {number} */ var typeSize = gluShaderUtil.getDataTypeScalarSize(this.m_rgbAttrType); 434 /** @type {number} */ var numSlots = isMatCase ? gluShaderUtil.getDataTypeMatrixNumColumns(this.m_rgbAttrType) : 1; // Matrix uses as many attribute slots as it has columns. 435 436 for (var slotNdx = 0; slotNdx < numSlots; slotNdx++) { 437 /** @type {number} */ var curLoc = location + slotNdx; 438 439 gl.enableVertexAttribArray(curLoc); 440 gl.vertexAttribDivisor(curLoc, divisor); 441 var curLocGlBuffer = gl.createBuffer(); 442 if (isFloatCase) { 443 var bufferCurLoc = new Float32Array(attrPtr); 444 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer); 445 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW); 446 447 gl.vertexAttribPointer(curLoc, typeSize, gl.FLOAT, false, 0, 0); 448 } else if (isIntCase) { 449 var bufferCurLoc = new Int32Array(attrPtr); 450 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer); 451 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW); 452 453 gl.vertexAttribIPointer(curLoc, typeSize, gl.INT, 0, 0); 454 } else if (isUintCase) { 455 var bufferCurLoc = new Uint32Array(attrPtr); 456 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer); 457 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW); 458 459 gl.vertexAttribIPointer(curLoc, typeSize, gl.UNSIGNED_INT, 0, 0); 460 } else if (isMatCase) { 461 /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(this.m_rgbAttrType); 462 /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(this.m_rgbAttrType); 463 464 var bufferCurLoc = new Float32Array(attrPtr); 465 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer); 466 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW); 467 468 gl.vertexAttribPointer(curLoc, numRows, gl.FLOAT, false, numCols * numRows * 4, 0); 469 } else 470 DE_ASSERT(false); 471 } 472 }; 473 474 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.setupAndRender = function() { 475 /** @type {WebGLProgram} */ var program = this.m_program.getProgram(); 476 477 gl.useProgram(program); 478 // Setup attributes. 479 480 // Position attribute is non-instanced. 481 /** @type {number} */ var positionLoc = gl.getAttribLocation(program, 'a_position'); 482 gl.enableVertexAttribArray(positionLoc); 483 var positionBuffer = gl.createBuffer(); 484 var bufferGridVertexPosition = new Float32Array(this.m_gridVertexPositions); 485 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); 486 gl.bufferData(gl.ARRAY_BUFFER, bufferGridVertexPosition, gl.STATIC_DRAW); 487 gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); 488 489 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) { 490 if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) { 491 // Position offset attribute is instanced with separate offset for every instance. 492 /** @type {number} */ var offsetLoc = gl.getAttribLocation(program, 'a_instanceOffset'); 493 gl.enableVertexAttribArray(offsetLoc); 494 gl.vertexAttribDivisor(offsetLoc, 1); 495 496 var offsetLocGlBuffer = gl.createBuffer(); 497 var bufferOffsetLoc = new Float32Array(this.m_instanceOffsets); 498 gl.bindBuffer(gl.ARRAY_BUFFER, offsetLocGlBuffer); 499 gl.bufferData(gl.ARRAY_BUFFER, bufferOffsetLoc, gl.STATIC_DRAW); 500 501 gl.vertexAttribPointer(offsetLoc, es3fInstancedRenderingTests.OFFSET_COMPONENTS, gl.FLOAT, false, 0, 0); 502 503 /** @type {number} */ var rLoc = gl.getAttribLocation(program, 'a_instanceR'); 504 this.setupVarAttribPointer(this.m_instanceColorR, rLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_R); 505 } 506 507 /** @type {number} */ var gLoc = gl.getAttribLocation(program, 'a_instanceG'); 508 this.setupVarAttribPointer(this.m_instanceColorG, gLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_G); 509 510 /** @type {number} */ var bLoc = gl.getAttribLocation(program, 'a_instanceB'); 511 this.setupVarAttribPointer(this.m_instanceColorB, bLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_B); 512 } 513 514 // Draw using appropriate function. 515 516 if (this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED) { 517 /** @type {number} */ var numPositionComponents = 2; 518 gl.drawArraysInstanced(gl.TRIANGLES, 0, Math.floor(this.m_gridVertexPositions.length / numPositionComponents), this.m_numInstances); 519 } else { 520 var gridIndicesGLBuffer = gl.createBuffer(); 521 var bufferGridIndices = new Uint16Array(this.m_gridIndices); 522 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gridIndicesGLBuffer); 523 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferGridIndices, gl.STATIC_DRAW); 524 525 gl.drawElementsInstanced(gl.TRIANGLES, this.m_gridIndices.length, gl.UNSIGNED_SHORT, 0, this.m_numInstances); 526 } 527 gl.useProgram(null); 528 }; 529 530 /** 531 * @param {tcuSurface.Surface} dst 532 */ 533 es3fInstancedRenderingTests.InstancedRenderingCase.prototype.computeReference = function(dst) { 534 /** @type {number} */ var wid = dst.getWidth(); 535 /** @type {number} */ var hei = dst.getHeight(); 536 537 // Draw a rectangle (vertical bar) for each instance. 538 539 for (var instanceNdx = 0; instanceNdx < this.m_numInstances; instanceNdx++) { 540 /** @type {number} */ var xStart = Math.floor(instanceNdx * wid / this.m_numInstances); 541 /** @type {number} */ var xEnd = Math.floor((instanceNdx + 1) * wid / this.m_numInstances); 542 543 // Emulate attribute divisors if that is the case. 544 545 /** @type {number} */ var clrNdxR = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) : instanceNdx; 546 /** @type {number} */ var clrNdxG = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) : instanceNdx; 547 /** @type {number} */ var clrNdxB = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) : instanceNdx; 548 549 /** @type {number} */ var rInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_R == 0 ? 0 : 1) : this.m_numInstances; 550 /** @type {number} */ var gInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_G == 0 ? 0 : 1) : this.m_numInstances; 551 /** @type {number} */ var bInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_B == 0 ? 0 : 1) : this.m_numInstances; 552 553 // Calculate colors. 554 555 /** @type {number} */ var r = clrNdxR / rInstances; 556 /** @type {number} */ var g = clrNdxG * 2.0 / gInstances; 557 /** @type {number} */ var b = 1.0 - clrNdxB / bInstances; 558 559 // Convert to integer and back if shader inputs are integers. 560 561 if (gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType)) { 562 /** @type {number} */var intR = (r * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS); 563 /** @type {number} */var intG = (g * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS); 564 /** @type {number} */var intB = (b * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS); 565 r = (intR - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE; 566 g = (intG - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE; 567 b = (intB - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE; 568 } else if (gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType)) { 569 /** @type {number} */var uintR = (r * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS); 570 /** @type {number} */var uintG = (g * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS); 571 /** @type {number} */var uintB = (b * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS); 572 r = (uintR - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE; 573 g = (uintG - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE; 574 b = (uintB - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE; 575 } 576 577 // Convert from float to unorm8. 578 var color = deMath.add(deMath.scale([r, g, b, 1.0], 255), [0.5, 0.5, 0.5, 0.5]); 579 color = deMath.clampVector(color, 0, 255); 580 581 // Draw rectangle. 582 for (var y = 0; y < hei; y++) 583 for (var x = xStart; x < xEnd; x++) 584 dst.setPixel(x, y, color); 585 } 586 }; 587 588 es3fInstancedRenderingTests.init = function() { 589 var testGroup = tcuTestCase.runner.testCases; 590 /** @type {Array<number>} */ var instanceCounts = [1, 2, 4, 20]; 591 592 for (var _function in es3fInstancedRenderingTests.DrawFunction) { 593 /** @type {?string} */ var functionName = 594 es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED ? 'draw_arrays_instanced' : 595 es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'draw_elements_instanced' : 596 null; 597 598 /** @type {?string} */ var functionDesc = 599 es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED ? 'Use glDrawArraysInstanced()' : 600 es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'Use glDrawElementsInstanced()' : 601 null; 602 603 DE_ASSERT(functionName != null); 604 DE_ASSERT(functionDesc != null); 605 606 /** @type {tcuTestCase.DeqpTest} */ var functionGroup = tcuTestCase.newTest(functionName, functionDesc); 607 testGroup.addChild(functionGroup); 608 609 for (var instancingType in es3fInstancedRenderingTests.InstancingType) { 610 /** @type {?string} */ var instancingTypeName = 611 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID ? 'instance_id' : 612 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? 'attribute_divisor' : 613 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? 'mixed' : 614 null; 615 616 /** @type {?string} */ var instancingTypeDesc = 617 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID ? 'Use gl_InstanceID for instancing' : 618 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? 'Use vertex attribute divisors for instancing' : 619 es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? 'Use both gl_InstanceID and vertex attribute divisors for instancing' : 620 null; 621 622 DE_ASSERT(instancingTypeName != null); 623 DE_ASSERT(instancingTypeDesc != null); 624 625 /** @type {tcuTestCase.DeqpTest} */ 626 var instancingTypeGroup = tcuTestCase.newTest(instancingTypeName, instancingTypeDesc); 627 628 functionGroup.addChild(instancingTypeGroup); 629 630 for (var countNdx in instanceCounts) { 631 /** @type {string} */ var countName = instanceCounts[countNdx].toString() + '_instances'; 632 instancingTypeGroup.addChild(new es3fInstancedRenderingTests.InstancedRenderingCase(countName, 633 '', 634 es3fInstancedRenderingTests.DrawFunction[_function], 635 es3fInstancedRenderingTests.InstancingType[instancingType], 636 gluShaderUtil.DataType.FLOAT, 637 instanceCounts[countNdx])); 638 } 639 } 640 } 641 642 /** @type {Array<gluShaderUtil.DataType>} */ var s_testTypes = 643 [ 644 gluShaderUtil.DataType.FLOAT, 645 gluShaderUtil.DataType.FLOAT_VEC2, 646 gluShaderUtil.DataType.FLOAT_VEC3, 647 gluShaderUtil.DataType.FLOAT_VEC4, 648 gluShaderUtil.DataType.FLOAT_MAT2, 649 gluShaderUtil.DataType.FLOAT_MAT2X3, 650 gluShaderUtil.DataType.FLOAT_MAT2X4, 651 gluShaderUtil.DataType.FLOAT_MAT3X2, 652 gluShaderUtil.DataType.FLOAT_MAT3, 653 gluShaderUtil.DataType.FLOAT_MAT3X4, 654 gluShaderUtil.DataType.FLOAT_MAT4X2, 655 gluShaderUtil.DataType.FLOAT_MAT4X3, 656 gluShaderUtil.DataType.FLOAT_MAT4, 657 658 gluShaderUtil.DataType.INT, 659 gluShaderUtil.DataType.INT_VEC2, 660 gluShaderUtil.DataType.INT_VEC3, 661 gluShaderUtil.DataType.INT_VEC4, 662 663 gluShaderUtil.DataType.UINT, 664 gluShaderUtil.DataType.UINT_VEC2, 665 gluShaderUtil.DataType.UINT_VEC3, 666 gluShaderUtil.DataType.UINT_VEC4 667 ]; 668 669 /** @type {number} */ var typeTestNumInstances = 4; 670 671 /** @type {tcuTestCase.DeqpTest} */ var typesGroup = tcuTestCase.newTest('types', 'Tests for instanced attributes of particular data types'); 672 673 testGroup.addChild(typesGroup); 674 675 for (var typeNdx in s_testTypes) { 676 /** @type {gluShaderUtil.DataType} */ var type = s_testTypes[typeNdx]; 677 typesGroup.addChild(new es3fInstancedRenderingTests.InstancedRenderingCase(gluShaderUtil.getDataTypeName(type), '', 678 es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED, 679 es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR, 680 type, 681 typeTestNumInstances)); 682 } 683 }; 684 685 es3fInstancedRenderingTests.run = function(context) { 686 gl = context; 687 //Set up Test Root parameters 688 var testName = 'instanced_rendering'; 689 var testDescription = 'Instanced Rendering Tests'; 690 var state = tcuTestCase.runner; 691 692 state.testName = testName; 693 state.setRoot(tcuTestCase.newTest(testName, testDescription, null)); 694 695 //Set up name and description of this test series. 696 setCurrentTestName(testName); 697 description(testDescription); 698 699 try { 700 //Create test cases 701 es3fInstancedRenderingTests.init(); 702 //Run test cases 703 tcuTestCase.runTestCases(); 704 } 705 catch (err) { 706 testFailedOptions('Failed to es3fInstancedRenderingTests.run tests', false); 707 tcuTestCase.runner.terminate(); 708 } 709 }; 710 711 });