diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js | 1068 |
1 files changed, 1068 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js new file mode 100644 index 0000000000..446782b4b6 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js @@ -0,0 +1,1068 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES Utilities + * ------------------------------------------------ + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; +goog.provide('modules.shared.glsBufferTestUtil'); +goog.require('framework.common.tcuImageCompare'); +goog.require('framework.common.tcuRGBA'); +goog.require('framework.common.tcuSurface'); +goog.require('framework.common.tcuTestCase'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.delibs.debase.deRandom'); +goog.require('framework.delibs.debase.deString'); +goog.require('framework.delibs.debase.deUtil'); +goog.require('framework.opengl.gluDrawUtil'); +goog.require('framework.opengl.gluShaderProgram'); +goog.require('framework.opengl.gluShaderUtil'); + +goog.scope(function() { + + var glsBufferTestUtil = modules.shared.glsBufferTestUtil; + var tcuImageCompare = framework.common.tcuImageCompare; + var tcuRGBA = framework.common.tcuRGBA; + var tcuSurface = framework.common.tcuSurface; + var tcuTestCase = framework.common.tcuTestCase; + var tcuTexture = framework.common.tcuTexture; + var gluShaderProgram = framework.opengl.gluShaderProgram; + var gluShaderUtil = framework.opengl.gluShaderUtil; + var gluDrawUtil = framework.opengl.gluDrawUtil; + var deUtil = framework.delibs.debase.deUtil; + var deMath = framework.delibs.debase.deMath; + var deRandom = framework.delibs.debase.deRandom; + var deString = framework.delibs.debase.deString; + + glsBufferTestUtil.VERIFY_QUAD_SIZE = 8; //!< Quad size in VertexArrayVerifier + glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW = 128; //!< Maximum number of lines per one draw in IndexArrayVerifier + glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128; + glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128; + + // Helper functions. + + /** + * @param {Uint8Array} ptr + * @param {number} numBytes + * @param {number} seed + */ + glsBufferTestUtil.fillWithRandomBytes = function(ptr, numBytes, seed) { + var rnd = new deRandom.Random(seed); + for (var left = numBytes; left > 0; left--) + ptr[left - 1] = rnd.getInt(); + }; + + /** + * @param {Uint8Array} resPtr + * @param {Uint8Array} refPtr + * @param {number} numBytes + * @return {boolean} + */ + glsBufferTestUtil.compareByteArrays = function(resPtr, refPtr, numBytes) { + var isOk = true; + var maxSpanLen = 8; + var maxDiffSpans = 4; + var numDiffSpans = 0; + var diffSpanStart = -1; + var ndx = 0; + + var log = 'Verification result: '; + + for (; ndx < numBytes; ndx++) { + if (resPtr[ndx] != refPtr[ndx]) { + if (diffSpanStart < 0) + diffSpanStart = ndx; + + isOk = false; + } else if (diffSpanStart >= 0) { + if (numDiffSpans < maxDiffSpans) { + var len = ndx - diffSpanStart; + var printLen = Math.min(len, maxSpanLen); + + log += len + ' byte difference at offset ' + diffSpanStart + '\n' + + ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) + + ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen); + } else + log += '(output too long, truncated)'; + + numDiffSpans += 1; + diffSpanStart = -1; + } + } + + if (diffSpanStart >= 0) { + if (numDiffSpans < maxDiffSpans) { + var len = ndx - diffSpanStart; + var printLen = Math.min(len, maxSpanLen); + + log += len + ' byte difference at offset ' + diffSpanStart + '\n' + + ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) + + ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen); + } else + log += '(output too long, truncated)'; + } + + log += (isOk ? 'Verification passed.' : 'Verification FAILED!'); + + bufferedLogToConsole(log); + + return isOk; + }; + + /** + * @param {number} target + * @return {string} + */ + glsBufferTestUtil.getBufferTargetName = function(target) { + switch (target) { + case gl.ARRAY_BUFFER: return 'array'; + case gl.COPY_READ_BUFFER: return 'copy_read'; + case gl.COPY_WRITE_BUFFER: return 'copy_write'; + case gl.ELEMENT_ARRAY_BUFFER: return 'element_array'; + case gl.PIXEL_PACK_BUFFER: return 'pixel_pack'; + case gl.PIXEL_UNPACK_BUFFER: return 'pixel_unpack'; + //case gl.TEXTURE_BUFFER: return "texture"; //TODO: Unimplemented in WebGL 2. Remove? + case gl.TRANSFORM_FEEDBACK_BUFFER: return 'transform_feedback'; + case gl.UNIFORM_BUFFER: return 'uniform'; + default: + throw new Error('Invalid buffer target'); + } + }; + + /** + * @param {number} hint + * @return {string} + */ + glsBufferTestUtil.getUsageHintName = function(hint) { + switch (hint) { + case gl.STREAM_DRAW: return 'stream_draw'; + case gl.STREAM_READ: return 'stream_read'; + case gl.STREAM_COPY: return 'stream_copy'; + case gl.STATIC_DRAW: return 'static_draw'; + case gl.STATIC_READ: return 'static_read'; + case gl.STATIC_COPY: return 'static_copy'; + case gl.DYNAMIC_DRAW: return 'dynamic_draw'; + case gl.DYNAMIC_READ: return 'dynamic_read'; + case gl.DYNAMIC_COPY: return 'dynamic_copy'; + default: + throw new Error('Invalid buffer usage hint'); + } + }; + + // Base class for buffer cases. + // BufferCase + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + glsBufferTestUtil.BufferCase = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + /** @type {Array<WebGLBuffer>} */ this.m_allocatedBuffers = []; + }; + + glsBufferTestUtil.BufferCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + glsBufferTestUtil.BufferCase.prototype.constructor = glsBufferTestUtil.BufferCase; + + /** + * init + */ + glsBufferTestUtil.BufferCase.prototype.init = function() {}; + + /** + * deinit + */ + glsBufferTestUtil.BufferCase.prototype.deinit = function() { + for (var ndx = 0; ndx < this.m_allocatedBuffers.length; ndx++) + this.deleteBuffer(this.m_allocatedBuffers[ndx]); + }; + + /** + * @return {WebGLBuffer} + */ + glsBufferTestUtil.BufferCase.prototype.genBuffer = function() { + var buf = 0; + buf = gl.createBuffer(); + if (buf != 0) { + try { + deUtil.dePushUniqueToArray(this.m_allocatedBuffers, buf); + } + catch (err) { + gl.deleteBuffer(buf); + throw err; + } + } + return buf; + }; + + /** + * @param {WebGLBuffer} buffer + */ + glsBufferTestUtil.BufferCase.prototype.deleteBuffer = function(buffer) { + gl.deleteBuffer(buffer); + this.m_allocatedBuffers.splice(this.m_allocatedBuffers.indexOf(buffer), 1); + }; + + glsBufferTestUtil.BufferCase.prototype.checkError = function() { + /** @type {number} */ var err = gl.getError(); + if (err != gl.NO_ERROR) + throw new TestFailedException('Got ' + WebGLTestUtils.glEnumToString(gl, err)); + }; + + // Reference buffer. + + /** + * @constructor + */ + glsBufferTestUtil.ReferenceBuffer = function() { + /** @type {ArrayBuffer} */ this.m_data; + }; + + /** + * @param {number=} offset + * @return {Uint8Array} + */ + glsBufferTestUtil.ReferenceBuffer.prototype.getPtr = function(offset) { + offset = offset ? offset : 0; return new Uint8Array(this.m_data, offset); + }; + + /** + * @param {number} numBytes + */ + glsBufferTestUtil.ReferenceBuffer.prototype.setSize = function(numBytes) { + this.m_data = new ArrayBuffer(numBytes); + }; + + /** + * @param {number} numBytes + * @param {Uint8Array} bytes + */ + glsBufferTestUtil.ReferenceBuffer.prototype.setData = function(numBytes, bytes) { + this.setSize(numBytes); + var dst = new Uint8Array(this.m_data); + dst.set(bytes.subarray(numBytes)); + }; + + /** + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + */ + glsBufferTestUtil.ReferenceBuffer.prototype.setSubData = function(offset, numBytes, bytes) { + assertMsgOptions(deMath.deInBounds32(offset, 0, this.m_data.byteLength) && deMath.deInRange32(offset + numBytes, offset, this.m_data.byteLength), + 'Parameters not in buffer bounds or range', false, true); + var dst = new Uint8Array(this.m_data, offset); + dst.set(bytes.subarray(offset, offset + numBytes)); + }; + + // Buffer writer system. + + /** + * @enum {number} + */ + glsBufferTestUtil.WriteType = { + BUFFER_SUB_DATA: 0, + BUFFER_WRITE_MAP: 1, + TRANSFORM_FEEDBACK: 2, + PIXEL_PACK: 3 + }; + + /** + * @param {glsBufferTestUtil.WriteType} write + * @return {string} + */ + glsBufferTestUtil.getWriteTypeDescription = function(write) { + /** @type {Array<string>} */ var s_desc = [ + 'gl.bufferSubData()', + 'gl.mapBufferRange()', + 'transform feedback', + 'gl.readPixels() into PBO binding' + ]; + return /** @type {string} */ (deUtil.getArrayElement(s_desc, write)); + }; + + // BufferWriterBase + + /** + * @constructor + */ + glsBufferTestUtil.BufferWriterBase = function() {}; + + /** + * //Meant to be overriden + * @return {number} + */ + glsBufferTestUtil.BufferWriterBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); }; + + /** + * //Meant to be overriden + * @return {number} + */ + glsBufferTestUtil.BufferWriterBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); }; + + /** + * //Meant to be overriden + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + */ + glsBufferTestUtil.BufferWriterBase.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { throw new Error('Must be overriden'); }; + + /** + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + * @param {number} targetHint + */ + glsBufferTestUtil.BufferWriterBase.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) { + this.writeNoTarget(buffer, offset, numBytes, bytes); + }; + + // BufferWriter + + /** + * @constructor + * @param {glsBufferTestUtil.WriteType} writeType + */ + glsBufferTestUtil.BufferWriter = function(writeType) { + /** @type {glsBufferTestUtil.BufferWriterBase} */ this.m_writer = null; + switch (writeType) { + case glsBufferTestUtil.WriteType.BUFFER_SUB_DATA: this.m_writer = new glsBufferTestUtil.BufferSubDataWriter(); break; + default: + testFailed('Unsupported writer'); + } + }; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferWriter.prototype.getMinSize = function() {return this.m_writer.getMinSize();}; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferWriter.prototype.getAlignment = function() {return this.m_writer.getAlignment();}; + + /** + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + */ + glsBufferTestUtil.BufferWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { + assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); + assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); + assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); + return this.m_writer.writeNoTarget(buffer, offset, numBytes, bytes); + }; + + /** + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + * @param {number} targetHint + */ + glsBufferTestUtil.BufferWriter.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) { + assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); + assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); + assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); + return this.m_writer.write(buffer, offset, numBytes, bytes, targetHint); + }; + + // BufferSubDataWriter + + /** + * @constructor + * @extends {glsBufferTestUtil.BufferWriterBase} + */ + glsBufferTestUtil.BufferSubDataWriter = function() { + glsBufferTestUtil.BufferWriterBase.call(this); + }; + + glsBufferTestUtil.BufferSubDataWriter.prototype = Object.create(glsBufferTestUtil.BufferWriterBase.prototype); + glsBufferTestUtil.BufferSubDataWriter.prototype.constructor = glsBufferTestUtil.BufferSubDataWriter; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferSubDataWriter.prototype.getMinSize = function() { return 1; }; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferSubDataWriter.prototype.getAlignment = function() { return 1; }; + + /** + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + */ + glsBufferTestUtil.BufferSubDataWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { + this.write(buffer, offset, numBytes, bytes, gl.ARRAY_BUFFER); + }; + + /** + * @param {WebGLBuffer} buffer + * @param {number} offset + * @param {number} numBytes + * @param {Uint8Array} bytes + * @param {number} target + */ + glsBufferTestUtil.BufferSubDataWriter.prototype.write = function(buffer, offset, numBytes, bytes, target) { + gl.bindBuffer(target, buffer); + gl.bufferSubData(target, offset, bytes); + gl.bindBuffer(target, null); + }; + + // Buffer verifier system. + + /** + * @enum {number} + */ + glsBufferTestUtil.VerifyType = { + AS_VERTEX_ARRAY: 0, + AS_INDEX_ARRAY: 1, + AS_UNIFORM_BUFFER: 2, + AS_PIXEL_UNPACK_BUFFER: 3, + BUFFER_READ_MAP: 4 + }; + + /** + * @param {glsBufferTestUtil.VerifyType} verify + * @return {string} + */ + glsBufferTestUtil.getVerifyTypeDescription = function(verify) { + /** @type {Array<string>} */ var s_desc = + [ + 'rendering as vertex data', + 'rendering as index data', + 'reading in shader as uniform buffer data', + 'using as PBO and uploading to texture', + 'reading back using glMapBufferRange()' + ]; + + return /** @type {string} */ (deUtil.getArrayElement(s_desc, verify)); + }; + + /** + * @constructor + */ + glsBufferTestUtil.BufferVerifierBase = function() {}; + + /** + * //Meant to be overriden + * @return {number} + */ + glsBufferTestUtil.BufferVerifierBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); }; + + /** + * //Meant to be overriden + * @return {number} + */ + glsBufferTestUtil.BufferVerifierBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); }; + + /** + * @param {WebGLBuffer} buffer + * @param {Uint8Array} reference + * @param {number} offset + * @param {number} numBytes + * @return {boolean} + */ + glsBufferTestUtil.BufferVerifierBase.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) { + throw new Error('Must be overriden'); + }; + + /** + * //Meant to be overriden + * @param {WebGLBuffer} buffer + * @param {Uint8Array} reference + * @param {number} offset + * @param {number} numBytes + * @param {number} targetHint + * @return {boolean} + */ + glsBufferTestUtil.BufferVerifierBase.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) { + //In WebGL 2, ELEMENT_ARRAY_BUFFER and TRANSFORM_FEEDBACK_BUFFER cannot be rebound to a different + //type of buffer, so, let's copy their data to an ARRAY BUFFER and pass that one instead to be verified. + var wasReadBufferCreated = false; + try { + if (targetHint == gl.ELEMENT_ARRAY_BUFFER || targetHint == gl.TRANSFORM_FEEDBACK_BUFFER) { + var readBuffer = new Uint8Array(offset + numBytes); + gl.getBufferSubData(targetHint, 0, readBuffer); + buffer = gl.createBuffer(); + + wasReadBufferCreated = true; + + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, readBuffer, gl.STATIC_DRAW); + } + + var result = this.verifyNoTarget(buffer, reference, offset, numBytes); + + if (wasReadBufferCreated) + gl.deleteBuffer(buffer); + + return result; + } catch (err) { + if (wasReadBufferCreated) + gl.deleteBuffer(buffer); + throw err; + } + }; + + // BufferVerifier + + /** + * @constructor + * @param {glsBufferTestUtil.VerifyType} verifyType + */ + glsBufferTestUtil.BufferVerifier = function(verifyType) { + /** @type {glsBufferTestUtil.BufferVerifierBase} */ this.m_verifier = null; + switch (verifyType) { + case glsBufferTestUtil.VerifyType.AS_VERTEX_ARRAY: this.m_verifier = new glsBufferTestUtil.VertexArrayVerifier(); break; + case glsBufferTestUtil.VerifyType.AS_INDEX_ARRAY: this.m_verifier = new glsBufferTestUtil.IndexArrayVerifier(); break; + default: + testFailed('Unsupported verifier type'); + } + }; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferVerifier.prototype.getMinSize = function() { return this.m_verifier.getMinSize(); }; + + /** + * @return {number} + */ + glsBufferTestUtil.BufferVerifier.prototype.getAlignment = function() { return this.m_verifier.getAlignment(); }; + + /** + * @param {WebGLBuffer} buffer + * @param {Uint8Array} reference + * @param {number} numBytes + * @return {boolean} + */ + glsBufferTestUtil.BufferVerifier.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) { + assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); + assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); + assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); + return this.m_verifier.verifyNoTarget(buffer, reference, offset, numBytes); + }; + + /** + * @param {WebGLBuffer} buffer + * @param {Uint8Array} reference + * @param {number} offset + * @param {number} numBytes + * @param {number} targetHint + * @return {boolean} + */ + glsBufferTestUtil.BufferVerifier.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) { + assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true); + assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true); + assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true); + return this.m_verifier.verify(buffer, reference, offset, numBytes, targetHint); + }; + + // VertexArrayVerifier + + /** + * @constructor + * @extends {glsBufferTestUtil.BufferVerifierBase} + */ + glsBufferTestUtil.VertexArrayVerifier = function() { + glsBufferTestUtil.BufferVerifierBase.call(this); + /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null; + this.m_posLoc = 0; + this.m_byteVecLoc = 0; + /** @type {WebGLVertexArrayObject} */ this.m_vao = null; + + /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl); + + assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'Unsupported GLSL version', false, true); + + this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources( + gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + + 'in highp vec2 a_position;\n' + + 'in mediump vec3 a_byteVec;\n' + + 'out mediump vec3 v_byteVec;\n' + + 'void main (void)\n' + + '{\n' + + ' gl_Position = vec4(a_position, 0.0, 1.0);\n' + + ' v_byteVec = a_byteVec;\n' + + '}\n', + + gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + + 'in mediump vec3 v_byteVec;\n' + + 'layout(location = 0) out mediump vec4 o_color;\n' + + 'void main (void)\n' + + '{\n' + + ' o_color = vec4(v_byteVec, 1.0);\n' + + '}\n' + )); + + if (!this.m_program.isOk()) { + testFailed('Compile failed'); + } + + this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position'); + this.m_byteVecLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_byteVec'); + + this.m_vao = gl.createVertexArray(); + this.m_positionBuf = gl.createBuffer(); + this.m_indexBuf = gl.createBuffer(); + }; + + glsBufferTestUtil.VertexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype); + glsBufferTestUtil.VertexArrayVerifier.prototype.constructor = glsBufferTestUtil.VertexArrayVerifier; + + /** + * @return {number} + */ + glsBufferTestUtil.VertexArrayVerifier.prototype.getMinSize = function() { return 3 * 4; }; + + /** + * @return {number} + */ + glsBufferTestUtil.VertexArrayVerifier.prototype.getAlignment = function() { return 1; }; + + /** + * deinit + */ + glsBufferTestUtil.VertexArrayVerifier.prototype.deinit = function() { + if (this.m_vao) gl.deleteVertexArray(this.m_vao); + if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf); + if (this.m_indexBuf) gl.deleteBuffer(this.m_indexBuf); + }; + + /** + * @param {number} gridSizeX + * @param {number} gridSizeY + * @return {Array<number>} + */ + glsBufferTestUtil.computePositions = function(gridSizeX, gridSizeY) { + var positions = []; + + for (var y = 0; y < gridSizeY; y++) + for (var x = 0; x < gridSizeX; x++) { + /** @type {number} */ var sx0 = (x + 0) / gridSizeX; + /** @type {number} */ var sy0 = (y + 0) / gridSizeY; + /** @type {number} */ var sx1 = (x + 1) / gridSizeX; + /** @type {number} */ var sy1 = (y + 1) / gridSizeY; + /** @type {number} */ var fx0 = 2.0 * sx0 - 1.0; + /** @type {number} */ var fy0 = 2.0 * sy0 - 1.0; + /** @type {number} */ var fx1 = 2.0 * sx1 - 1.0; + /** @type {number} */ var fy1 = 2.0 * sy1 - 1.0; + /** @type {number} */ var baseNdx = (y * gridSizeX + x) * 8; + + positions[baseNdx + 0] = fx0; positions[baseNdx + 1] = fy0; + positions[baseNdx + 2] = fx0; positions[baseNdx + 3] = fy1; + positions[baseNdx + 4] = fx1; positions[baseNdx + 5] = fy0; + positions[baseNdx + 6] = fx1; positions[baseNdx + 7] = fy1; + } + + return positions; + }; + + /** + * @param {number} gridSizeX + * @param {number} gridSizeY + * @return {Uint16Array} + */ + glsBufferTestUtil.computeIndices = function(gridSizeX, gridSizeY) { + var indices = new Uint16Array(3 * 2 * gridSizeX * gridSizeY); + + for (var quadNdx = 0; quadNdx < gridSizeX * gridSizeY; quadNdx++) { + /** @type {number} */ var v00 = quadNdx * 4 + 0; + /** @type {number} */ var v01 = quadNdx * 4 + 1; + /** @type {number} */ var v10 = quadNdx * 4 + 2; + /** @type {number} */ var v11 = quadNdx * 4 + 3; + + assertMsgOptions(v11 < (1 << 16), 'Vertex index value won\'t fit into a 16-bit number', false, true); + + indices[quadNdx * 6 + 0] = v10; + indices[quadNdx * 6 + 1] = v00; + indices[quadNdx * 6 + 2] = v01; + + indices[quadNdx * 6 + 3] = v10; + indices[quadNdx * 6 + 4] = v01; + indices[quadNdx * 6 + 5] = v11; + } + + return indices; + }; + + /** + * @param {Uint8Array} ptr + * @param {number} vtxNdx + * @return {Array<number>} + */ + glsBufferTestUtil.fetchVtxColor = function(ptr, vtxNdx) { + return new tcuRGBA.RGBA([ + ptr[vtxNdx * 3 + 0], + ptr[vtxNdx * 3 + 1], + ptr[vtxNdx * 3 + 2], + 255]).toVec(); + }; + + /** + * @param {tcuSurface.Surface} dst + * @param {number} numQuads + * @param {number} rowLength + * @param {Uint8Array} inPtr + */ + glsBufferTestUtil.renderQuadGridReference = function(dst, numQuads, rowLength, inPtr) { + dst.setSize(rowLength * glsBufferTestUtil.VERIFY_QUAD_SIZE, (Math.floor(numQuads / rowLength) + (numQuads % rowLength != 0 ? 1 : 0)) * glsBufferTestUtil.VERIFY_QUAD_SIZE); + + /** @type {tcuTexture.PixelBufferAccess} */ var dstAccess = dst.getAccess(); + dstAccess.clear([0, 0, 0, 1.0]); + + for (var quadNdx = 0; quadNdx < numQuads; quadNdx++) { + /** @type {number} */ var x0 = (quadNdx % rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE; + /** @type {number} */ var y0 = Math.floor(quadNdx / rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE; + /** @type {Array<number>} */ var v00 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 0); + /** @type {Array<number>} */ var v10 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 1); + /** @type {Array<number>} */ var v01 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 2); + /** @type {Array<number>} */ var v11 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 3); + + for (var y = 0; y < glsBufferTestUtil.VERIFY_QUAD_SIZE; y++) + for (var x = 0; x < glsBufferTestUtil.VERIFY_QUAD_SIZE; x++) { + /** @type {number} */ var fx = (x + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE; + /** @type {number} */ var fy = (y + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE; + + /** @type {boolean} */ var tri = fx + fy <= 1.0; + /** @type {number} */ var tx = tri ? fx : (1.0 - fx); + /** @type {number} */ var ty = tri ? fy : (1.0 - fy); + /** @type {Array<number>} */ var t0 = tri ? v00 : v11; + /** @type {Array<number>} */ var t1 = tri ? v01 : v10; + /** @type {Array<number>} */ var t2 = tri ? v10 : v01; + /** @type {Array<number>} */ var color = deMath.add( + deMath.add(t0, deMath.scale(deMath.subtract(t1, t0), tx)), + deMath.scale(deMath.subtract(t2, t0), ty) + ); + + dstAccess.setPixel(color, x0 + x, y0 + y); + } + } + }; + + /** + * @param {WebGLBuffer} buffer + * @param {Uint8Array} refPtr + * @param {number} offset + * @param {number} numBytes + * @return {boolean} + */ + glsBufferTestUtil.VertexArrayVerifier.prototype.verifyNoTarget = function(buffer, refPtr, offset, numBytes) { + var numBytesInVtx = 3; + var numBytesInQuad = numBytesInVtx * 4; + var maxQuadsX = Math.min(128, Math.floor(gl.drawingBufferWidth / glsBufferTestUtil.VERIFY_QUAD_SIZE)); + var maxQuadsY = Math.min(128, Math.floor(gl.drawingBufferHeight / glsBufferTestUtil.VERIFY_QUAD_SIZE)); + var maxQuadsPerBatch = maxQuadsX * maxQuadsY; + var numVerified = 0; + var program = this.m_program.getProgram(); + /** @type {tcuRGBA.RGBA} */ var threshold = /*TODO: renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);*/ new tcuRGBA.RGBA([3, 3, 3, 3]); + var isOk = true; + + /** @type {Array<number>} */ var positions = []; + /** @type {Uint16Array} */var indices; + + /** @type {tcuSurface.Surface} */ var rendered = new tcuSurface.Surface(); + /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(); + + // Can't render full quad with smaller buffers. + assertMsgOptions(numBytes >= numBytesInQuad, 'Number of bytes must be bigger than number of bytes per quad', false, true); + + positions = glsBufferTestUtil.computePositions(maxQuadsX, maxQuadsY); + indices = glsBufferTestUtil.computeIndices(maxQuadsX, maxQuadsY); + + // Reset buffer bindings. + gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); + + // Setup rendering state. + gl.viewport(0, 0, maxQuadsX * glsBufferTestUtil.VERIFY_QUAD_SIZE, maxQuadsY * glsBufferTestUtil.VERIFY_QUAD_SIZE); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.useProgram(program); + gl.bindVertexArray(this.m_vao); + + // Upload positions + gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); + gl.enableVertexAttribArray(this.m_posLoc); + gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); + + // Upload indices + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_indexBuf); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); + + gl.enableVertexAttribArray(this.m_byteVecLoc); + + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + + while (numVerified < numBytes) { + /** @type {number} */ var numRemaining = numBytes - numVerified; + var isLeftoverBatch = numRemaining < numBytesInQuad; + /** @type {number} */ var numBytesToVerify = isLeftoverBatch ? numBytesInQuad : Math.min(maxQuadsPerBatch * numBytesInQuad, numRemaining - numRemaining % numBytesInQuad); + /** @type {number} */ var curOffset = isLeftoverBatch ? (numBytes - numBytesInQuad) : numVerified; + /** @type {number} */ var numQuads = Math.floor(numBytesToVerify / numBytesInQuad); + /** @type {number} */ var numCols = Math.min(maxQuadsX, numQuads); + /** @type {number} */ var numRows = Math.floor(numQuads / maxQuadsX) + (numQuads % maxQuadsX != 0 ? 1 : 0); + /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1); + + 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); + assertMsgOptions(deMath.deInBounds32(curOffset, 0, numBytes), 'Offset out of bounds', false, true); + assertMsgOptions(deMath.deInRange32(curOffset + numBytesToVerify, curOffset, numBytes), 'Range of bytes to verify outside of bounds', false, true); + + // Render batch. + gl.clear(gl.COLOR_BUFFER_BIT); + gl.vertexAttribPointer(this.m_byteVecLoc, 3, gl.UNSIGNED_BYTE, true, 0, offset + curOffset); + gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_SHORT, 0); + + glsBufferTestUtil.renderQuadGridReference(reference, numQuads, numCols, refPtr.subarray(offset + curOffset)); + + rendered.setSize(numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE); + rendered.readViewport(gl, [0, 0, numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE]); + + if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, reference, rendered, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) { + isOk = false; + break; + } + + numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; + } + + gl.bindVertexArray(null); + + return isOk; + }; + + // IndexArrayVerifier + + /** + * @constructor + * @extends {glsBufferTestUtil.BufferVerifierBase} + */ + glsBufferTestUtil.IndexArrayVerifier = function() { + glsBufferTestUtil.BufferVerifierBase.call(this); + + this.m_program = null; + this.m_posLoc = 0; + this.m_colorLoc = 0; + + /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.GLSLVersion.V300_ES; + + assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'GLSL version not supported', false, true); + + this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources( + gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + + 'in highp vec2 a_position;\n' + + 'in mediump vec3 a_color;\n' + + 'out mediump vec3 v_color;\n' + + 'void main (void)\n' + + '{\n' + + ' gl_Position = vec4(a_position, 0.0, 1.0);\n' + + ' v_color = a_color;\n' + + '}\n', + + gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' + + 'in mediump vec3 v_color;\n' + + 'layout(location = 0) out mediump vec4 o_color;\n' + + 'void main (void)\n' + + '{\n' + + ' o_color = vec4(v_color, 1.0);\n' + + '}\n')); + + if (!this.m_program.isOk()) { + testFailed('Compile failed'); + } + + this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position'); + this.m_colorLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_color'); + + this.m_vao = gl.createVertexArray(); + this.m_positionBuf = gl.createBuffer(); + this.m_colorBuf = gl.createBuffer(); + }; + + glsBufferTestUtil.IndexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype); + glsBufferTestUtil.IndexArrayVerifier.prototype.constructor = glsBufferTestUtil.IndexArrayVerifier; + + /** + * deinit + */ + glsBufferTestUtil.IndexArrayVerifier.prototype.deinit = function() { + if (this.m_vao) gl.deleteVertexArray(this.m_vao); + if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf); + if (this.m_colorBuf) gl.deleteBuffer(this.m_colorBuf); + }; + + /** + * @return {Array<number>} + */ + glsBufferTestUtil.computeIndexVerifierPositions = function() { + var numPosX = 16; + var numPosY = 16; + + var dst = []; + + for (var y = 0; y < numPosY; y++) { + for (var x = 0; x < numPosX; x++) { + var xf = x / (numPosX - 1); + var yf = y / (numPosY - 1); + + var offset = 2 * (y * numPosX + x); + dst[offset] = 2.0 * xf - 1.0; + dst[offset + 1] = 2.0 * yf - 1.0; + } + } + + return dst; + }; + + /** + * @return {Array<number>} + */ + glsBufferTestUtil.computeIndexVerifierColors = function() { + /** @type {number} */ var numColors = 256; + /** @type {number} */ var minVal = 0.1; + /** @type {number} */ var maxVal = 0.5; + var rnd = new deRandom.Random(0xabc231); + + var dst = []; + + for (var i = 0; i < numColors; ++i) { + dst[3 * i] = rnd.getFloat(minVal, maxVal); + dst[3 * i + 1] = rnd.getFloat(minVal, maxVal); + dst[3 * i + 2] = rnd.getFloat(minVal, maxVal); + } + + return dst; + }; + + /** + * @param {Array<number>} dst + * @param {Array<number>} src + * @param {Uint8Array} indices + * @param {number} numIndices + */ + glsBufferTestUtil.execVertexFetch = function(dst, src, indices, numIndices) { + for (var i = 0; i < numIndices; ++i) + dst[i] = src[indices[i]]; + }; + + /** + * @param {WebGLBuffer} buffer + * @param {Uint8Array} refPtr + * @param {number} offset + * @param {number} numBytes + * @return {boolean} + */ + glsBufferTestUtil.IndexArrayVerifier.prototype.verify = function(buffer, refPtr, offset, numBytes) { + var viewportW = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, gl.drawingBufferWidth); + var viewportH = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, gl.drawingBufferHeight); + var minBytesPerBatch = 2; + /** @type {tcuRGBA.RGBA} */ var threshold = new tcuRGBA.RGBA([0, 0, 0, 0]); + + var positions = []; + var colors = []; + + var fetchedPos = []; + var fetchedColor = []; + + /** @type {tcuSurface.Surface} */ var indexBufferImg = new tcuSurface.Surface(viewportW, viewportH); + /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(viewportW, viewportH); + + var numVerified = 0; + var isOk = true; + + positions = glsBufferTestUtil.computeIndexVerifierPositions(); + colors = glsBufferTestUtil.computeIndexVerifierColors(); + + // Reset buffer bindings. + gl.bindVertexArray(this.m_vao); + gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); + + // Setup rendering state. + gl.viewport(0, 0, viewportW, viewportH); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.useProgram(this.m_program.getProgram()); + gl.enableVertexAttribArray(this.m_posLoc); + gl.enableVertexAttribArray(this.m_colorLoc); + gl.enable(gl.BLEND); + gl.blendFunc(gl.ONE, gl.ONE); + gl.blendEquation(gl.FUNC_ADD); + + while (numVerified < numBytes) { + var numRemaining = numBytes - numVerified; + var isLeftoverBatch = numRemaining < minBytesPerBatch; + var numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : Math.min(glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW + 1, numRemaining); + var curOffset = isLeftoverBatch ? (numBytes - minBytesPerBatch) : numVerified; + /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1); + + // Step 1: Render using index buffer. + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STREAM_DRAW); + gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STREAM_DRAW); + gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0); + + gl.drawElements(gl.LINE_STRIP, numBytesToVerify, gl.UNSIGNED_BYTE, offset + curOffset); + indexBufferImg.readViewport(gl); + + // Step 2: Do manual fetch and render without index buffer. + glsBufferTestUtil.execVertexFetch(fetchedPos, positions, refPtr.subarray(offset + curOffset), numBytesToVerify); + glsBufferTestUtil.execVertexFetch(fetchedColor, colors, refPtr.subarray(offset + curOffset), numBytesToVerify); + + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedPos), gl.STREAM_DRAW); + gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedColor), gl.STREAM_DRAW); + gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.LINE_STRIP, 0, numBytesToVerify); + referenceImg.readViewport(gl, [0, 0, viewportW, viewportH]); + + if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, referenceImg, indexBufferImg, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) { + isOk = false; + break; + } + + numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify; + } + + gl.bindVertexArray(null); + + return isOk; + }; + +}); |