glsBufferTestUtil.js (41334B)
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('modules.shared.glsBufferTestUtil'); 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.delibs.debase.deMath'); 29 goog.require('framework.delibs.debase.deRandom'); 30 goog.require('framework.delibs.debase.deString'); 31 goog.require('framework.delibs.debase.deUtil'); 32 goog.require('framework.opengl.gluDrawUtil'); 33 goog.require('framework.opengl.gluShaderProgram'); 34 goog.require('framework.opengl.gluShaderUtil'); 35 36 goog.scope(function() { 37 38 var glsBufferTestUtil = modules.shared.glsBufferTestUtil; 39 var tcuImageCompare = framework.common.tcuImageCompare; 40 var tcuRGBA = framework.common.tcuRGBA; 41 var tcuSurface = framework.common.tcuSurface; 42 var tcuTestCase = framework.common.tcuTestCase; 43 var tcuTexture = framework.common.tcuTexture; 44 var gluShaderProgram = framework.opengl.gluShaderProgram; 45 var gluShaderUtil = framework.opengl.gluShaderUtil; 46 var gluDrawUtil = framework.opengl.gluDrawUtil; 47 var deUtil = framework.delibs.debase.deUtil; 48 var deMath = framework.delibs.debase.deMath; 49 var deRandom = framework.delibs.debase.deRandom; 50 var deString = framework.delibs.debase.deString; 51 52 glsBufferTestUtil.VERIFY_QUAD_SIZE = 8; //!< Quad size in VertexArrayVerifier 53 glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW = 128; //!< Maximum number of lines per one draw in IndexArrayVerifier 54 glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128; 55 glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128; 56 57 // Helper functions. 58 59 /** 60 * @param {Uint8Array} ptr 61 * @param {number} numBytes 62 * @param {number} seed 63 */ 64 glsBufferTestUtil.fillWithRandomBytes = function(ptr, numBytes, seed) { 65 var rnd = new deRandom.Random(seed); 66 for (var left = numBytes; left > 0; left--) 67 ptr[left - 1] = rnd.getInt(); 68 }; 69 70 /** 71 * @param {Uint8Array} resPtr 72 * @param {Uint8Array} refPtr 73 * @param {number} numBytes 74 * @return {boolean} 75 */ 76 glsBufferTestUtil.compareByteArrays = function(resPtr, refPtr, numBytes) { 77 var isOk = true; 78 var maxSpanLen = 8; 79 var maxDiffSpans = 4; 80 var numDiffSpans = 0; 81 var diffSpanStart = -1; 82 var ndx = 0; 83 84 var log = 'Verification result: '; 85 86 for (; ndx < numBytes; ndx++) { 87 if (resPtr[ndx] != refPtr[ndx]) { 88 if (diffSpanStart < 0) 89 diffSpanStart = ndx; 90 91 isOk = false; 92 } else if (diffSpanStart >= 0) { 93 if (numDiffSpans < maxDiffSpans) { 94 var len = ndx - diffSpanStart; 95 var printLen = Math.min(len, maxSpanLen); 96 97 log += len + ' byte difference at offset ' + diffSpanStart + '\n' + 98 ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) + 99 ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen); 100 } else 101 log += '(output too long, truncated)'; 102 103 numDiffSpans += 1; 104 diffSpanStart = -1; 105 } 106 } 107 108 if (diffSpanStart >= 0) { 109 if (numDiffSpans < maxDiffSpans) { 110 var len = ndx - diffSpanStart; 111 var printLen = Math.min(len, maxSpanLen); 112 113 log += len + ' byte difference at offset ' + diffSpanStart + '\n' + 114 ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) + 115 ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen); 116 } else 117 log += '(output too long, truncated)'; 118 } 119 120 log += (isOk ? 'Verification passed.' : 'Verification FAILED!'); 121 122 bufferedLogToConsole(log); 123 124 return isOk; 125 }; 126 127 /** 128 * @param {number} target 129 * @return {string} 130 */ 131 glsBufferTestUtil.getBufferTargetName = function(target) { 132 switch (target) { 133 case gl.ARRAY_BUFFER: return 'array'; 134 case gl.COPY_READ_BUFFER: return 'copy_read'; 135 case gl.COPY_WRITE_BUFFER: return 'copy_write'; 136 case gl.ELEMENT_ARRAY_BUFFER: return 'element_array'; 137 case gl.PIXEL_PACK_BUFFER: return 'pixel_pack'; 138 case gl.PIXEL_UNPACK_BUFFER: return 'pixel_unpack'; 139 //case gl.TEXTURE_BUFFER: return "texture"; //TODO: Unimplemented in WebGL 2. Remove? 140 case gl.TRANSFORM_FEEDBACK_BUFFER: return 'transform_feedback'; 141 case gl.UNIFORM_BUFFER: return 'uniform'; 142 default: 143 throw new Error('Invalid buffer target'); 144 } 145 }; 146 147 /** 148 * @param {number} hint 149 * @return {string} 150 */ 151 glsBufferTestUtil.getUsageHintName = function(hint) { 152 switch (hint) { 153 case gl.STREAM_DRAW: return 'stream_draw'; 154 case gl.STREAM_READ: return 'stream_read'; 155 case gl.STREAM_COPY: return 'stream_copy'; 156 case gl.STATIC_DRAW: return 'static_draw'; 157 case gl.STATIC_READ: return 'static_read'; 158 case gl.STATIC_COPY: return 'static_copy'; 159 case gl.DYNAMIC_DRAW: return 'dynamic_draw'; 160 case gl.DYNAMIC_READ: return 'dynamic_read'; 161 case gl.DYNAMIC_COPY: return 'dynamic_copy'; 162 default: 163 throw new Error('Invalid buffer usage hint'); 164 } 165 }; 166 167 // Base class for buffer cases. 168 // BufferCase 169 170 /** 171 * @constructor 172 * @extends {tcuTestCase.DeqpTest} 173 * @param {string} name 174 * @param {string} description 175 */ 176 glsBufferTestUtil.BufferCase = function(name, description) { 177 tcuTestCase.DeqpTest.call(this, name, description); 178 /** @type {Array<WebGLBuffer>} */ this.m_allocatedBuffers = []; 179 }; 180 181 glsBufferTestUtil.BufferCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype); 182 glsBufferTestUtil.BufferCase.prototype.constructor = glsBufferTestUtil.BufferCase; 183 184 /** 185 * init 186 */ 187 glsBufferTestUtil.BufferCase.prototype.init = function() {}; 188 189 /** 190 * deinit 191 */ 192 glsBufferTestUtil.BufferCase.prototype.deinit = function() { 193 for (var ndx = 0; ndx < this.m_allocatedBuffers.length; ndx++) 194 this.deleteBuffer(this.m_allocatedBuffers[ndx]); 195 }; 196 197 /** 198 * @return {WebGLBuffer} 199 */ 200 glsBufferTestUtil.BufferCase.prototype.genBuffer = function() { 201 var buf = 0; 202 buf = gl.createBuffer(); 203 if (buf != 0) { 204 try { 205 deUtil.dePushUniqueToArray(this.m_allocatedBuffers, buf); 206 } 207 catch (err) { 208 gl.deleteBuffer(buf); 209 throw err; 210 } 211 } 212 return buf; 213 }; 214 215 /** 216 * @param {WebGLBuffer} buffer 217 */ 218 glsBufferTestUtil.BufferCase.prototype.deleteBuffer = function(buffer) { 219 gl.deleteBuffer(buffer); 220 this.m_allocatedBuffers.splice(this.m_allocatedBuffers.indexOf(buffer), 1); 221 }; 222 223 glsBufferTestUtil.BufferCase.prototype.checkError = function() { 224 /** @type {number} */ var err = gl.getError(); 225 if (err != gl.NO_ERROR) 226 throw new TestFailedException('Got ' + WebGLTestUtils.glEnumToString(gl, err)); 227 }; 228 229 // Reference buffer. 230 231 /** 232 * @constructor 233 */ 234 glsBufferTestUtil.ReferenceBuffer = function() { 235 /** @type {ArrayBuffer} */ this.m_data; 236 }; 237 238 /** 239 * @param {number=} offset 240 * @return {Uint8Array} 241 */ 242 glsBufferTestUtil.ReferenceBuffer.prototype.getPtr = function(offset) { 243 offset = offset ? offset : 0; return new Uint8Array(this.m_data, offset); 244 }; 245 246 /** 247 * @param {number} numBytes 248 */ 249 glsBufferTestUtil.ReferenceBuffer.prototype.setSize = function(numBytes) { 250 this.m_data = new ArrayBuffer(numBytes); 251 }; 252 253 /** 254 * @param {number} numBytes 255 * @param {Uint8Array} bytes 256 */ 257 glsBufferTestUtil.ReferenceBuffer.prototype.setData = function(numBytes, bytes) { 258 this.setSize(numBytes); 259 var dst = new Uint8Array(this.m_data); 260 dst.set(bytes.subarray(numBytes)); 261 }; 262 263 /** 264 * @param {number} offset 265 * @param {number} numBytes 266 * @param {Uint8Array} bytes 267 */ 268 glsBufferTestUtil.ReferenceBuffer.prototype.setSubData = function(offset, numBytes, bytes) { 269 assertMsgOptions(deMath.deInBounds32(offset, 0, this.m_data.byteLength) && deMath.deInRange32(offset + numBytes, offset, this.m_data.byteLength), 270 'Parameters not in buffer bounds or range', false, true); 271 var dst = new Uint8Array(this.m_data, offset); 272 dst.set(bytes.subarray(offset, offset + numBytes)); 273 }; 274 275 // Buffer writer system. 276 277 /** 278 * @enum {number} 279 */ 280 glsBufferTestUtil.WriteType = { 281 BUFFER_SUB_DATA: 0, 282 BUFFER_WRITE_MAP: 1, 283 TRANSFORM_FEEDBACK: 2, 284 PIXEL_PACK: 3 285 }; 286 287 /** 288 * @param {glsBufferTestUtil.WriteType} write 289 * @return {string} 290 */ 291 glsBufferTestUtil.getWriteTypeDescription = function(write) { 292 /** @type {Array<string>} */ var s_desc = [ 293 'gl.bufferSubData()', 294 'gl.mapBufferRange()', 295 'transform feedback', 296 'gl.readPixels() into PBO binding' 297 ]; 298 return /** @type {string} */ (deUtil.getArrayElement(s_desc, write)); 299 }; 300 301 // BufferWriterBase 302 303 /** 304 * @constructor 305 */ 306 glsBufferTestUtil.BufferWriterBase = function() {}; 307 308 /** 309 * //Meant to be overriden 310 * @return {number} 311 */ 312 glsBufferTestUtil.BufferWriterBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); }; 313 314 /** 315 * //Meant to be overriden 316 * @return {number} 317 */ 318 glsBufferTestUtil.BufferWriterBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); }; 319 320 /** 321 * //Meant to be overriden 322 * @param {WebGLBuffer} buffer 323 * @param {number} offset 324 * @param {number} numBytes 325 * @param {Uint8Array} bytes 326 */ 327 glsBufferTestUtil.BufferWriterBase.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { throw new Error('Must be overriden'); }; 328 329 /** 330 * @param {WebGLBuffer} buffer 331 * @param {number} offset 332 * @param {number} numBytes 333 * @param {Uint8Array} bytes 334 * @param {number} targetHint 335 */ 336 glsBufferTestUtil.BufferWriterBase.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) { 337 this.writeNoTarget(buffer, offset, numBytes, bytes); 338 }; 339 340 // BufferWriter 341 342 /** 343 * @constructor 344 * @param {glsBufferTestUtil.WriteType} writeType 345 */ 346 glsBufferTestUtil.BufferWriter = function(writeType) { 347 /** @type {glsBufferTestUtil.BufferWriterBase} */ this.m_writer = null; 348 switch (writeType) { 349 case glsBufferTestUtil.WriteType.BUFFER_SUB_DATA: this.m_writer = new glsBufferTestUtil.BufferSubDataWriter(); break; 350 default: 351 testFailed('Unsupported writer'); 352 } 353 }; 354 355 /** 356 * @return {number} 357 */ 358 glsBufferTestUtil.BufferWriter.prototype.getMinSize = function() {return this.m_writer.getMinSize();}; 359 360 /** 361 * @return {number} 362 */ 363 glsBufferTestUtil.BufferWriter.prototype.getAlignment = function() {return this.m_writer.getAlignment();}; 364 365 /** 366 * @param {WebGLBuffer} buffer 367 * @param {number} offset 368 * @param {number} numBytes 369 * @param {Uint8Array} bytes 370 */ 371 glsBufferTestUtil.BufferWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { 372 assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); 373 assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); 374 assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); 375 return this.m_writer.writeNoTarget(buffer, offset, numBytes, bytes); 376 }; 377 378 /** 379 * @param {WebGLBuffer} buffer 380 * @param {number} offset 381 * @param {number} numBytes 382 * @param {Uint8Array} bytes 383 * @param {number} targetHint 384 */ 385 glsBufferTestUtil.BufferWriter.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) { 386 assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); 387 assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); 388 assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); 389 return this.m_writer.write(buffer, offset, numBytes, bytes, targetHint); 390 }; 391 392 // BufferSubDataWriter 393 394 /** 395 * @constructor 396 * @extends {glsBufferTestUtil.BufferWriterBase} 397 */ 398 glsBufferTestUtil.BufferSubDataWriter = function() { 399 glsBufferTestUtil.BufferWriterBase.call(this); 400 }; 401 402 glsBufferTestUtil.BufferSubDataWriter.prototype = Object.create(glsBufferTestUtil.BufferWriterBase.prototype); 403 glsBufferTestUtil.BufferSubDataWriter.prototype.constructor = glsBufferTestUtil.BufferSubDataWriter; 404 405 /** 406 * @return {number} 407 */ 408 glsBufferTestUtil.BufferSubDataWriter.prototype.getMinSize = function() { return 1; }; 409 410 /** 411 * @return {number} 412 */ 413 glsBufferTestUtil.BufferSubDataWriter.prototype.getAlignment = function() { return 1; }; 414 415 /** 416 * @param {WebGLBuffer} buffer 417 * @param {number} offset 418 * @param {number} numBytes 419 * @param {Uint8Array} bytes 420 */ 421 glsBufferTestUtil.BufferSubDataWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { 422 this.write(buffer, offset, numBytes, bytes, gl.ARRAY_BUFFER); 423 }; 424 425 /** 426 * @param {WebGLBuffer} buffer 427 * @param {number} offset 428 * @param {number} numBytes 429 * @param {Uint8Array} bytes 430 * @param {number} target 431 */ 432 glsBufferTestUtil.BufferSubDataWriter.prototype.write = function(buffer, offset, numBytes, bytes, target) { 433 gl.bindBuffer(target, buffer); 434 gl.bufferSubData(target, offset, bytes); 435 gl.bindBuffer(target, null); 436 }; 437 438 // Buffer verifier system. 439 440 /** 441 * @enum {number} 442 */ 443 glsBufferTestUtil.VerifyType = { 444 AS_VERTEX_ARRAY: 0, 445 AS_INDEX_ARRAY: 1, 446 AS_UNIFORM_BUFFER: 2, 447 AS_PIXEL_UNPACK_BUFFER: 3, 448 BUFFER_READ_MAP: 4 449 }; 450 451 /** 452 * @param {glsBufferTestUtil.VerifyType} verify 453 * @return {string} 454 */ 455 glsBufferTestUtil.getVerifyTypeDescription = function(verify) { 456 /** @type {Array<string>} */ var s_desc = 457 [ 458 'rendering as vertex data', 459 'rendering as index data', 460 'reading in shader as uniform buffer data', 461 'using as PBO and uploading to texture', 462 'reading back using glMapBufferRange()' 463 ]; 464 465 return /** @type {string} */ (deUtil.getArrayElement(s_desc, verify)); 466 }; 467 468 /** 469 * @constructor 470 */ 471 glsBufferTestUtil.BufferVerifierBase = function() {}; 472 473 /** 474 * //Meant to be overriden 475 * @return {number} 476 */ 477 glsBufferTestUtil.BufferVerifierBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); }; 478 479 /** 480 * //Meant to be overriden 481 * @return {number} 482 */ 483 glsBufferTestUtil.BufferVerifierBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); }; 484 485 /** 486 * @param {WebGLBuffer} buffer 487 * @param {Uint8Array} reference 488 * @param {number} offset 489 * @param {number} numBytes 490 * @return {boolean} 491 */ 492 glsBufferTestUtil.BufferVerifierBase.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) { 493 throw new Error('Must be overriden'); 494 }; 495 496 /** 497 * //Meant to be overriden 498 * @param {WebGLBuffer} buffer 499 * @param {Uint8Array} reference 500 * @param {number} offset 501 * @param {number} numBytes 502 * @param {number} targetHint 503 * @return {boolean} 504 */ 505 glsBufferTestUtil.BufferVerifierBase.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) { 506 //In WebGL 2, ELEMENT_ARRAY_BUFFER and TRANSFORM_FEEDBACK_BUFFER cannot be rebound to a different 507 //type of buffer, so, let's copy their data to an ARRAY BUFFER and pass that one instead to be verified. 508 var wasReadBufferCreated = false; 509 try { 510 if (targetHint == gl.ELEMENT_ARRAY_BUFFER || targetHint == gl.TRANSFORM_FEEDBACK_BUFFER) { 511 var readBuffer = new Uint8Array(offset + numBytes); 512 gl.getBufferSubData(targetHint, 0, readBuffer); 513 buffer = gl.createBuffer(); 514 515 wasReadBufferCreated = true; 516 517 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 518 gl.bufferData(gl.ARRAY_BUFFER, readBuffer, gl.STATIC_DRAW); 519 } 520 521 var result = this.verifyNoTarget(buffer, reference, offset, numBytes); 522 523 if (wasReadBufferCreated) 524 gl.deleteBuffer(buffer); 525 526 return result; 527 } catch (err) { 528 if (wasReadBufferCreated) 529 gl.deleteBuffer(buffer); 530 throw err; 531 } 532 }; 533 534 // BufferVerifier 535 536 /** 537 * @constructor 538 * @param {glsBufferTestUtil.VerifyType} verifyType 539 */ 540 glsBufferTestUtil.BufferVerifier = function(verifyType) { 541 /** @type {glsBufferTestUtil.BufferVerifierBase} */ this.m_verifier = null; 542 switch (verifyType) { 543 case glsBufferTestUtil.VerifyType.AS_VERTEX_ARRAY: this.m_verifier = new glsBufferTestUtil.VertexArrayVerifier(); break; 544 case glsBufferTestUtil.VerifyType.AS_INDEX_ARRAY: this.m_verifier = new glsBufferTestUtil.IndexArrayVerifier(); break; 545 default: 546 testFailed('Unsupported verifier type'); 547 } 548 }; 549 550 /** 551 * @return {number} 552 */ 553 glsBufferTestUtil.BufferVerifier.prototype.getMinSize = function() { return this.m_verifier.getMinSize(); }; 554 555 /** 556 * @return {number} 557 */ 558 glsBufferTestUtil.BufferVerifier.prototype.getAlignment = function() { return this.m_verifier.getAlignment(); }; 559 560 /** 561 * @param {WebGLBuffer} buffer 562 * @param {Uint8Array} reference 563 * @param {number} numBytes 564 * @return {boolean} 565 */ 566 glsBufferTestUtil.BufferVerifier.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) { 567 assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); 568 assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); 569 assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); 570 return this.m_verifier.verifyNoTarget(buffer, reference, offset, numBytes); 571 }; 572 573 /** 574 * @param {WebGLBuffer} buffer 575 * @param {Uint8Array} reference 576 * @param {number} offset 577 * @param {number} numBytes 578 * @param {number} targetHint 579 * @return {boolean} 580 */ 581 glsBufferTestUtil.BufferVerifier.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) { 582 assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); 583 assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); 584 assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); 585 return this.m_verifier.verify(buffer, reference, offset, numBytes, targetHint); 586 }; 587 588 // VertexArrayVerifier 589 590 /** 591 * @constructor 592 * @extends {glsBufferTestUtil.BufferVerifierBase} 593 */ 594 glsBufferTestUtil.VertexArrayVerifier = function() { 595 glsBufferTestUtil.BufferVerifierBase.call(this); 596 /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null; 597 this.m_posLoc = 0; 598 this.m_byteVecLoc = 0; 599 /** @type {WebGLVertexArrayObject} */ this.m_vao = null; 600 601 /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl); 602 603 assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'Unsupported GLSL version', false, true); 604 605 this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources( 606 gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + 607 'in highp vec2 a_position;\n' + 608 'in mediump vec3 a_byteVec;\n' + 609 'out mediump vec3 v_byteVec;\n' + 610 'void main (void)\n' + 611 '{\n' + 612 ' gl_Position = vec4(a_position, 0.0, 1.0);\n' + 613 ' v_byteVec = a_byteVec;\n' + 614 '}\n', 615 616 gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + 617 'in mediump vec3 v_byteVec;\n' + 618 'layout(location = 0) out mediump vec4 o_color;\n' + 619 'void main (void)\n' + 620 '{\n' + 621 ' o_color = vec4(v_byteVec, 1.0);\n' + 622 '}\n' 623 )); 624 625 if (!this.m_program.isOk()) { 626 testFailed('Compile failed'); 627 } 628 629 this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position'); 630 this.m_byteVecLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_byteVec'); 631 632 this.m_vao = gl.createVertexArray(); 633 this.m_positionBuf = gl.createBuffer(); 634 this.m_indexBuf = gl.createBuffer(); 635 }; 636 637 glsBufferTestUtil.VertexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype); 638 glsBufferTestUtil.VertexArrayVerifier.prototype.constructor = glsBufferTestUtil.VertexArrayVerifier; 639 640 /** 641 * @return {number} 642 */ 643 glsBufferTestUtil.VertexArrayVerifier.prototype.getMinSize = function() { return 3 * 4; }; 644 645 /** 646 * @return {number} 647 */ 648 glsBufferTestUtil.VertexArrayVerifier.prototype.getAlignment = function() { return 1; }; 649 650 /** 651 * deinit 652 */ 653 glsBufferTestUtil.VertexArrayVerifier.prototype.deinit = function() { 654 if (this.m_vao) gl.deleteVertexArray(this.m_vao); 655 if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf); 656 if (this.m_indexBuf) gl.deleteBuffer(this.m_indexBuf); 657 }; 658 659 /** 660 * @param {number} gridSizeX 661 * @param {number} gridSizeY 662 * @return {Array<number>} 663 */ 664 glsBufferTestUtil.computePositions = function(gridSizeX, gridSizeY) { 665 var positions = []; 666 667 for (var y = 0; y < gridSizeY; y++) 668 for (var x = 0; x < gridSizeX; x++) { 669 /** @type {number} */ var sx0 = (x + 0) / gridSizeX; 670 /** @type {number} */ var sy0 = (y + 0) / gridSizeY; 671 /** @type {number} */ var sx1 = (x + 1) / gridSizeX; 672 /** @type {number} */ var sy1 = (y + 1) / gridSizeY; 673 /** @type {number} */ var fx0 = 2.0 * sx0 - 1.0; 674 /** @type {number} */ var fy0 = 2.0 * sy0 - 1.0; 675 /** @type {number} */ var fx1 = 2.0 * sx1 - 1.0; 676 /** @type {number} */ var fy1 = 2.0 * sy1 - 1.0; 677 /** @type {number} */ var baseNdx = (y * gridSizeX + x) * 8; 678 679 positions[baseNdx + 0] = fx0; positions[baseNdx + 1] = fy0; 680 positions[baseNdx + 2] = fx0; positions[baseNdx + 3] = fy1; 681 positions[baseNdx + 4] = fx1; positions[baseNdx + 5] = fy0; 682 positions[baseNdx + 6] = fx1; positions[baseNdx + 7] = fy1; 683 } 684 685 return positions; 686 }; 687 688 /** 689 * @param {number} gridSizeX 690 * @param {number} gridSizeY 691 * @return {Uint16Array} 692 */ 693 glsBufferTestUtil.computeIndices = function(gridSizeX, gridSizeY) { 694 var indices = new Uint16Array(3 * 2 * gridSizeX * gridSizeY); 695 696 for (var quadNdx = 0; quadNdx < gridSizeX * gridSizeY; quadNdx++) { 697 /** @type {number} */ var v00 = quadNdx * 4 + 0; 698 /** @type {number} */ var v01 = quadNdx * 4 + 1; 699 /** @type {number} */ var v10 = quadNdx * 4 + 2; 700 /** @type {number} */ var v11 = quadNdx * 4 + 3; 701 702 assertMsgOptions(v11 < (1 << 16), 'Vertex index value won\'t fit into a 16-bit number', false, true); 703 704 indices[quadNdx * 6 + 0] = v10; 705 indices[quadNdx * 6 + 1] = v00; 706 indices[quadNdx * 6 + 2] = v01; 707 708 indices[quadNdx * 6 + 3] = v10; 709 indices[quadNdx * 6 + 4] = v01; 710 indices[quadNdx * 6 + 5] = v11; 711 } 712 713 return indices; 714 }; 715 716 /** 717 * @param {Uint8Array} ptr 718 * @param {number} vtxNdx 719 * @return {Array<number>} 720 */ 721 glsBufferTestUtil.fetchVtxColor = function(ptr, vtxNdx) { 722 return new tcuRGBA.RGBA([ 723 ptr[vtxNdx * 3 + 0], 724 ptr[vtxNdx * 3 + 1], 725 ptr[vtxNdx * 3 + 2], 726 255]).toVec(); 727 }; 728 729 /** 730 * @param {tcuSurface.Surface} dst 731 * @param {number} numQuads 732 * @param {number} rowLength 733 * @param {Uint8Array} inPtr 734 */ 735 glsBufferTestUtil.renderQuadGridReference = function(dst, numQuads, rowLength, inPtr) { 736 dst.setSize(rowLength * glsBufferTestUtil.VERIFY_QUAD_SIZE, (Math.floor(numQuads / rowLength) + (numQuads % rowLength != 0 ? 1 : 0)) * glsBufferTestUtil.VERIFY_QUAD_SIZE); 737 738 /** @type {tcuTexture.PixelBufferAccess} */ var dstAccess = dst.getAccess(); 739 dstAccess.clear([0, 0, 0, 1.0]); 740 741 for (var quadNdx = 0; quadNdx < numQuads; quadNdx++) { 742 /** @type {number} */ var x0 = (quadNdx % rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE; 743 /** @type {number} */ var y0 = Math.floor(quadNdx / rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE; 744 /** @type {Array<number>} */ var v00 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 0); 745 /** @type {Array<number>} */ var v10 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 1); 746 /** @type {Array<number>} */ var v01 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 2); 747 /** @type {Array<number>} */ var v11 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 3); 748 749 for (var y = 0; y < glsBufferTestUtil.VERIFY_QUAD_SIZE; y++) 750 for (var x = 0; x < glsBufferTestUtil.VERIFY_QUAD_SIZE; x++) { 751 /** @type {number} */ var fx = (x + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE; 752 /** @type {number} */ var fy = (y + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE; 753 754 /** @type {boolean} */ var tri = fx + fy <= 1.0; 755 /** @type {number} */ var tx = tri ? fx : (1.0 - fx); 756 /** @type {number} */ var ty = tri ? fy : (1.0 - fy); 757 /** @type {Array<number>} */ var t0 = tri ? v00 : v11; 758 /** @type {Array<number>} */ var t1 = tri ? v01 : v10; 759 /** @type {Array<number>} */ var t2 = tri ? v10 : v01; 760 /** @type {Array<number>} */ var color = deMath.add( 761 deMath.add(t0, deMath.scale(deMath.subtract(t1, t0), tx)), 762 deMath.scale(deMath.subtract(t2, t0), ty) 763 ); 764 765 dstAccess.setPixel(color, x0 + x, y0 + y); 766 } 767 } 768 }; 769 770 /** 771 * @param {WebGLBuffer} buffer 772 * @param {Uint8Array} refPtr 773 * @param {number} offset 774 * @param {number} numBytes 775 * @return {boolean} 776 */ 777 glsBufferTestUtil.VertexArrayVerifier.prototype.verifyNoTarget = function(buffer, refPtr, offset, numBytes) { 778 var numBytesInVtx = 3; 779 var numBytesInQuad = numBytesInVtx * 4; 780 var maxQuadsX = Math.min(128, Math.floor(gl.drawingBufferWidth / glsBufferTestUtil.VERIFY_QUAD_SIZE)); 781 var maxQuadsY = Math.min(128, Math.floor(gl.drawingBufferHeight / glsBufferTestUtil.VERIFY_QUAD_SIZE)); 782 var maxQuadsPerBatch = maxQuadsX * maxQuadsY; 783 var numVerified = 0; 784 var program = this.m_program.getProgram(); 785 /** @type {tcuRGBA.RGBA} */ var threshold = /*TODO: renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);*/ new tcuRGBA.RGBA([3, 3, 3, 3]); 786 var isOk = true; 787 788 /** @type {Array<number>} */ var positions = []; 789 /** @type {Uint16Array} */var indices; 790 791 /** @type {tcuSurface.Surface} */ var rendered = new tcuSurface.Surface(); 792 /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(); 793 794 // Can't render full quad with smaller buffers. 795 assertMsgOptions(numBytes >= numBytesInQuad, 'Number of bytes must be bigger than number of bytes per quad', false, true); 796 797 positions = glsBufferTestUtil.computePositions(maxQuadsX, maxQuadsY); 798 indices = glsBufferTestUtil.computeIndices(maxQuadsX, maxQuadsY); 799 800 // Reset buffer bindings. 801 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); 802 803 // Setup rendering state. 804 gl.viewport(0, 0, maxQuadsX * glsBufferTestUtil.VERIFY_QUAD_SIZE, maxQuadsY * glsBufferTestUtil.VERIFY_QUAD_SIZE); 805 gl.clearColor(0.0, 0.0, 0.0, 1.0); 806 gl.useProgram(program); 807 gl.bindVertexArray(this.m_vao); 808 809 // Upload positions 810 gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); 811 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); 812 gl.enableVertexAttribArray(this.m_posLoc); 813 gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); 814 815 // Upload indices 816 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_indexBuf); 817 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); 818 819 gl.enableVertexAttribArray(this.m_byteVecLoc); 820 821 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 822 823 while (numVerified < numBytes) { 824 /** @type {number} */ var numRemaining = numBytes - numVerified; 825 var isLeftoverBatch = numRemaining < numBytesInQuad; 826 /** @type {number} */ var numBytesToVerify = isLeftoverBatch ? numBytesInQuad : Math.min(maxQuadsPerBatch * numBytesInQuad, numRemaining - numRemaining % numBytesInQuad); 827 /** @type {number} */ var curOffset = isLeftoverBatch ? (numBytes - numBytesInQuad) : numVerified; 828 /** @type {number} */ var numQuads = Math.floor(numBytesToVerify / numBytesInQuad); 829 /** @type {number} */ var numCols = Math.min(maxQuadsX, numQuads); 830 /** @type {number} */ var numRows = Math.floor(numQuads / maxQuadsX) + (numQuads % maxQuadsX != 0 ? 1 : 0); 831 /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1); 832 833 assertMsgOptions(numBytesToVerify > 0 && numBytesToVerify % numBytesInQuad == 0, 'Bytes to verify must be greater than zero and must be a multiple of the bytes per quad', false, true); 834 assertMsgOptions(deMath.deInBounds32(curOffset, 0, numBytes), 'Offset out of bounds', false, true); 835 assertMsgOptions(deMath.deInRange32(curOffset + numBytesToVerify, curOffset, numBytes), 'Range of bytes to verify outside of bounds', false, true); 836 837 // Render batch. 838 gl.clear(gl.COLOR_BUFFER_BIT); 839 gl.vertexAttribPointer(this.m_byteVecLoc, 3, gl.UNSIGNED_BYTE, true, 0, offset + curOffset); 840 gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_SHORT, 0); 841 842 glsBufferTestUtil.renderQuadGridReference(reference, numQuads, numCols, refPtr.subarray(offset + curOffset)); 843 844 rendered.setSize(numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE); 845 rendered.readViewport(gl, [0, 0, numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE]); 846 847 if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, reference, rendered, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) { 848 isOk = false; 849 break; 850 } 851 852 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 853 } 854 855 gl.bindVertexArray(null); 856 857 return isOk; 858 }; 859 860 // IndexArrayVerifier 861 862 /** 863 * @constructor 864 * @extends {glsBufferTestUtil.BufferVerifierBase} 865 */ 866 glsBufferTestUtil.IndexArrayVerifier = function() { 867 glsBufferTestUtil.BufferVerifierBase.call(this); 868 869 this.m_program = null; 870 this.m_posLoc = 0; 871 this.m_colorLoc = 0; 872 873 /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.GLSLVersion.V300_ES; 874 875 assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'GLSL version not supported', false, true); 876 877 this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources( 878 gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + 879 'in highp vec2 a_position;\n' + 880 'in mediump vec3 a_color;\n' + 881 'out mediump vec3 v_color;\n' + 882 'void main (void)\n' + 883 '{\n' + 884 ' gl_Position = vec4(a_position, 0.0, 1.0);\n' + 885 ' v_color = a_color;\n' + 886 '}\n', 887 888 gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + 889 'in mediump vec3 v_color;\n' + 890 'layout(location = 0) out mediump vec4 o_color;\n' + 891 'void main (void)\n' + 892 '{\n' + 893 ' o_color = vec4(v_color, 1.0);\n' + 894 '}\n')); 895 896 if (!this.m_program.isOk()) { 897 testFailed('Compile failed'); 898 } 899 900 this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position'); 901 this.m_colorLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_color'); 902 903 this.m_vao = gl.createVertexArray(); 904 this.m_positionBuf = gl.createBuffer(); 905 this.m_colorBuf = gl.createBuffer(); 906 }; 907 908 glsBufferTestUtil.IndexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype); 909 glsBufferTestUtil.IndexArrayVerifier.prototype.constructor = glsBufferTestUtil.IndexArrayVerifier; 910 911 /** 912 * deinit 913 */ 914 glsBufferTestUtil.IndexArrayVerifier.prototype.deinit = function() { 915 if (this.m_vao) gl.deleteVertexArray(this.m_vao); 916 if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf); 917 if (this.m_colorBuf) gl.deleteBuffer(this.m_colorBuf); 918 }; 919 920 /** 921 * @return {Array<number>} 922 */ 923 glsBufferTestUtil.computeIndexVerifierPositions = function() { 924 var numPosX = 16; 925 var numPosY = 16; 926 927 var dst = []; 928 929 for (var y = 0; y < numPosY; y++) { 930 for (var x = 0; x < numPosX; x++) { 931 var xf = x / (numPosX - 1); 932 var yf = y / (numPosY - 1); 933 934 var offset = 2 * (y * numPosX + x); 935 dst[offset] = 2.0 * xf - 1.0; 936 dst[offset + 1] = 2.0 * yf - 1.0; 937 } 938 } 939 940 return dst; 941 }; 942 943 /** 944 * @return {Array<number>} 945 */ 946 glsBufferTestUtil.computeIndexVerifierColors = function() { 947 /** @type {number} */ var numColors = 256; 948 /** @type {number} */ var minVal = 0.1; 949 /** @type {number} */ var maxVal = 0.5; 950 var rnd = new deRandom.Random(0xabc231); 951 952 var dst = []; 953 954 for (var i = 0; i < numColors; ++i) { 955 dst[3 * i] = rnd.getFloat(minVal, maxVal); 956 dst[3 * i + 1] = rnd.getFloat(minVal, maxVal); 957 dst[3 * i + 2] = rnd.getFloat(minVal, maxVal); 958 } 959 960 return dst; 961 }; 962 963 /** 964 * @param {Array<number>} dst 965 * @param {Array<number>} src 966 * @param {Uint8Array} indices 967 * @param {number} numIndices 968 */ 969 glsBufferTestUtil.execVertexFetch = function(dst, src, indices, numIndices) { 970 for (var i = 0; i < numIndices; ++i) 971 dst[i] = src[indices[i]]; 972 }; 973 974 /** 975 * @param {WebGLBuffer} buffer 976 * @param {Uint8Array} refPtr 977 * @param {number} offset 978 * @param {number} numBytes 979 * @return {boolean} 980 */ 981 glsBufferTestUtil.IndexArrayVerifier.prototype.verify = function(buffer, refPtr, offset, numBytes) { 982 var viewportW = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, gl.drawingBufferWidth); 983 var viewportH = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, gl.drawingBufferHeight); 984 var minBytesPerBatch = 2; 985 /** @type {tcuRGBA.RGBA} */ var threshold = new tcuRGBA.RGBA([0, 0, 0, 0]); 986 987 var positions = []; 988 var colors = []; 989 990 var fetchedPos = []; 991 var fetchedColor = []; 992 993 /** @type {tcuSurface.Surface} */ var indexBufferImg = new tcuSurface.Surface(viewportW, viewportH); 994 /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(viewportW, viewportH); 995 996 var numVerified = 0; 997 var isOk = true; 998 999 positions = glsBufferTestUtil.computeIndexVerifierPositions(); 1000 colors = glsBufferTestUtil.computeIndexVerifierColors(); 1001 1002 // Reset buffer bindings. 1003 gl.bindVertexArray(this.m_vao); 1004 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); 1005 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); 1006 1007 // Setup rendering state. 1008 gl.viewport(0, 0, viewportW, viewportH); 1009 gl.clearColor(0.0, 0.0, 0.0, 1.0); 1010 gl.useProgram(this.m_program.getProgram()); 1011 gl.enableVertexAttribArray(this.m_posLoc); 1012 gl.enableVertexAttribArray(this.m_colorLoc); 1013 gl.enable(gl.BLEND); 1014 gl.blendFunc(gl.ONE, gl.ONE); 1015 gl.blendEquation(gl.FUNC_ADD); 1016 1017 while (numVerified < numBytes) { 1018 var numRemaining = numBytes - numVerified; 1019 var isLeftoverBatch = numRemaining < minBytesPerBatch; 1020 var numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : Math.min(glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW + 1, numRemaining); 1021 var curOffset = isLeftoverBatch ? (numBytes - minBytesPerBatch) : numVerified; 1022 /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1); 1023 1024 // Step 1: Render using index buffer. 1025 gl.clear(gl.COLOR_BUFFER_BIT); 1026 1027 gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); 1028 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STREAM_DRAW); 1029 gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); 1030 1031 gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf); 1032 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STREAM_DRAW); 1033 gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0); 1034 1035 gl.drawElements(gl.LINE_STRIP, numBytesToVerify, gl.UNSIGNED_BYTE, offset + curOffset); 1036 indexBufferImg.readViewport(gl); 1037 1038 // Step 2: Do manual fetch and render without index buffer. 1039 glsBufferTestUtil.execVertexFetch(fetchedPos, positions, refPtr.subarray(offset + curOffset), numBytesToVerify); 1040 glsBufferTestUtil.execVertexFetch(fetchedColor, colors, refPtr.subarray(offset + curOffset), numBytesToVerify); 1041 1042 gl.clear(gl.COLOR_BUFFER_BIT); 1043 1044 gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); 1045 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedPos), gl.STREAM_DRAW); 1046 gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); 1047 1048 gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf); 1049 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedColor), gl.STREAM_DRAW); 1050 gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0); 1051 1052 gl.drawArrays(gl.LINE_STRIP, 0, numBytesToVerify); 1053 referenceImg.readViewport(gl, [0, 0, viewportW, viewportH]); 1054 1055 if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, referenceImg, indexBufferImg, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) { 1056 isOk = false; 1057 break; 1058 } 1059 1060 numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; 1061 } 1062 1063 gl.bindVertexArray(null); 1064 1065 return isOk; 1066 }; 1067 1068 });