summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js2451
1 files changed, 2451 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js
new file mode 100644
index 0000000000..e9c45366ac
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js
@@ -0,0 +1,2451 @@
+/*-------------------------------------------------------------------------
+ * 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.glsUniformBlockCase');
+goog.require('framework.common.tcuTestCase');
+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 glsUniformBlockCase = modules.shared.glsUniformBlockCase;
+var tcuTestCase = framework.common.tcuTestCase;
+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;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+var littleEndian = (function() {
+ var buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
+ // Int16Array uses the platform's endianness.
+ return new Int16Array(buffer)[0] === 256;
+})();
+
+/**
+ * Class to implement some pointers functionality.
+ * @constructor
+ */
+glsUniformBlockCase.BlockPointers = function() {
+ /** @type {ArrayBuffer} */ this.data; //!< Data (vector<deUint8>).
+ /** @type {Array<number>} */ this.offsets = []; //!< Reference block pointers (map<int, void*>).
+ /** @type {Array<number>} */ this.sizes = [];
+};
+
+/**
+ * push - Adds an offset/size pair to the collection
+ * @param {number} offset Offset of the element to refer.
+ * @param {number} size Size of the referred element.
+ */
+glsUniformBlockCase.BlockPointers.prototype.push = function(offset, size) {
+ this.offsets.push(offset);
+ this.sizes.push(size);
+};
+
+/**
+ * find - Finds and maps the data at the given offset, and returns a Uint8Array
+ * @param {number} index of the element to find.
+ * @return {Uint8Array}
+ */
+glsUniformBlockCase.BlockPointers.prototype.find = function(index) {
+ return new Uint8Array(this.data, this.offsets[index], this.sizes[index]);
+};
+
+/**
+ * resize - Replaces resize of a vector in C++. Sets the size of the data buffer.
+ * NOTE: In this case however, if you resize, the data is lost.
+ * @param {number} newsize The new size of the data buffer.
+ */
+glsUniformBlockCase.BlockPointers.prototype.resize = function(newsize) {
+ this.data = new ArrayBuffer(newsize);
+};
+
+/**
+ * glsUniformBlockCase.isSupportedGLSLVersion
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {boolean}
+ */
+glsUniformBlockCase.isSupportedGLSLVersion = function(version) {
+ return version >= gluShaderUtil.GLSLVersion.V300_ES;
+};
+
+/**
+ * @enum {number}
+ */
+glsUniformBlockCase.UniformFlags = {
+ PRECISION_LOW: (1 << 0),
+ PRECISION_MEDIUM: (1 << 1),
+ PRECISION_HIGH: (1 << 2),
+
+ LAYOUT_SHARED: (1 << 3),
+ LAYOUT_PACKED: (1 << 4),
+ LAYOUT_STD140: (1 << 5),
+ LAYOUT_ROW_MAJOR: (1 << 6),
+ LAYOUT_COLUMN_MAJOR: (1 << 7), //!< \note Lack of both flags means column-major matrix.
+
+ DECLARE_VERTEX: (1 << 8),
+ DECLARE_FRAGMENT: (1 << 9),
+
+ UNUSED_VERTEX: (1 << 10), //!< glsUniformBlockCase.Uniform or struct member is not read in vertex shader.
+ UNUSED_FRAGMENT: (1 << 11) //!< glsUniformBlockCase.Uniform or struct member is not read in fragment shader.
+};
+
+/** @const */ glsUniformBlockCase.UniformFlags.PRECISION_MASK = glsUniformBlockCase.UniformFlags.PRECISION_LOW | glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM | glsUniformBlockCase.UniformFlags.PRECISION_HIGH;
+/** @const */ glsUniformBlockCase.UniformFlags.LAYOUT_MASK = glsUniformBlockCase.UniformFlags.LAYOUT_SHARED | glsUniformBlockCase.UniformFlags.LAYOUT_PACKED | glsUniformBlockCase.UniformFlags.LAYOUT_STD140 | glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR | glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR;
+/** @const */ glsUniformBlockCase.UniformFlags.DECLARE_BOTH = glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT;
+/** @const */ glsUniformBlockCase.UniformFlags.UNUSED_BOTH = glsUniformBlockCase.UniformFlags.UNUSED_VERTEX | glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT;
+
+/**
+* glsUniformBlockCase.VarType types enum
+* @enum {number}
+*/
+glsUniformBlockCase.Type = {
+ TYPE_BASIC: 0,
+ TYPE_ARRAY: 1,
+ TYPE_STRUCT: 2
+};
+
+glsUniformBlockCase.Type.TYPE_LAST = Object.keys(glsUniformBlockCase.Type).length;
+
+/**
+* glsUniformBlockCase.TypeArray struct (nothing to do with JS's TypedArrays)
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @constructor
+*/
+glsUniformBlockCase.TypeArray = function(elementType, arraySize) {
+ /** @type {glsUniformBlockCase.VarType} */ this.elementType = elementType;
+ /** @type {number} */ this.size = arraySize;
+};
+
+/**
+ * glsUniformBlockCase.VarType class
+ * @constructor
+ */
+glsUniformBlockCase.VarType = function() {
+ /** @type {glsUniformBlockCase.Type} */ this.m_type;
+ /** @type {number} */ this.m_flags = 0;
+
+ /*
+ * m_data used to be a 'Data' union in C++. Using a var is enough here.
+ * it will contain any necessary value.
+ */
+
+ /** @type {(gluShaderUtil.DataType|glsUniformBlockCase.TypeArray|glsUniformBlockCase.StructType)} */
+ this.m_data;
+};
+
+/**
+* Creates a basic type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {gluShaderUtil.DataType} basicType
+* @param {number} flags
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeBasic = function(basicType, flags) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_BASIC;
+ this.m_flags = flags;
+ this.m_data = basicType;
+
+ return this;
+};
+
+/**
+* Creates an array type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeArray = function(elementType, arraySize) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_ARRAY;
+ this.m_flags = 0;
+ this.m_data = new glsUniformBlockCase.TypeArray(elementType, arraySize);
+
+ return this;
+};
+
+/**
+* Creates a struct type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {glsUniformBlockCase.StructType} structPtr
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeStruct = function(structPtr) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_STRUCT;
+ this.m_flags = 0;
+ this.m_data = structPtr;
+
+ return this;
+};
+
+/** isBasicType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents a basic type.
+**/
+glsUniformBlockCase.VarType.prototype.isBasicType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_BASIC;
+};
+
+/** isArrayType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents an array.
+**/
+glsUniformBlockCase.VarType.prototype.isArrayType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_ARRAY;
+};
+
+/** isStructType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents a struct.
+**/
+glsUniformBlockCase.VarType.prototype.isStructType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_STRUCT;
+};
+
+/** getFlags
+* @return {number} returns the flags of the glsUniformBlockCase.VarType.
+**/
+glsUniformBlockCase.VarType.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** getBasicType
+* @return {gluShaderUtil.DataType} returns the basic data type of the glsUniformBlockCase.VarType.
+**/
+glsUniformBlockCase.VarType.prototype.getBasicType = function() {
+ return /** @type {gluShaderUtil.DataType} */ (this.m_data);
+};
+
+/** getElementType
+* @return {glsUniformBlockCase.VarType} returns the glsUniformBlockCase.VarType of the element in case of an Array.
+**/
+glsUniformBlockCase.VarType.prototype.getElementType = function() {
+ return this.m_data.elementType;
+};
+
+/** getArraySize
+* (not to be confused with a javascript array)
+* @return {number} returns the size of the array in case it is an array.
+**/
+glsUniformBlockCase.VarType.prototype.getArraySize = function() {
+ return this.m_data.size;
+};
+
+/** getStruct
+* @return {glsUniformBlockCase.StructType} returns the structure when it is a glsUniformBlockCase.StructType.
+**/
+glsUniformBlockCase.VarType.prototype.getStruct = function() {
+ return /** @type {glsUniformBlockCase.StructType} */ (this.m_data);
+};
+
+/**
+ * Creates a basic type glsUniformBlockCase.VarType.
+ * @param {gluShaderUtil.DataType} basicType
+ * @param {number} flags
+ * @return {glsUniformBlockCase.VarType}
+ */
+glsUniformBlockCase.newVarTypeBasic = function(basicType, flags) {
+ return new glsUniformBlockCase.VarType().VarTypeBasic(basicType, flags);
+};
+
+/**
+* Creates an array type glsUniformBlockCase.VarType.
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @return {glsUniformBlockCase.VarType}
+*/
+glsUniformBlockCase.newVarTypeArray = function(elementType, arraySize) {
+ return new glsUniformBlockCase.VarType().VarTypeArray(elementType, arraySize);
+};
+
+/**
+* Creates a struct type glsUniformBlockCase.VarType.
+* @param {glsUniformBlockCase.StructType} structPtr
+* @return {glsUniformBlockCase.VarType}
+*/
+glsUniformBlockCase.newVarTypeStruct = function(structPtr) {
+ return new glsUniformBlockCase.VarType().VarTypeStruct(structPtr);
+};
+
+/** glsUniformBlockCase.StructMember
+ * in the JSDoc annotations or if a number would do.
+ * @constructor
+**/
+glsUniformBlockCase.StructMember = function() {
+ /** @type {string} */ this.m_name;
+ /** @type {glsUniformBlockCase.VarType} */ this.m_type;
+ /** @type {number} */ this.m_flags = 0;
+};
+
+/**
+ * Creates a glsUniformBlockCase.StructMember. Use this after the constructor call.
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number} flags
+ * @return {glsUniformBlockCase.StructMember} The currently modified object
+ */
+glsUniformBlockCase.StructMember.prototype.Constructor = function(name, type, flags) {
+ this.m_type = type;
+ this.m_name = name;
+ this.m_flags = flags;
+
+ return this;
+};
+
+/** getName
+* @return {string} the name of the member
+**/
+glsUniformBlockCase.StructMember.prototype.getName = function() { return this.m_name; };
+
+/** getType
+* @return {glsUniformBlockCase.VarType} the type of the member
+**/
+glsUniformBlockCase.StructMember.prototype.getType = function() { return this.m_type; };
+
+/** getFlags
+* @return {number} the flags in the member
+**/
+glsUniformBlockCase.StructMember.prototype.getFlags = function() { return this.m_flags; };
+
+/**
+ * Creates a glsUniformBlockCase.StructMember with name, type and flags.
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @return {glsUniformBlockCase.StructMember}
+ */
+ glsUniformBlockCase.newStructMember = function(name, type, flags) {
+ return new glsUniformBlockCase.StructMember().Constructor(name, type, flags);
+ };
+
+/**
+ * glsUniformBlockCase.StructType
+ * @constructor
+ */
+glsUniformBlockCase.StructType = function() {
+ /** @type {string}*/ this.m_typeName;
+ /** @type {Array<glsUniformBlockCase.StructMember>} */ this.m_members = [];
+};
+
+/**
+ * glsUniformBlockCase.StructType - Constructor with type name
+ * @param {string} typeName
+ * @return {glsUniformBlockCase.StructType} The currently modified object.
+ */
+glsUniformBlockCase.StructType.prototype.Constructor = function(typeName) {
+ /** @type {string}*/ this.m_typeName = typeName;
+ return this;
+};
+
+/** getTypeName
+* @return {string}
+**/
+glsUniformBlockCase.StructType.prototype.getTypeName = function() {
+ return this.m_typeName;
+};
+
+/*
+ * Instead of iterators, we'll add
+ * a getter for a specific element (getMember),
+ * and current members amount (getSize).
+ */
+
+/** getMember
+* @param {number} memberNdx The index of the member to retrieve.
+* @return {glsUniformBlockCase.StructMember}
+**/
+glsUniformBlockCase.StructType.prototype.getMember = function(memberNdx) {
+ if (memberNdx >= 0 && memberNdx < this.m_members.length)
+ return this.m_members[memberNdx];
+ else {
+ throw new Error("Invalid member index for glsUniformBlockCase.StructType's members");
+ }
+};
+
+/** getSize
+* @return {number} The size of the m_members array.
+**/
+glsUniformBlockCase.StructType.prototype.getSize = function() {
+ return this.m_members.length;
+};
+
+/** addMember
+* @param {string} member_name
+* @param {glsUniformBlockCase.VarType} member_type
+* @param {number=} member_flags
+**/
+glsUniformBlockCase.StructType.prototype.addMember = function(member_name, member_type, member_flags) {
+ var member = glsUniformBlockCase.newStructMember(member_name, member_type, member_flags);
+
+ this.m_members.push(member);
+};
+
+/**
+ * Creates a glsUniformBlockCase.StructType.
+ * @param {string} name
+ * @return {glsUniformBlockCase.StructType}
+ */
+glsUniformBlockCase.newStructType = function(name) {
+ return new glsUniformBlockCase.StructType().Constructor(name);
+};
+
+/** glsUniformBlockCase.Uniform
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number=} flags
+ * @constructor
+**/
+glsUniformBlockCase.Uniform = function(name, type, flags) {
+ /** @type {string} */ this.m_name = name;
+ /** @type {glsUniformBlockCase.VarType} */ this.m_type = type;
+ /** @type {number} */ this.m_flags = (typeof flags === 'undefined') ? 0 : flags;
+};
+
+/** getName
+ * @return {string}
+ */
+glsUniformBlockCase.Uniform.prototype.getName = function() {
+ return this.m_name;
+};
+
+/** getType
+ * @return {glsUniformBlockCase.VarType}
+ */
+glsUniformBlockCase.Uniform.prototype.getType = function() {
+ return this.m_type;
+};
+
+/** getFlags
+* @return {number}
+**/
+glsUniformBlockCase.Uniform.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** glsUniformBlockCase.UniformBlock
+ * @param {string} blockName
+ * @constructor
+**/
+glsUniformBlockCase.UniformBlock = function(blockName) {
+ /** @type {string} */ this.m_blockName = blockName;
+ /** @type {string} */ this.m_instanceName;
+ /** @type {Array<glsUniformBlockCase.Uniform>} */ this.m_uniforms = [];
+ /** @type {number} */ this.m_arraySize = 0; //!< Array size or 0 if not interface block array.
+ /** @type {number} */ this.m_flags = 0;
+};
+
+/** getBlockName
+* @return {string}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getBlockName = function() {
+ return this.m_blockName;
+};
+
+/** getInstanceName
+* @return {string}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getInstanceName = function() {
+ return this.m_instanceName;
+};
+
+/** isArray
+* @return {boolean}
+**/
+glsUniformBlockCase.UniformBlock.prototype.isArray = function() {
+ return this.m_arraySize > 0;
+};
+
+/** getArraySize
+* @return {number}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getArraySize = function() {
+ return this.m_arraySize;
+};
+
+/** getFlags
+* @return {number}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** setInstanceName
+* @param {string} name
+**/
+glsUniformBlockCase.UniformBlock.prototype.setInstanceName = function(name) {
+ this.m_instanceName = name;
+};
+
+/** setFlags
+* @param {number} flags
+**/
+glsUniformBlockCase.UniformBlock.prototype.setFlags = function(flags) {
+ this.m_flags = flags;
+};
+
+/** setArraySize
+* @param {number} arraySize
+**/
+glsUniformBlockCase.UniformBlock.prototype.setArraySize = function(arraySize) {
+ this.m_arraySize = arraySize;
+};
+
+/** addUniform
+* @param {glsUniformBlockCase.Uniform} uniform
+**/
+glsUniformBlockCase.UniformBlock.prototype.addUniform = function(uniform) {
+ this.m_uniforms.push(uniform);
+};
+
+/*
+ * Using uniform getter (getUniform),
+ * and uniform array size getter (countUniforms)
+ * instead of iterators.
+*/
+
+/**
+ * getUniform
+ * @param {number} index
+ * @return {glsUniformBlockCase.Uniform}
+ */
+glsUniformBlockCase.UniformBlock.prototype.getUniform = function(index) {
+ if (index >= 0 && index < this.m_uniforms.length)
+ return this.m_uniforms[index];
+ else {
+ throw new Error("Invalid uniform index for glsUniformBlockCase.UniformBlock's uniforms");
+ }
+};
+
+/**
+ * countUniforms
+ * @return {number}
+ */
+glsUniformBlockCase.UniformBlock.prototype.countUniforms = function() {
+ return this.m_uniforms.length;
+};
+
+/**
+ * glsUniformBlockCase.ShaderInterface
+ * @constructor
+ */
+glsUniformBlockCase.ShaderInterface = function() {
+ /** @type {Array<glsUniformBlockCase.StructType>} */ this.m_structs = [];
+ /** @type {Array<glsUniformBlockCase.UniformBlock>} */ this.m_uniformBlocks = [];
+};
+
+/** allocStruct
+* @param {string} name
+* @return {glsUniformBlockCase.StructType}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.allocStruct = function(name) {
+ //m_structs.reserve(m_structs.length + 1);
+ this.m_structs.push(glsUniformBlockCase.newStructType(name));
+ return this.m_structs[this.m_structs.length - 1];
+};
+
+/** findStruct
+* @param {string} name
+* @return {glsUniformBlockCase.StructType}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.findStruct = function(name) {
+ for (var pos = 0; pos < this.m_structs.length; pos++) {
+ if (this.m_structs[pos].getTypeName() == name)
+ return this.m_structs[pos];
+ }
+ return null;
+};
+
+/** getNamedStructs
+* @param {Array<glsUniformBlockCase.StructType>} structs
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getNamedStructs = function(structs) {
+ for (var pos = 0; pos < this.m_structs.length; pos++) {
+ if (this.m_structs[pos].getTypeName() != undefined)
+ structs.push(this.m_structs[pos]);
+ }
+};
+
+/** allocBlock
+* @param {string} name
+* @return {glsUniformBlockCase.UniformBlock}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.allocBlock = function(name) {
+ this.m_uniformBlocks.push(new glsUniformBlockCase.UniformBlock(name));
+ return this.m_uniformBlocks[this.m_uniformBlocks.length - 1];
+};
+
+/** getNumUniformBlocks
+* @return {number}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getNumUniformBlocks = function() {
+ return this.m_uniformBlocks.length;
+};
+
+/** getUniformBlock
+* @param {number} ndx
+* @return {glsUniformBlockCase.UniformBlock}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getUniformBlock = function(ndx) {
+ return this.m_uniformBlocks[ndx];
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.BlockLayoutEntry = function() {
+ return {
+ /** @type {number} */ size: 0,
+ /** @type {string} */ name: '',
+ /** @type {Array<number>} */ activeUniformIndices: []
+ };
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformLayoutEntry = function() {
+ return {
+ /** @type {string} */ name: '',
+ /** @type {gluShaderUtil.DataType} */ type: gluShaderUtil.DataType.INVALID,
+ /** @type {number} */ size: 0,
+ /** @type {number} */ blockNdx: -1,
+ /** @type {number} */ offset: -1,
+ /** @type {number} */ arrayStride: -1,
+ /** @type {number} */ matrixStride: -1,
+ /** @type {boolean} */ isRowMajor: false
+ };
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformLayout = function() {
+ /** @type {Array<glsUniformBlockCase.BlockLayoutEntry>}*/ this.blocks = [];
+ /** @type {Array<glsUniformBlockCase.UniformLayoutEntry>}*/ this.uniforms = [];
+};
+
+/** getUniformIndex, returns a uniform index number in the layout,
+ * given the uniform's name.
+ * @param {string} name
+ * @return {number} uniform's index
+ */
+glsUniformBlockCase.UniformLayout.prototype.getUniformIndex = function(name) {
+ for (var ndx = 0; ndx < this.uniforms.length; ndx++) {
+ if (this.uniforms[ndx].name == name)
+ return ndx;
+ }
+ return -1;
+};
+
+/** getBlockIndex, returns a block index number in the layout,
+ * given the block's name.
+ * @param {string} name the name of the block
+ * @return {number} block's index
+ */
+glsUniformBlockCase.UniformLayout.prototype.getBlockIndex = function(name) {
+ for (var ndx = 0; ndx < this.blocks.length; ndx++) {
+ if (this.blocks[ndx].name == name)
+ return ndx;
+ }
+ return -1;
+};
+
+/**
+ * @enum {number}
+ */
+glsUniformBlockCase.BufferMode = {
+ BUFFERMODE_SINGLE: 0, //!< Single buffer shared between uniform blocks.
+ BUFFERMODE_PER_BLOCK: 1 //!< Per-block buffers
+};
+
+glsUniformBlockCase.BufferMode.BUFFERMODE_LAST = Object.keys(glsUniformBlockCase.BufferMode).length;
+
+/**
+ * glsUniformBlockCase.PrecisionFlagsFmt
+ * @param {number} flags
+ * @return {string}
+ */
+glsUniformBlockCase.PrecisionFlagsFmt = function(flags) {
+ // Precision.
+ DE_ASSERT(deMath.dePop32(flags & (glsUniformBlockCase.UniformFlags.PRECISION_LOW | glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM | glsUniformBlockCase.UniformFlags.PRECISION_HIGH)) <= 1);
+ var str = '';
+ str += (flags & glsUniformBlockCase.UniformFlags.PRECISION_LOW ? 'lowp' :
+ flags & glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM ? 'mediump' :
+ flags & glsUniformBlockCase.UniformFlags.PRECISION_HIGH ? 'highp' : '');
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.LayoutFlagsFmt
+ * @param {number} flags_
+ * @return {string}
+ */
+glsUniformBlockCase.LayoutFlagsFmt = function(flags_) {
+ var str = '';
+ var bitDesc =
+ [{ bit: glsUniformBlockCase.UniformFlags.LAYOUT_SHARED, token: 'shared' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_PACKED, token: 'packed' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_STD140, token: 'std140' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR, token: 'row_major' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR, token: 'column_major' }
+ ];
+
+ /** @type {number} */ var remBits = flags_;
+ for (var descNdx = 0; descNdx < bitDesc.length; descNdx++) {
+ if (remBits & bitDesc[descNdx].bit) {
+ if (remBits != flags_)
+ str += ', ';
+ str += bitDesc[descNdx].token;
+ remBits &= (~bitDesc[descNdx].bit) & 0xFFFFFFFF; //0xFFFFFFFF truncate to 32 bit value
+ }
+ }
+ DE_ASSERT(remBits == 0);
+
+ return str;
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformBufferManager = function(renderCtx) {
+ this.m_renderCtx = renderCtx;
+ /** @type {Array<number>} */ this.m_buffers = [];
+};
+
+/**
+ * allocBuffer
+ * @return {WebGLBuffer}
+ */
+glsUniformBlockCase.UniformBufferManager.prototype.allocBuffer = function() {
+ /** @type {WebGLBuffer} */ var buf = this.m_renderCtx.createBuffer();
+
+ this.m_buffers.push(buf);
+
+ return buf;
+};
+
+/**
+ * @param {string} name
+ * @param {string} description
+ * @param {glsUniformBlockCase.BufferMode} bufferMode
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+glsUniformBlockCase.UniformBlockCase = function(name, description, bufferMode) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ /** @type {string} */ this.m_name = name;
+ /** @type {string} */ this.m_description = description;
+ /** @type {glsUniformBlockCase.BufferMode} */ this.m_bufferMode = bufferMode;
+ /** @type {glsUniformBlockCase.ShaderInterface} */ this.m_interface = new glsUniformBlockCase.ShaderInterface();
+};
+
+glsUniformBlockCase.UniformBlockCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+glsUniformBlockCase.UniformBlockCase.prototype.constructor = glsUniformBlockCase.UniformBlockCase;
+
+/**
+ * glsUniformBlockCase.getDataTypeByteSize
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeByteSize = function(type) {
+ return gluShaderUtil.getDataTypeScalarSize(type) * deMath.INT32_SIZE;
+};
+
+/**
+ * glsUniformBlockCase.getDataTypeByteAlignment
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeByteAlignment = function(type) {
+ switch (type) {
+ case gluShaderUtil.DataType.FLOAT:
+ case gluShaderUtil.DataType.INT:
+ case gluShaderUtil.DataType.UINT:
+ case gluShaderUtil.DataType.BOOL: return 1 * deMath.INT32_SIZE;
+
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.INT_VEC2:
+ case gluShaderUtil.DataType.UINT_VEC2:
+ case gluShaderUtil.DataType.BOOL_VEC2: return 2 * deMath.INT32_SIZE;
+
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.INT_VEC3:
+ case gluShaderUtil.DataType.UINT_VEC3:
+ case gluShaderUtil.DataType.BOOL_VEC3: // Fall-through to vec4
+
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ case gluShaderUtil.DataType.INT_VEC4:
+ case gluShaderUtil.DataType.UINT_VEC4:
+ case gluShaderUtil.DataType.BOOL_VEC4: return 4 * deMath.INT32_SIZE;
+
+ default:
+ DE_ASSERT(false);
+ return 0;
+ }
+};
+
+/**
+ * glsUniformBlockCase.getDataTypeArrayStride
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeArrayStride = function(type) {
+ DE_ASSERT(!gluShaderUtil.isDataTypeMatrix(type));
+
+ /** @type {number} */ var baseStride = glsUniformBlockCase.getDataTypeByteSize(type);
+ /** @type {number} */ var vec4Alignment = deMath.INT32_SIZE * 4;
+
+ DE_ASSERT(baseStride <= vec4Alignment);
+ return Math.max(baseStride, vec4Alignment); // Really? See rule 4.
+};
+
+/**
+ * glsUniformBlockCase.deRoundUp32 Rounds up 'a' in case the
+ * relationship with 'b' has a decimal part.
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+glsUniformBlockCase.deRoundUp32 = function(a, b) {
+ var d = Math.trunc(a / b);
+ return d * b == a ? a : (d + 1) * b;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140BaseAlignment
+ * @param {glsUniformBlockCase.VarType} type
+ * @return {number}
+ */
+glsUniformBlockCase.computeStd140BaseAlignment = function(type) {
+ /** @type {number} */ var vec4Alignment = deMath.INT32_SIZE * 4;
+
+ if (type.isBasicType()) {
+ /** @type {gluShaderUtil.DataType} */ var basicType = type.getBasicType();
+
+ if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ /** @type {boolean} */ var isRowMajor = !!(type.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ /** @type {number} */ var vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+
+ return glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+ } else
+ return glsUniformBlockCase.getDataTypeByteAlignment(basicType);
+ } else if (type.isArrayType()) {
+ /** @type {number} */ var elemAlignment = glsUniformBlockCase.computeStd140BaseAlignment(type.getElementType());
+
+ // Round up to alignment of vec4
+ return glsUniformBlockCase.deRoundUp32(elemAlignment, vec4Alignment);
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ /** @type {number} */ var maxBaseAlignment = 0;
+
+ for (var memberNdx = 0; memberNdx < type.getStruct().getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = type.getStruct().getMember(memberNdx);
+ maxBaseAlignment = Math.max(maxBaseAlignment, glsUniformBlockCase.computeStd140BaseAlignment(memberIter.getType()));
+ }
+
+ return glsUniformBlockCase.deRoundUp32(maxBaseAlignment, vec4Alignment);
+ }
+};
+
+/**
+ * mergeLayoutflags
+ * @param {number} prevFlags
+ * @param {number} newFlags
+ * @return {number}
+ */
+glsUniformBlockCase.mergeLayoutFlags = function(prevFlags, newFlags) {
+ /** @type {number} */ var packingMask = glsUniformBlockCase.UniformFlags.LAYOUT_PACKED | glsUniformBlockCase.UniformFlags.LAYOUT_SHARED | glsUniformBlockCase.UniformFlags.LAYOUT_STD140;
+ /** @type {number} */ var matrixMask = glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR | glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR;
+
+ /** @type {number} */ var mergedFlags = 0;
+
+ mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
+ mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
+
+ return mergedFlags;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140Layout_B
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {number} curOffset
+ * @param {number} curBlockNdx
+ * @param {string} curPrefix
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number} layoutFlags
+ * @return {number} //This is what would return in the curOffset output parameter in the original C++ project.
+ */
+glsUniformBlockCase.computeStd140Layout_B = function(layout, curOffset, curBlockNdx, curPrefix, type, layoutFlags) {
+ /** @type {number} */ var baseAlignment = glsUniformBlockCase.computeStd140BaseAlignment(type);
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry;
+ /** @type {number} */ var stride;
+ /** @type {gluShaderUtil.DataType} */ var elemBasicType;
+ /** @type {boolean} */ var isRowMajor;
+ /** @type {number} */ var vecSize;
+ /** @type {number} */ var numVecs;
+
+ curOffset = deMath.deAlign32(curOffset, baseAlignment);
+
+ if (type.isBasicType()) {
+ /** @type {gluShaderUtil.DataType} */ var basicType = type.getBasicType();
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+
+ entry.name = curPrefix;
+ entry.type = basicType;
+ entry.size = 1;
+ entry.arrayStride = 0;
+ entry.matrixStride = 0;
+ entry.blockNdx = curBlockNdx;
+
+ if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ // Array of vectors as specified in rules 5 & 7.
+ isRowMajor = !!(layoutFlags & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+ numVecs = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumColumns(basicType);
+ stride = glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+
+ entry.offset = curOffset;
+ entry.matrixStride = stride;
+ entry.isRowMajor = isRowMajor;
+
+ curOffset += numVecs * stride;
+ } else {
+ // Scalar or vector.
+ entry.offset = curOffset;
+
+ curOffset += glsUniformBlockCase.getDataTypeByteSize(basicType);
+ }
+
+ layout.uniforms.push(entry);
+ } else if (type.isArrayType()) {
+ /** @type {glsUniformBlockCase.VarType} */ var elemType = type.getElementType();
+
+ if (elemType.isBasicType() && !gluShaderUtil.isDataTypeMatrix(elemType.getBasicType())) {
+ // Array of scalars or vectors.
+ elemBasicType = elemType.getBasicType();
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+ stride = glsUniformBlockCase.getDataTypeArrayStride(elemBasicType);
+
+ entry.name = curPrefix + '[0]'; // Array uniforms are always postfixed with [0]
+ entry.type = elemBasicType;
+ entry.blockNdx = curBlockNdx;
+ entry.offset = curOffset;
+ entry.size = type.getArraySize();
+ entry.arrayStride = stride;
+ entry.matrixStride = 0;
+
+ curOffset += stride * type.getArraySize();
+
+ layout.uniforms.push(entry);
+ } else if (elemType.isBasicType() && gluShaderUtil.isDataTypeMatrix(elemType.getBasicType())) {
+ // Array of matrices.
+ elemBasicType = elemType.getBasicType();
+ isRowMajor = !!(layoutFlags & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(elemBasicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(elemBasicType);
+ numVecs = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(elemBasicType) :
+ gluShaderUtil.getDataTypeMatrixNumColumns(elemBasicType);
+ stride = glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+
+ entry.name = curPrefix + '[0]'; // Array uniforms are always postfixed with [0]
+ entry.type = elemBasicType;
+ entry.blockNdx = curBlockNdx;
+ entry.offset = curOffset;
+ entry.size = type.getArraySize();
+ entry.arrayStride = stride * numVecs;
+ entry.matrixStride = stride;
+ entry.isRowMajor = isRowMajor;
+
+ curOffset += numVecs * type.getArraySize() * stride;
+
+ layout.uniforms.push(entry);
+ } else {
+ DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
+
+ for (var elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, curBlockNdx, curPrefix + '[' + elemNdx + ']', type.getElementType(), layoutFlags);
+ }
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ for (var memberNdx = 0; memberNdx < type.getStruct().getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = type.getStruct().getMember(memberNdx);
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, curBlockNdx, curPrefix + '.' + memberIter.getName(), memberIter.getType(), layoutFlags);
+ }
+
+ curOffset = deMath.deAlign32(curOffset, baseAlignment);
+ }
+
+ return curOffset;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140Layout
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.computeStd140Layout = function(layout, sinterface) {
+ // \todo [2012-01-23 pyry] Uniforms in default block.
+
+ /** @type {number} */ var numUniformBlocks = sinterface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var hasInstanceName = block.getInstanceName() !== undefined;
+ /** @type {string} */ var blockPrefix = hasInstanceName ? (block.getBlockName() + '.') : '';
+ /** @type {number} */ var curOffset = 0;
+ /** @type {number} */ var activeBlockNdx = layout.blocks.length;
+ /** @type {number} */ var firstUniformNdx = layout.uniforms.length;
+
+ for (var ubNdx = 0; ubNdx < block.countUniforms(); ubNdx++) {
+ /** @type {glsUniformBlockCase.Uniform} */ var uniform = block.getUniform(ubNdx);
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(), glsUniformBlockCase.mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
+ }
+
+ /** @type {number} */ var uniformIndicesEnd = layout.uniforms.length;
+ /** @type {number} */ var blockSize = curOffset;
+ /** @type {number} */ var numInstances = block.isArray() ? block.getArraySize() : 1;
+
+ // Create block layout entries for each instance.
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ // Allocate entry for instance.
+ layout.blocks.push(new glsUniformBlockCase.BlockLayoutEntry());
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var blockEntry = layout.blocks[layout.blocks.length - 1];
+
+ blockEntry.name = block.getBlockName();
+ blockEntry.size = blockSize;
+
+ // Compute active uniform set for block.
+ for (var uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
+ blockEntry.activeUniformIndices.push(uniformNdx);
+
+ if (block.isArray())
+ blockEntry.name += '[' + instanceNdx + ']';
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.generateValue - Value generator
+ * @param {glsUniformBlockCase.UniformLayoutEntry} entry
+ * @param {Uint8Array} basePtr
+ * @param {deRandom.Random} rnd
+ */
+glsUniformBlockCase.generateValue = function(entry, basePtr, rnd) {
+ /** @type {gluShaderUtil.DataType}*/ var scalarType = gluShaderUtil.getDataTypeScalarTypeAsDataType(entry.type); //Using a more appropriate function in this case.
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(entry.type);
+ /** @type {boolean} */ var isMatrix = gluShaderUtil.isDataTypeMatrix(entry.type);
+ /** @type {number} */ var numVecs = isMatrix ? (entry.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(entry.type) : gluShaderUtil.getDataTypeMatrixNumColumns(entry.type)) : 1;
+ /** @type {number} */ var vecSize = scalarSize / numVecs;
+ /** @type {boolean} */ var isArray = entry.size > 1;
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+
+ DE_ASSERT(scalarSize % numVecs == 0);
+
+ for (var elemNdx = 0; elemNdx < entry.size; elemNdx++) {
+ /** @type {Uint8Array} */ var elemPtr = basePtr.subarray(entry.offset + (isArray ? elemNdx * entry.arrayStride : 0));
+
+ for (var vecNdx = 0; vecNdx < numVecs; vecNdx++) {
+ /** @type {Uint8Array} */ var vecPtr = elemPtr.subarray(isMatrix ? vecNdx * entry.matrixStride : 0);
+
+ for (var compNdx = 0; compNdx < vecSize; compNdx++) {
+ /** @type {Uint8Array} */ var compPtr = vecPtr.subarray(compSize * compNdx);
+ /** @type {number} */ var _random;
+
+ //Copy the random data byte per byte
+ var _size = glsUniformBlockCase.getDataTypeByteSize(scalarType);
+
+ var nbuffer = new ArrayBuffer(_size);
+ var nview = new DataView(nbuffer);
+
+ switch (scalarType) {
+ case gluShaderUtil.DataType.FLOAT:
+ _random = rnd.getInt(-9, 9);
+ nview.setFloat32(0, _random, littleEndian);
+ break;
+ case gluShaderUtil.DataType.INT:
+ _random = rnd.getInt(-9, 9);
+ nview.setInt32(0, _random, littleEndian);
+ break;
+ case gluShaderUtil.DataType.UINT:
+ _random = rnd.getInt(0, 9);
+ nview.setUint32(0, _random, littleEndian);
+ break;
+ // \note Random bit pattern is used for true values. Spec states that all non-zero values are
+ // interpreted as true but some implementations fail this.
+ case gluShaderUtil.DataType.BOOL:
+ _random = rnd.getBool() ? 1 : 0;
+ nview.setUint32(0, _random, littleEndian);
+ break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ for (var i = 0; i < _size; i++) {
+ compPtr[i] = nview.getUint8(i);
+ }
+ }
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.generateValues
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ * @param {number} seed
+ */
+glsUniformBlockCase.generateValues = function(layout, blockPointers, seed) {
+ /** @type  {deRandom.Random} */ var rnd = new deRandom.Random(seed);
+ /** @type  {number} */ var numBlocks = layout.blocks.length;
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {Uint8Array} */ var basePtr = blockPointers.find(blockNdx);
+ /** @type  {number} */ var numEntries = layout.blocks[blockNdx].activeUniformIndices.length;
+
+ for (var entryNdx = 0; entryNdx < numEntries; entryNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
+ glsUniformBlockCase.generateValue(entry, basePtr, rnd);
+ }
+ }
+};
+
+// Shader generator.
+
+/**
+ * glsUniformBlockCase.getCompareFuncForType
+ * @param {gluShaderUtil.DataType} type
+ * @return {string}
+ */
+glsUniformBlockCase.getCompareFuncForType = function(type) {
+ switch (type) {
+ case gluShaderUtil.DataType.FLOAT: return 'mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 'mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 'mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 'mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 'mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 'mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 'mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.INT: return 'mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC2: return 'mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC3: return 'mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC4: return 'mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT: return 'mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC2: return 'mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC3: return 'mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC4: return 'mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL: return 'mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC2: return 'mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC3: return 'mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC4: return 'mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ default:
+ throw new Error('Type "' + type + '" not supported.');
+
+ }
+};
+
+/**
+ * glsUniformBlockCase.getCompareDependencies
+ * @param {Array<gluShaderUtil.DataType>} compareFuncs Should contain unique elements
+ * @param {gluShaderUtil.DataType} basicType
+ */
+glsUniformBlockCase.getCompareDependencies = function(compareFuncs, basicType) {
+ switch (basicType) {
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.DataType.FLOAT);
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+
+ case gluShaderUtil.DataType.FLOAT_MAT2:
+ case gluShaderUtil.DataType.FLOAT_MAT2X3:
+ case gluShaderUtil.DataType.FLOAT_MAT2X4:
+ case gluShaderUtil.DataType.FLOAT_MAT3X2:
+ case gluShaderUtil.DataType.FLOAT_MAT3:
+ case gluShaderUtil.DataType.FLOAT_MAT3X4:
+ case gluShaderUtil.DataType.FLOAT_MAT4X2:
+ case gluShaderUtil.DataType.FLOAT_MAT4X3:
+ case gluShaderUtil.DataType.FLOAT_MAT4:
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.DataType.FLOAT);
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType)));
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+
+ default:
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+ }
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes_B
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.VarType} type
+ */
+glsUniformBlockCase.collectUniqueBasicTypes_B = function(basicTypes, type) {
+ if (type.isStructType()) {
+ /** @type {glsUniformBlockCase.StructType} */ var stype = type.getStruct();
+ for (var memberNdx = 0; memberNdx < stype.getSize(); memberNdx++)
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, stype.getMember(memberNdx).getType());
+ } else if (type.isArrayType())
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, type.getElementType());
+ else {
+ DE_ASSERT(type.isBasicType());
+ deUtil.dePushUniqueToArray(basicTypes, type.getBasicType());
+ }
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes_A
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.UniformBlock} uniformBlock
+ */
+glsUniformBlockCase.collectUniqueBasicTypes_A = function(basicTypes, uniformBlock) {
+ for (var uniformNdx = 0; uniformNdx < uniformBlock.countUniforms(); uniformNdx++)
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, uniformBlock.getUniform(uniformNdx).getType());
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.collectUniqueBasicTypes = function(basicTypes, sinterface) {
+ for (var ndx = 0; ndx < sinterface.getNumUniformBlocks(); ++ndx)
+ glsUniformBlockCase.collectUniqueBasicTypes_A(basicTypes, sinterface.getUniformBlock(ndx));
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes
+ * @return {string} Was originally an output parameter. As it is a basic type, we have to return it instead.
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.generateCompareFuncs = function(sinterface) {
+ /** @type {string} */ var str = '';
+ /** @type {Array<gluShaderUtil.DataType>} */ var types = []; //Will contain unique elements.
+ /** @type {Array<gluShaderUtil.DataType>} */ var compareFuncs = []; //Will contain unique elements.
+
+ // Collect unique basic types
+ glsUniformBlockCase.collectUniqueBasicTypes(types, sinterface);
+
+ // Set of compare functions required
+ for (var typeNdx = 0; typeNdx < types.length; typeNdx++)
+ glsUniformBlockCase.getCompareDependencies(compareFuncs, types[typeNdx]);
+
+ for (var type in gluShaderUtil.DataType) {
+ if (compareFuncs.indexOf(gluShaderUtil.DataType[type]) > -1)
+ str += glsUniformBlockCase.getCompareFuncForType(gluShaderUtil.DataType[type]);
+ }
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.Indent - Prints level_ number of tab chars
+ * @param {number} level_
+ * @return {string}
+ */
+glsUniformBlockCase.Indent = function(level_) {
+ var str = '';
+ for (var i = 0; i < level_; i++)
+ str += '\t';
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_C
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateDeclaration_C = function(structType, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ DE_ASSERT(structType.getTypeName() !== undefined);
+ src += glsUniformBlockCase.generateFullDeclaration(structType, indentLevel);
+ src += ';\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateFullDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateFullDeclaration = function(structType, indentLevel) {
+ var src = 'struct';
+ if (structType.getTypeName())
+ src += ' ' + structType.getTypeName();
+ src += '\n' + glsUniformBlockCase.Indent(indentLevel) + ' {\n';
+
+ for (var memberNdx = 0; memberNdx < structType.getSize(); memberNdx++) {
+ src += glsUniformBlockCase.Indent(indentLevel + 1);
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = structType.getMember(memberNdx);
+ src += glsUniformBlockCase.generateDeclaration_B(memberIter.getType(), memberIter.getName(), indentLevel + 1, memberIter.getFlags() & glsUniformBlockCase.UniformFlags.UNUSED_BOTH);
+ }
+
+ src += glsUniformBlockCase.Indent(indentLevel) + '}';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateLocalDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateLocalDeclaration = function(structType, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ if (structType.getTypeName() === undefined)
+ src += glsUniformBlockCase.generateFullDeclaration(structType, indentLevel);
+ else
+ src += structType.getTypeName();
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_B
+ * @return {string} src
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {string} name
+ * @param {number} indentLevel
+ * @param {number} unusedHints
+ */
+glsUniformBlockCase.generateDeclaration_B = function(type, name, indentLevel, unusedHints) {
+ /** @type {string} */ var src = '';
+ /** @type {number} */ var flags = type.getFlags();
+
+ if ((flags & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(flags & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ if ((flags & glsUniformBlockCase.UniformFlags.PRECISION_MASK) != 0)
+ src += glsUniformBlockCase.PrecisionFlagsFmt(flags & glsUniformBlockCase.UniformFlags.PRECISION_MASK) + ' ';
+
+ if (type.isBasicType())
+ src += gluShaderUtil.getDataTypeName(type.getBasicType()) + ' ' + name;
+ else if (type.isArrayType()) {
+ /** @type {Array<number>} */ var arraySizes = [];
+ /** @type {glsUniformBlockCase.VarType} */ var curType = type;
+ while (curType.isArrayType()) {
+ arraySizes.push(curType.getArraySize());
+ curType = curType.getElementType();
+ }
+
+ if (curType.isBasicType()) {
+ if ((curType.getFlags() & glsUniformBlockCase.UniformFlags.PRECISION_MASK) != 0)
+ src += glsUniformBlockCase.PrecisionFlagsFmt(curType.getFlags() & glsUniformBlockCase.UniformFlags.PRECISION_MASK) + ' ';
+ src += gluShaderUtil.getDataTypeName(curType.getBasicType());
+ } else {
+ DE_ASSERT(curType.isStructType());
+ src += glsUniformBlockCase.generateLocalDeclaration(curType.getStruct(), indentLevel + 1);
+ }
+
+ src += ' ' + name;
+
+ for (var sizeNdx = 0; sizeNdx < arraySizes.length; sizeNdx++)
+ src += '[' + arraySizes[sizeNdx] + ']';
+ } else {
+ src += glsUniformBlockCase.generateLocalDeclaration(type.getStruct(), indentLevel + 1);
+ src += ' ' + name;
+ }
+
+ src += ';';
+
+ // Print out unused hints.
+ if (unusedHints != 0)
+ src += ' // unused in ' + (unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_BOTH ? 'both shaders' :
+ unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_VERTEX ? 'vertex shader' :
+ unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT ? 'fragment shader' : '???');
+
+ src += '\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_A
+ * @return {string} src
+ * @param {glsUniformBlockCase.Uniform} uniform
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateDeclaration_A = function(uniform, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ if ((uniform.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(uniform.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ src += glsUniformBlockCase.generateDeclaration_B(uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & glsUniformBlockCase.UniformFlags.UNUSED_BOTH);
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.UniformBlock} block
+ */
+glsUniformBlockCase.generateDeclaration = function(block) {
+ /** @type {string} */ var src = '';
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ src += 'uniform ' + block.getBlockName();
+ src += '\n {\n';
+
+ for (var uniformNdx = 0; uniformNdx < block.countUniforms(); uniformNdx++) {
+ src += glsUniformBlockCase.Indent(1);
+ src += glsUniformBlockCase.generateDeclaration_A(block.getUniform(uniformNdx), 1 /* indent level */);
+ }
+
+ src += '}';
+
+ if (block.getInstanceName() !== undefined) {
+ src += ' ' + block.getInstanceName();
+ if (block.isArray())
+ src += '[' + block.getArraySize() + ']';
+ } else
+ DE_ASSERT(!block.isArray());
+
+ src += ';\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.newArrayBufferFromView - Creates a new buffer copying data from a given view
+ * @param {goog.NumberArray} view
+ * @return {ArrayBuffer} The newly created buffer
+ */
+glsUniformBlockCase.newArrayBufferFromView = function(view) {
+ var buffer = new ArrayBuffer(view.length * view.BYTES_PER_ELEMENT);
+ var copyview;
+ switch (view.BYTES_PER_ELEMENT) {
+ case 1:
+ copyview = new Uint8Array(buffer); break;
+ case 2:
+ copyview = new Uint16Array(buffer); break;
+ case 4:
+ copyview = new Uint32Array(buffer); break;
+ default:
+ assertMsgOptions(false, 'Unexpected value for BYTES_PER_ELEMENT in view', false, true);
+ }
+ for (var i = 0; i < view.length; i++)
+ copyview[i] = view[i];
+
+ return buffer;
+};
+
+/**
+ * glsUniformBlockCase.generateValueSrc
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {glsUniformBlockCase.UniformLayoutEntry} entry
+ * @param {Uint8Array} basePtr
+ * @param {number} elementNdx
+ */
+glsUniformBlockCase.generateValueSrc = function(entry, basePtr, elementNdx) {
+ /** @type {string} */ var src = '';
+ /** @type {gluShaderUtil.DataType} */ var scalarType = gluShaderUtil.getDataTypeScalarTypeAsDataType(entry.type);
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(entry.type);
+ /** @type {boolean} */ var isArray = entry.size > 1;
+ /** @type {Uint8Array} */ var elemPtr = basePtr.subarray(entry.offset + (isArray ? elementNdx * entry.arrayStride : 0));
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+ /** @type {Uint8Array} */ var compPtr;
+ if (scalarSize > 1)
+ src += gluShaderUtil.getDataTypeName(entry.type) + '(';
+
+ if (gluShaderUtil.isDataTypeMatrix(entry.type)) {
+ /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(entry.type);
+ /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(entry.type);
+
+ DE_ASSERT(scalarType == gluShaderUtil.DataType.FLOAT);
+
+ // Constructed in column-wise order.
+ for (var colNdx = 0; colNdx < numCols; colNdx++) {
+ for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
+ compPtr = elemPtr.subarray(entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
+ colNdx * entry.matrixStride + rowNdx * compSize);
+
+ if (colNdx > 0 || rowNdx > 0)
+ src += ', ';
+
+ var newbuffer = new Uint8Array(compPtr.subarray(0, 4)).buffer;
+ var newview = new DataView(newbuffer);
+ src += parseFloat(newview.getFloat32(0, littleEndian)).toFixed(1);
+ }
+ }
+ } else {
+ for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) {
+ compPtr = elemPtr.subarray(scalarNdx * compSize);
+
+ if (scalarNdx > 0)
+ src += ', ';
+
+ var newbuffer = glsUniformBlockCase.newArrayBufferFromView(compPtr.subarray(0, 4));
+ var newview = new DataView(newbuffer);
+
+ switch (scalarType) {
+ case gluShaderUtil.DataType.FLOAT: src += parseFloat(newview.getFloat32(0, littleEndian) * 100 / 100).toFixed(1); break;
+ case gluShaderUtil.DataType.INT: src += newview.getInt32(0, littleEndian); break;
+ case gluShaderUtil.DataType.UINT: src += newview.getUint32(0, littleEndian) + 'u'; break;
+ case gluShaderUtil.DataType.BOOL: src += (newview.getUint32(0, littleEndian) != 0 ? 'true' : 'false'); break;
+ default:
+ DE_ASSERT(false);
+ }
+ }
+ }
+
+ if (scalarSize > 1)
+ src += ')';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateCompareSrc_A
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {string} resultVar
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {string} srcName
+ * @param {string} apiName
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {Uint8Array} basePtr
+ * @param {number} unusedMask
+ */
+glsUniformBlockCase.generateCompareSrc_A = function(resultVar, type, srcName, apiName, layout, basePtr, unusedMask) {
+ /** @type {string} */ var src = '';
+ /** @type {string} */ var op;
+ /** @type {glsUniformBlockCase.VarType|gluShaderUtil.DataType} */ var elementType;
+
+ if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType())) {
+ // Basic type or array of basic types.
+ /** @type {boolean} */ var isArray = type.isArrayType();
+ elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
+ /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(elementType);
+ /** @type {string} */ var fullApiName = apiName + (isArray ? '[0]' : ''); // Arrays are always postfixed with [0]
+ /** @type {number} */ var uniformNdx = layout.getUniformIndex(fullApiName);
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry = layout.uniforms[uniformNdx];
+
+ if (isArray) {
+ for (var elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) {
+ src += '\tresult *= compare_' + typeName + '(' + srcName + '[' + elemNdx + '], ';
+ src += glsUniformBlockCase.generateValueSrc(entry, basePtr, elemNdx);
+ src += ');\n';
+ }
+ } else {
+ src += '\tresult *= compare_' + typeName + '(' + srcName + ', ';
+ src += glsUniformBlockCase.generateValueSrc(entry, basePtr, 0);
+ src += ');\n';
+ }
+ } else if (type.isArrayType()) {
+ elementType = type.getElementType();
+
+ for (var elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++) {
+ op = '[' + elementNdx + ']';
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, elementType, srcName + op, apiName + op, layout, basePtr, unusedMask);
+ }
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ /** @type {glsUniformBlockCase.StructType} */ var stype = type.getStruct();
+ for (var memberNdx = 0; memberNdx < stype.getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = stype.getMember(memberNdx);
+ if (memberIter.getFlags() & unusedMask)
+ continue; // Skip member.
+
+ op = '.' + memberIter.getName();
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, memberIter.getType(), srcName + op, apiName + op, layout, basePtr, unusedMask);
+ }
+ }
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateCompareSrc
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {string} resultVar
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ * @param {boolean} isVertex
+ */
+glsUniformBlockCase.generateCompareSrc = function(resultVar, sinterface, layout, blockPointers, isVertex) {
+ /** @type {string} */ var src = '';
+ /** @type {number} */ var unusedMask = isVertex ? glsUniformBlockCase.UniformFlags.UNUSED_VERTEX : glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT;
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+
+ if ((block.getFlags() & (isVertex ? glsUniformBlockCase.UniformFlags.DECLARE_VERTEX : glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) == 0)
+ continue; // Skip.
+
+ /** @type {boolean} */ var hasInstanceName = block.getInstanceName() !== undefined;
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {number} */ var numInstances = isArray ? block.getArraySize() : 1;
+ /** @type {string} */ var apiPrefix = hasInstanceName ? block.getBlockName() + '.' : '';
+
+ DE_ASSERT(!isArray || hasInstanceName);
+
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ /** @type {string} */ var instancePostfix = isArray ? '[' + instanceNdx + ']' : '';
+ /** @type {string} */ var blockInstanceName = block.getBlockName() + instancePostfix;
+ /** @type {string} */ var srcPrefix = hasInstanceName ? block.getInstanceName() + instancePostfix + '.' : '';
+ /** @type {number} */ var activeBlockNdx = layout.getBlockIndex(blockInstanceName);
+ /** @type {Uint8Array} */ var basePtr = blockPointers.find(activeBlockNdx);
+
+ for (var uniformNdx = 0; uniformNdx < block.countUniforms(); uniformNdx++) {
+ /** @type {glsUniformBlockCase.Uniform} */ var uniform = block.getUniform(uniformNdx);
+
+ if (uniform.getFlags() & unusedMask)
+ continue; // Don't read from that uniform.
+
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, uniform.getType(), srcPrefix + uniform.getName(), apiPrefix + uniform.getName(), layout, basePtr, unusedMask);
+ }
+ }
+ }
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateVertexShader
+ * @return {string} src
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ */
+glsUniformBlockCase.generateVertexShader = function(sinterface, layout, blockPointers) {
+ /** @type {string} */ var src = '';
+
+ DE_ASSERT(glsUniformBlockCase.isSupportedGLSLVersion(gluShaderUtil.getGLSLVersion(gl)));
+
+ src += gluShaderUtil.getGLSLVersionDeclaration(gluShaderUtil.getGLSLVersion(gl)) + '\n';
+ src += 'in highp vec4 a_position;\n';
+ src += 'out mediump float v_vtxResult;\n';
+ src += '\n';
+
+ /** @type {Array<glsUniformBlockCase.StructType>} */ var namedStructs = [];
+ sinterface.getNamedStructs(namedStructs);
+ for (var structNdx = 0; structNdx < namedStructs.length; structNdx++)
+ src += glsUniformBlockCase.generateDeclaration_C(namedStructs[structNdx], 0);
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ if (block.getFlags() & glsUniformBlockCase.UniformFlags.DECLARE_VERTEX)
+ src += glsUniformBlockCase.generateDeclaration(block);
+ }
+
+ // Comparison utilities.
+ src += '\n';
+ src += glsUniformBlockCase.generateCompareFuncs(sinterface);
+
+ src += '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' gl_Position = a_position;\n' +
+ ' mediump float result = 1.0;\n';
+
+ // Value compare.
+ src += glsUniformBlockCase.generateCompareSrc('result', sinterface, layout, blockPointers, true);
+
+ src += ' v_vtxResult = result;\n' +
+ '}\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateFragmentShader
+ * @return {string} Used to be an output parameter
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ */
+glsUniformBlockCase.generateFragmentShader = function(sinterface, layout, blockPointers) {
+ /** @type {string} */ var src = '';
+ DE_ASSERT(glsUniformBlockCase.isSupportedGLSLVersion(gluShaderUtil.getGLSLVersion(gl)));
+
+ src += gluShaderUtil.getGLSLVersionDeclaration(gluShaderUtil.getGLSLVersion(gl)) + '\n';
+ src += 'in mediump float v_vtxResult;\n';
+ src += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+ src += '\n';
+
+ /** @type {Array<glsUniformBlockCase.StructType>} */ var namedStructs = [];
+ sinterface.getNamedStructs(namedStructs);
+ for (var structNdx = 0; structNdx < namedStructs.length; structNdx++)
+ src += glsUniformBlockCase.generateDeclaration_C(namedStructs[structNdx], 0);
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ if (block.getFlags() & glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)
+ src += glsUniformBlockCase.generateDeclaration(block);
+ }
+
+ // Comparison utilities.
+ src += '\n';
+ src += glsUniformBlockCase.generateCompareFuncs(sinterface);
+
+ src += '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' mediump float result = 1.0;\n';
+
+ // Value compare.
+ src += glsUniformBlockCase.generateCompareSrc('result', sinterface, layout, blockPointers, false);
+
+ src += ' dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n' +
+ '}\n';
+
+ return src;
+};
+
+/**
+ * TODO: test glsUniformBlockCase.getGLUniformLayout Gets the uniform blocks and uniforms in the program.
+ * @param {WebGL2RenderingContext} gl
+ * @param {glsUniformBlockCase.UniformLayout} layout To store the layout described in program.
+ * @param {WebGLProgram} program id
+ */
+glsUniformBlockCase.getGLUniformLayout = function(gl, layout, program) {
+ /** @type {number} */ var numActiveUniforms = 0;
+ /** @type {number} */ var numActiveBlocks = 0;
+
+ numActiveUniforms = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS)); // ACTIVE_UNIFORM* returns GLInt
+ numActiveBlocks = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS));
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var entryBlock;
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entryUniform;
+ /** @type {number} */ var size;
+ /** @type {number} */ var nameLen;
+ /** @type {string} */ var nameBuf;
+ /** @type {number} */ var numBlockUniforms;
+
+ // Block entries.
+ //No need to allocate these beforehand: layout.blocks.resize(numActiveBlocks);
+ for (var blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++) {
+ entryBlock = new glsUniformBlockCase.BlockLayoutEntry();
+
+ size = /** @type {number} */ (gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_DATA_SIZE));
+ // nameLen not used so this line is removed.
+ // nameLen = gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_NAME_LENGTH); // TODO: UNIFORM_BLOCK_NAME_LENGTH is removed in WebGL2
+ numBlockUniforms = /** @type {number} */ (gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS));
+
+ nameBuf = gl.getActiveUniformBlockName(program, blockNdx);
+
+ entryBlock.name = nameBuf;
+ entryBlock.size = size;
+ //entry.activeUniformIndices.resize(numBlockUniforms);
+
+ if (numBlockUniforms > 0)
+ entryBlock.activeUniformIndices = gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
+
+ layout.blocks.push(entryBlock); //Pushing the block into the array here.
+ }
+
+ if (numActiveUniforms > 0) {
+ // glsUniformBlockCase.Uniform entries.
+ /** @type {Array<number>} */ var uniformIndices = [];
+ for (var i = 0; i < numActiveUniforms; i++)
+ uniformIndices.push(i);
+
+ /** @type {Array<number>} */ var types = [];
+ /** @type {Array<number>} */ var sizes = [];
+ /** @type {Array<number>} */ var nameLengths = [];
+ /** @type {Array<number>} */ var blockIndices = [];
+ /** @type {Array<number>} */ var offsets = [];
+ /** @type {Array<number>} */ var arrayStrides = [];
+ /** @type {Array<number>} */ var matrixStrides = [];
+ /** @type {Array<number>} */ var rowMajorFlags = [];
+
+ // Execute queries.
+ types = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_TYPE);
+ sizes = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_SIZE);
+ // Remove this: nameLengths = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_NAME_LENGTH);
+ blockIndices = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_BLOCK_INDEX);
+ offsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ arrayStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_ARRAY_STRIDE);
+ matrixStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_MATRIX_STRIDE);
+ rowMajorFlags = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_IS_ROW_MAJOR);
+
+ // Translate to LayoutEntries
+ // No resize needed. Will push them: layout.uniforms.resize(numActiveUniforms);
+ for (var uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++) {
+ entryUniform = new glsUniformBlockCase.UniformLayoutEntry();
+
+ // Remove this: nameLen = 0;
+ size = 0;
+ /** @type {number} */ var type = gl.NONE;
+
+ var uniform = gl.getActiveUniform(program, uniformNdx);
+
+ nameBuf = uniform.name;
+ // Remove this: nameLen = nameBuf.length;
+ size = uniform.size;
+ type = uniform.type;
+
+ // Remove this: nameLen != nameLengths[uniformNdx] ||
+ if (size != sizes[uniformNdx] ||
+ type != types[uniformNdx])
+ testFailedOptions("Values returned by gl.getActiveUniform() don't match with values queried with gl.getActiveUniforms().", true);
+
+ entryUniform.name = nameBuf;
+ entryUniform.type = gluShaderUtil.getDataTypeFromGLType(types[uniformNdx]);
+ entryUniform.size = sizes[uniformNdx];
+ entryUniform.blockNdx = blockIndices[uniformNdx];
+ entryUniform.offset = offsets[uniformNdx];
+ entryUniform.arrayStride = arrayStrides[uniformNdx];
+ entryUniform.matrixStride = matrixStrides[uniformNdx];
+ entryUniform.isRowMajor = rowMajorFlags[uniformNdx] != false;
+
+ layout.uniforms.push(entryUniform); //Pushing this uniform in the end.
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.copyUniformData_A - Copies a source uniform buffer segment to a destination uniform buffer segment.
+ * @param {glsUniformBlockCase.UniformLayoutEntry} dstEntry
+ * @param {Uint8Array} dstBlockPtr
+ * @param {glsUniformBlockCase.UniformLayoutEntry} srcEntry
+ * @param {Uint8Array} srcBlockPtr
+ */
+glsUniformBlockCase.copyUniformData_A = function(dstEntry, dstBlockPtr, srcEntry, srcBlockPtr) {
+ /** @type {Uint8Array} */ var dstBasePtr = dstBlockPtr.subarray(dstEntry.offset);
+ /** @type {Uint8Array} */ var srcBasePtr = srcBlockPtr.subarray(srcEntry.offset);
+
+ DE_ASSERT(dstEntry.size <= srcEntry.size);
+ DE_ASSERT(dstEntry.type == srcEntry.type);
+
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(dstEntry.type);
+ /** @type {boolean} */ var isMatrix = gluShaderUtil.isDataTypeMatrix(dstEntry.type);
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+
+ for (var elementNdx = 0; elementNdx < dstEntry.size; elementNdx++) {
+ /** @type {Uint8Array} */ var dstElemPtr = dstBasePtr.subarray(elementNdx * dstEntry.arrayStride);
+ /** @type {Uint8Array} */ var srcElemPtr = srcBasePtr.subarray(elementNdx * srcEntry.arrayStride);
+
+ if (isMatrix) {
+ /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(dstEntry.type);
+ /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(dstEntry.type);
+
+ for (var colNdx = 0; colNdx < numCols; colNdx++) {
+ for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
+ var srcoffset = dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
+ colNdx * dstEntry.matrixStride + rowNdx * compSize;
+ /** @type {Uint8Array} */ var dstCompPtr = dstElemPtr.subarray(srcoffset, srcoffset + compSize);
+ var dstoffset = srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
+ colNdx * srcEntry.matrixStride + rowNdx * compSize;
+ /** @type {Uint8Array} */ var srcCompPtr = srcElemPtr.subarray(dstoffset, dstoffset + compSize);
+
+ //Copy byte per byte
+ for (var i = 0; i < compSize; i++)
+ dstCompPtr[i] = srcCompPtr[i];
+ }
+ }
+ } else
+ //Copy byte per byte
+ for (var i = 0; i < scalarSize * compSize; i++)
+ dstElemPtr[i] = srcElemPtr[i];
+ }
+};
+
+/**
+ * glsUniformBlockCase.copyUniformData - Copies a source uniform buffer to a destination uniform buffer.
+ * @param {glsUniformBlockCase.UniformLayout} dstLayout
+ * @param {glsUniformBlockCase.BlockPointers} dstBlockPointers
+ * @param {glsUniformBlockCase.UniformLayout} srcLayout
+ * @param {glsUniformBlockCase.BlockPointers} srcBlockPointers
+ */
+glsUniformBlockCase.copyUniformData = function(dstLayout, dstBlockPointers, srcLayout, srcBlockPointers) {
+ // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
+ /** @type {number} */ var numBlocks = srcLayout.blocks.length;
+
+ for (var srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var srcBlock = srcLayout.blocks[srcBlockNdx];
+ /** @type {Uint8Array} */ var srcBlockPtr = srcBlockPointers.find(srcBlockNdx);
+ /** @type {number} */ var dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name);
+ /** @type {Uint8Array} */ var dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx) : null;
+
+ if (dstBlockNdx < 0)
+ continue;
+
+ for (var srcUniformNdx = 0; srcUniformNdx < srcBlock.activeUniformIndices.length; srcUniformNdx++) {
+ /** @type {number} */ var srcUniformNdxIter = srcBlock.activeUniformIndices[srcUniformNdx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var srcEntry = srcLayout.uniforms[srcUniformNdxIter];
+ /** @type {number} */ var dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name);
+
+ if (dstUniformNdx < 0)
+ continue;
+
+ glsUniformBlockCase.copyUniformData_A(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
+ }
+ }
+};
+
+ /**
+ * TODO: Test with an actual WebGL 2.0 context
+ * iterate - The actual execution of the test.
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsUniformBlockCase.UniformBlockCase.prototype.iterate = function() {
+ /** @type {glsUniformBlockCase.UniformLayout} */ var refLayout = new glsUniformBlockCase.UniformLayout(); //!< std140 layout.
+ /** @type {glsUniformBlockCase.BlockPointers} */ var blockPointers = new glsUniformBlockCase.BlockPointers();
+
+ // Compute reference layout.
+ glsUniformBlockCase.computeStd140Layout(refLayout, this.m_interface);
+
+ // Assign storage for reference values.
+ /** @type {number} */ var totalSize = 0;
+ for (var blockNdx = 0; blockNdx < refLayout.blocks.length; blockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var blockIter = refLayout.blocks[blockNdx];
+ totalSize += blockIter.size;
+ }
+ blockPointers.resize(totalSize);
+
+ // Pointers for each block.
+ var curOffset = 0;
+ for (var blockNdx = 0; blockNdx < refLayout.blocks.length; blockNdx++) {
+ var size = refLayout.blocks[blockNdx].size;
+ blockPointers.push(curOffset, size);
+ curOffset += size;
+ }
+
+ // Generate values.
+ glsUniformBlockCase.generateValues(refLayout, blockPointers, 1 /* seed */);
+
+ // Generate shaders and build program.
+ /** @type {string} */ var vtxSrc = glsUniformBlockCase.generateVertexShader(this.m_interface, refLayout, blockPointers);
+ /** @type {string} */ var fragSrc = glsUniformBlockCase.generateFragmentShader(this.m_interface, refLayout, blockPointers);
+
+ /** @type {gluShaderProgram.ShaderProgram}*/ var program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtxSrc, fragSrc));
+ bufferedLogToConsole(program.getProgramInfo().infoLog);
+
+ if (!program.isOk()) {
+ // Compile failed.
+ testFailedOptions('Compile failed', false);
+ return tcuTestCase.IterateResult.STOP;
+ }
+
+ // Query layout from GL.
+ /** @type {glsUniformBlockCase.UniformLayout} */ var glLayout = new glsUniformBlockCase.UniformLayout();
+ glsUniformBlockCase.getGLUniformLayout(gl, glLayout, program.getProgram());
+
+ // Print layout to log.
+ bufferedLogToConsole('Active glsUniformBlockCase.Uniform Blocks');
+ for (var blockNdx = 0; blockNdx < glLayout.blocks.length; blockNdx++)
+ bufferedLogToConsole(blockNdx + ': ' + glLayout.blocks[blockNdx]);
+
+ bufferedLogToConsole('Active Uniforms');
+ for (var uniformNdx = 0; uniformNdx < glLayout.uniforms.length; uniformNdx++)
+ bufferedLogToConsole(uniformNdx + ': ' + glLayout.uniforms[uniformNdx]);
+
+ // Check that we can even try rendering with given layout.
+ if (!this.checkLayoutIndices(glLayout) || !this.checkLayoutBounds(glLayout) || !this.compareTypes(refLayout, glLayout)) {
+ testFailedOptions('Invalid layout', false);
+ return tcuTestCase.IterateResult.STOP; // It is not safe to use the given layout.
+ }
+
+ // Verify all std140 blocks.
+ if (!this.compareStd140Blocks(refLayout, glLayout))
+ testFailedOptions('Invalid std140 layout', false);
+
+ // Verify all shared blocks - all uniforms should be active, and certain properties match.
+ if (!this.compareSharedBlocks(refLayout, glLayout))
+ testFailedOptions('Invalid shared layout', false);
+
+ // Check consistency with index queries
+ if (!this.checkIndexQueries(program.getProgram(), glLayout))
+ testFailedOptions('Inconsintent block index query results', false);
+
+ // Use program.
+ gl.useProgram(program.getProgram());
+
+ /** @type {number} */ var binding;
+ /** @type {WebGLBuffer} */ var buffer;
+
+ // Assign binding points to all active uniform blocks.
+ for (var blockNdx = 0; blockNdx < glLayout.blocks.length; blockNdx++) {
+ binding = blockNdx; // \todo [2012-01-25 pyry] Randomize order?
+ gl.uniformBlockBinding(program.getProgram(), blockNdx, binding);
+ }
+
+ /** @type {number} */ var numBlocks;
+ /** @type {glsUniformBlockCase.BlockPointers} */ var glBlockPointers;
+
+ // Allocate buffers, write data and bind to targets.
+ /** @type {glsUniformBlockCase.UniformBufferManager} */ var bufferManager = new glsUniformBlockCase.UniformBufferManager(gl);
+ if (this.m_bufferMode == glsUniformBlockCase.BufferMode.BUFFERMODE_PER_BLOCK) {
+ numBlocks = glLayout.blocks.length;
+ glBlockPointers = new glsUniformBlockCase.BlockPointers();
+
+ var totalsize = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+ totalsize += glLayout.blocks[blockNdx].size;
+
+ glBlockPointers.resize(totalsize);
+
+ var offset = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ glBlockPointers.push(offset, glLayout.blocks[blockNdx].size);
+ offset += glLayout.blocks[blockNdx].size;
+ }
+
+ glsUniformBlockCase.copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ buffer = bufferManager.allocBuffer();
+ binding = blockNdx;
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+ gl.bufferData(gl.UNIFORM_BUFFER, glBlockPointers.find(blockNdx) /*(glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0]*/, gl.STATIC_DRAW);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer);
+ }
+ } else {
+ DE_ASSERT(this.m_bufferMode == glsUniformBlockCase.BufferMode.BUFFERMODE_SINGLE);
+
+ totalSize = 0;
+ curOffset = 0;
+ numBlocks = glLayout.blocks.length;
+ /** @type {number} */ var bindingAlignment = 0;
+ glBlockPointers = new glsUniformBlockCase.BlockPointers();
+
+ bindingAlignment = /** @type {number} */ (gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT));
+
+ // Compute total size and offsets.
+ curOffset = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ if (bindingAlignment > 0)
+ curOffset = glsUniformBlockCase.deRoundUp32(curOffset, bindingAlignment);
+ glBlockPointers.push(curOffset, glLayout.blocks[blockNdx].size);
+ curOffset += glLayout.blocks[blockNdx].size;
+ }
+ totalSize = curOffset;
+ glBlockPointers.resize(totalSize);
+
+ // Copy to gl format.
+ glsUniformBlockCase.copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
+
+ // Allocate buffer and upload data.
+ buffer = bufferManager.allocBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+ if (glBlockPointers.data.byteLength > 0 /*!glData.empty()*/)
+ gl.bufferData(gl.UNIFORM_BUFFER, glBlockPointers.find(blockNdx) /*(glw::GLsizeiptr)glData.size(), &glData[0]*/, gl.STATIC_DRAW);
+
+ // Bind ranges to binding points.
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ binding = blockNdx;
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, glBlockPointers.offsets[blockNdx], glLayout.blocks[blockNdx].size);
+ }
+ }
+
+ /** @type {boolean} */ var renderOk = this.render(program);
+ if (!renderOk)
+ testFailedOptions('Image compare failed', false);
+ else
+ assertMsgOptions(renderOk, '', true, false);
+
+ return tcuTestCase.IterateResult.STOP;
+};
+
+/**
+* compareStd140Blocks
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareStd140Blocks = function(refLayout, cmpLayout) {
+ /**@type {boolean} */ var isOk = true;
+ /**@type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /**@type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /**@type {boolean} */ var isArray = block.isArray();
+ /**@type {string} */ var instanceName = block.getBlockName() + (isArray ? '[0]' : '');
+ /**@type {number} */ var refBlockNdx = refLayout.getBlockIndex(instanceName);
+ /**@type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+ /**@type {boolean} */ var isUsed = (block.getFlags() & (glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) != 0;
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_STD140) == 0)
+ continue; // Not std140 layout.
+
+ DE_ASSERT(refBlockNdx >= 0);
+
+ if (cmpBlockNdx < 0) {
+ // Not found, should it?
+ if (isUsed) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform block '" + instanceName + "' not found");
+ isOk = false;
+ }
+
+ continue; // Skip block.
+ }
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var refBlockLayout = refLayout.blocks[refBlockNdx];
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
+ // \todo [2012-01-24 pyry] Verify all instances.
+ if (refBlockLayout.activeUniformIndices.length != cmpBlockLayout.activeUniformIndices.length) {
+ bufferedLogToConsole("Error: Number of active uniforms differ in block '" + instanceName +
+ "' (expected " + refBlockLayout.activeUniformIndices.length +
+ ', got ' + cmpBlockLayout.activeUniformIndices.length +
+ ')');
+ isOk = false;
+ }
+
+ for (var ndx = 0; ndx < refBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = refBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[ndxIter];
+ /** @type {number} */ var cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name);
+
+ if (cmpEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + refEntry.name + "' not found");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
+
+ if (refEntry.type != cmpEntry.type ||
+ refEntry.size != cmpEntry.size ||
+ refEntry.offset != cmpEntry.offset ||
+ refEntry.arrayStride != cmpEntry.arrayStride ||
+ refEntry.matrixStride != cmpEntry.matrixStride ||
+ refEntry.isRowMajor != cmpEntry.isRowMajor) {
+ bufferedLogToConsole("Error: Layout mismatch in '" + refEntry.name + "':\n" +
+ ' expected: type = ' + gluShaderUtil.getDataTypeName(refEntry.type) + ', size = ' + refEntry.size + ', row major = ' + (refEntry.isRowMajor ? 'true' : 'false') + '\n' +
+ ' got: type = ' + gluShaderUtil.getDataTypeName(cmpEntry.type) + ', size = ' + cmpEntry.size + ', row major = ' + (cmpEntry.isRowMajor ? 'true' : 'false'));
+ isOk = false;
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/**
+* compareSharedBlocks
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareSharedBlocks = function(refLayout, cmpLayout) {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {string} */ var instanceName = block.getBlockName() + (isArray ? '[0]' : '');
+ /** @type {number} */ var refBlockNdx = refLayout.getBlockIndex(instanceName);
+ /** @type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+ /** @type {boolean} */ var isUsed = (block.getFlags() & (glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) != 0;
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_SHARED) == 0)
+ continue; // Not shared layout.
+
+ DE_ASSERT(refBlockNdx >= 0);
+
+ if (cmpBlockNdx < 0) {
+ // Not found, should it?
+ if (isUsed) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform block '" + instanceName + "' not found");
+ isOk = false;
+ }
+
+ continue; // Skip block.
+ }
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var refBlockLayout = refLayout.blocks[refBlockNdx];
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ if (refBlockLayout.activeUniformIndices.length != cmpBlockLayout.activeUniformIndices.length) {
+ bufferedLogToConsole("Error: Number of active uniforms differ in block '" + instanceName +
+ "' (expected " + refBlockLayout.activeUniformIndices.length +
+ ', got ' + cmpBlockLayout.activeUniformIndices.length +
+ ')');
+ isOk = false;
+ }
+
+ for (var ndx = 0; ndx < refBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = refBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[ndxIter];
+ /** @type {number} */ var cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name);
+
+ if (cmpEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + refEntry.name + "' not found");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
+
+ if (refEntry.type != cmpEntry.type ||
+ refEntry.size != cmpEntry.size ||
+ refEntry.isRowMajor != cmpEntry.isRowMajor) {
+ bufferedLogToConsole("Error: Layout mismatch in '" + refEntry.name + "':\n" +
+ ' expected: type = ' + gluShaderUtil.getDataTypeName(refEntry.type) + ', size = ' + refEntry.size + ', row major = ' + (refEntry.isRowMajor ? 'true' : 'false') + '\n' +
+ ' got: type = ' + gluShaderUtil.getDataTypeName(cmpEntry.type) + ', size = ' + cmpEntry.size + ', row major = ' + (cmpEntry.isRowMajor ? 'true' : 'false'));
+ isOk = false;
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/** compareTypes
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+* @return {boolean} true if uniform types are the same
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareTypes = function(refLayout, cmpLayout) {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {number} */ var numInstances = isArray ? block.getArraySize() : 1;
+
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ /** @type {string} */ var instanceName;
+
+ instanceName += block.getBlockName();
+ if (isArray)
+ instanceName = instanceName + '[' + instanceNdx + ']';
+
+ /** @type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+
+ if (cmpBlockNdx < 0)
+ continue;
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ for (var ndx = 0; ndx < cmpBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = cmpBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[ndxIter];
+ /** @type {number} */ var refEntryNdx = refLayout.getUniformIndex(cmpEntry.name);
+
+ if (refEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + cmpEntry.name + "' not found in reference layout");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[refEntryNdx];
+
+ // \todo [2012-11-26 pyry] Should we check other properties as well?
+ if (refEntry.type != cmpEntry.type) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform type mismatch in '" + refEntry.name + "':</br>" +
+ "' expected: '" + gluShaderUtil.getDataTypeName(refEntry.type) + "'</br>" +
+ "' got: '" + gluShaderUtil.getDataTypeName(cmpEntry.type) + "'");
+ isOk = false;
+ }
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/** checkLayoutIndices
+* @param {glsUniformBlockCase.UniformLayout} layout Layout whose indices are to be checked
+* @return {boolean} true if all is ok
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkLayoutIndices = function(layout) {
+ /** @type {number} */ var numUniforms = layout.uniforms.length;
+ /** @type {number} */ var numBlocks = layout.blocks.length;
+ /** @type {boolean} */ var isOk = true;
+
+ // Check uniform block indices.
+ for (var uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var uniform = layout.uniforms[uniformNdx];
+
+ if (uniform.blockNdx < 0 || !deMath.deInBounds32(uniform.blockNdx, 0, numBlocks)) {
+ bufferedLogToConsole("Error: Invalid block index in uniform '" + uniform.name + "'");
+ isOk = false;
+ }
+ }
+
+ // Check active uniforms.
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var block = layout.blocks[blockNdx];
+
+ for (var uniformNdx = 0; uniformNdx < block.activeUniformIndices.length; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var activeUniformNdx = block.activeUniformIndices[uniformNdx];
+ if (!deMath.deInBounds32(activeUniformNdx, 0, numUniforms)) {
+ bufferedLogToConsole('Error: Invalid active uniform index ' + activeUniformNdx + " in block '" + block.name);
+ isOk = false;
+ }
+ }
+ }
+ return isOk;
+};
+
+/** checkLayoutBounds
+* @param {glsUniformBlockCase.UniformLayout} layout The uniform layout to check
+* @return {boolean} true if all is within bounds
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkLayoutBounds = function(layout) {
+ /** @type {number} */ var numUniforms = layout.uniforms.length;
+ /** @type {boolean}*/ var isOk = true;
+
+ for (var uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry}*/ var uniform = layout.uniforms[uniformNdx];
+
+ if (uniform.blockNdx < 0)
+ continue;
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry}*/ var block = layout.blocks[uniform.blockNdx];
+ /** @type {boolean}*/ var isMatrix = gluShaderUtil.isDataTypeMatrix(uniform.type);
+ /** @type {number}*/ var numVecs = isMatrix ? (uniform.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(uniform.type) : gluShaderUtil.getDataTypeMatrixNumColumns(uniform.type)) : 1;
+ /** @type {number}*/ var numComps = isMatrix ? (uniform.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(uniform.type) : gluShaderUtil.getDataTypeMatrixNumRows(uniform.type)) : gluShaderUtil.getDataTypeScalarSize(uniform.type);
+ /** @type {number}*/ var numElements = uniform.size;
+ /** @type {number}*/ var compSize = deMath.INT32_SIZE;
+ /** @type {number}*/ var vecSize = numComps * compSize;
+
+ /** @type {number}*/ var minOffset = 0;
+ /** @type {number}*/ var maxOffset = 0;
+
+ // For negative strides.
+ minOffset = Math.min(minOffset, (numVecs - 1) * uniform.matrixStride);
+ minOffset = Math.min(minOffset, (numElements - 1) * uniform.arrayStride);
+ minOffset = Math.min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
+
+ maxOffset = Math.max(maxOffset, vecSize);
+ maxOffset = Math.max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
+ maxOffset = Math.max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
+ maxOffset = Math.max(maxOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
+
+ if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + uniform.name + "' out of block bounds");
+ isOk = false;
+ }
+ }
+
+ return isOk;
+};
+
+/** checkIndexQueries
+* @param {WebGLProgram} program The shader program to be checked against
+* @param {glsUniformBlockCase.UniformLayout} layout The layout to check
+* @return {boolean} true if everything matches.
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkIndexQueries = function(program, layout) {
+ /** @type {boolean}*/ var allOk = true;
+
+ // \note Spec mandates that uniform blocks are assigned consecutive locations from 0
+ // to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in glsUniformBlockCase.UniformLayout.
+ for (var blockNdx = 0; blockNdx < layout.blocks.length; blockNdx++) {
+ /** @const */ var block = layout.blocks[blockNdx];
+ /** @const */ var queriedNdx = gl.getUniformBlockIndex(program, block.name);
+
+ if (queriedNdx != blockNdx) {
+ bufferedLogToConsole('ERROR: glGetUniformBlockIndex(' + block.name + ') returned ' + queriedNdx + ', expected ' + blockNdx + '!');
+ allOk = false;
+ }
+ }
+
+ return allOk;
+};
+
+/** @const @type {number} */ glsUniformBlockCase.VIEWPORT_WIDTH = 128;
+/** @const @type {number} */ glsUniformBlockCase.VIEWPORT_HEIGHT = 128;
+
+/** Renders a white square, and then tests all pixels are
+* effectively white in the color buffer.
+* @param {gluShaderProgram.ShaderProgram} program The shader program to use.
+* @return {boolean} false if there was at least one incorrect pixel
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.render = function(program) {
+ // Compute viewport.
+ /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
+ /** @const */ var viewportW = Math.min(gl.canvas.width, glsUniformBlockCase.VIEWPORT_WIDTH);
+ /** @const */ var viewportH = Math.min(gl.canvas.height, glsUniformBlockCase.VIEWPORT_HEIGHT);
+ /** @const */ var viewportX = rnd.getInt(0, gl.canvas.width);
+ /** @const */ var viewportY = rnd.getInt(0, gl.canvas.height);
+
+ gl.clearColor(0.125, 0.25, 0.5, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ //Draw
+ var position = [
+ -1.0, -1.0, 0.0, 1.0,
+ -1.0, 1.0, 0.0, 1.0,
+ 1.0, -1.0, 0.0, 1.0,
+ 1.0, 1.0, 0.0, 1.0
+ ];
+ var indices = [0, 1, 2, 2, 1, 3];
+
+ gl.viewport(viewportX, viewportY, viewportW, viewportH);
+
+ // Access
+ var posLoc = gl.getAttribLocation(program.getProgram(), 'a_position');
+ var posArray = [new gluDrawUtil.VertexArrayBinding(gl.FLOAT, posLoc, 4, 4, position)];
+ gluDrawUtil.draw(gl, program.getProgram(), posArray, gluDrawUtil.triangles(indices));
+
+ // Verify that all pixels are white.
+ var pixels = new gluDrawUtil.Surface();
+ var numFailedPixels = 0;
+
+ var readPixelsX = (viewportX + viewportW) > gl.canvas.width
+ ? (gl.canvas.width - viewportX) : viewportW;
+ var readPixelsY = (viewportY + viewportH) > gl.canvas.height
+ ? (gl.canvas.height - viewportY) : viewportH;
+
+ var buffer = pixels.readSurface(gl, viewportX, viewportY, readPixelsX, readPixelsY);
+
+ var whitePixel = new gluDrawUtil.Pixel([255.0, 255.0, 255.0, 255.0]);
+ for (var y = 0; y < readPixelsY; y++) {
+ for (var x = 0; x < readPixelsX; x++) {
+ if (!pixels.getPixel(x, y).equals(whitePixel))
+ numFailedPixels += 1;
+ }
+ }
+
+ if (numFailedPixels > 0) {
+ bufferedLogToConsole('Image comparison failed, got ' + numFailedPixels + ' non-white pixels.');
+ }
+
+ return numFailedPixels == 0;
+};
+
+});