diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl')
17 files changed, 11780 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js new file mode 100644 index 0000000000..baa05a9708 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js @@ -0,0 +1,510 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluDrawUtil'); +goog.require('framework.opengl.gluShaderProgram'); + +goog.scope(function() { + +var gluDrawUtil = framework.opengl.gluDrawUtil; +var gluShaderProgram = framework.opengl.gluShaderProgram; + +/** + * Description of a vertex array binding + * @constructor + * @param {number} type GL gluDrawUtil.Type of data + * @param {(number|undefined)} location Binding location + * @param {number} components Number of components per vertex + * @param {number} elements Number of elements in the array + * @param {Array<number>} data Source data + * @param {number=} stride + * @param {number=} offset + */ +gluDrawUtil.VertexArrayBinding = function(type, location, components, elements, data, stride, offset) { + this.type = type; + this.location = location === undefined ? -1 : location; + this.components = components; + this.elements = elements; + this.data = data; + /** @type {?string} */ this.name = null; + this.stride = stride || 0; + this.offset = offset || 0; +}; + +/** + * Description of a vertex array binding + * @param {gluDrawUtil.BindingPoint} binding + * @param {gluDrawUtil.VertexArrayPointer} pointer + * @param {number=} dataType GL Data Type + * @return {gluDrawUtil.VertexArrayBinding} + */ +gluDrawUtil.vabFromBindingPointAndArrayPointer = function(binding, pointer, dataType) { + var type = dataType === undefined ? gl.FLOAT : dataType; + var location = binding.location; + var components = pointer.numComponents; + var elements = pointer.numElements; + var data = pointer.data; + var vaBinding = new gluDrawUtil.VertexArrayBinding(type, location, components, elements, data); + vaBinding.componentType = pointer.componentType; + vaBinding.name = binding.name; + vaBinding.convert = pointer.convert; + vaBinding.stride = pointer.stride; + return vaBinding; +}; + +/** + * ! Lower named bindings to locations and eliminate bindings that are not used by program. + * @param {WebGL2RenderingContext} gl WebGL context + * @param {WebGLProgram} program + * @param {Array} inputArray - Array with the named binding locations + * @param {Array=} outputArray - Array with the lowered locations + * @return {Array} outputArray + */ +gluDrawUtil.namedBindingsToProgramLocations = function(gl, program, inputArray, outputArray) { + outputArray = outputArray || []; + + for (var i = 0; i < inputArray.length; i++) { + var cur = inputArray[i]; + if (cur.name) { + //assert(binding.location >= 0); + var location = gl.getAttribLocation(program, cur.name); + if (location >= 0) { + if (cur.location >= 0) + location += cur.location; + // Add binding.location as an offset to accomodate matrices. + outputArray.push(new gluDrawUtil.VertexArrayBinding(cur.type, location, cur.components, cur.elements, cur.data, cur.stride, cur.offset)); + } + } else { + outputArray.push(cur); + } + } + + return outputArray; +}; + +/** + * Creates vertex buffer, binds it and draws elements + * @param {WebGL2RenderingContext} gl WebGL context + * @param {WebGLProgram} program ID, vertexProgramID + * @param {Array<gluDrawUtil.VertexArrayBinding>} vertexArrays + * @param {gluDrawUtil.PrimitiveList} primitives to gluDrawUtil.draw + * @param { {beforeDrawCall:function(), afterDrawCall:function()}=} callback + */ +gluDrawUtil.draw = function(gl, program, vertexArrays, primitives, callback) { + /** TODO: finish implementation */ + /** @type {Array<WebGLBuffer>} */ var objects = []; + + // Lower bindings to locations + vertexArrays = gluDrawUtil.namedBindingsToProgramLocations(gl, program, vertexArrays); + + for (var i = 0; i < vertexArrays.length; i++) { + /** @type {WebGLBuffer} */ var buffer = gluDrawUtil.vertexBuffer(gl, vertexArrays[i]); + objects.push(buffer); + } + + if (primitives.indices) { + /** @type {WebGLBuffer} */ var elemBuffer = gluDrawUtil.indexBuffer(gl, primitives); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer); + + if (callback) + callback.beforeDrawCall(); + + gluDrawUtil.drawIndexed(gl, primitives, 0); + + if (callback) + callback.afterDrawCall(); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + } else { + if (callback) + callback.beforeDrawCall(); + + gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, primitives.type), 0, primitives.numElements); + + if (callback) + callback.afterDrawCall(); + } + + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'drawArrays', false, true); + for (var i = 0; i < vertexArrays.length; i++) { + gl.disableVertexAttribArray(vertexArrays[i].location); + } + gl.bindBuffer(gl.ARRAY_BUFFER, null); +}; + +/** + * Creates vertex buffer, binds it and draws elements + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluDrawUtil.PrimitiveList} primitives Primitives to gluDrawUtil.draw + * @param {number} offset + */ +gluDrawUtil.drawIndexed = function(gl, primitives, offset) { +/** @type {number} */ var mode = gluDrawUtil.getPrimitiveGLType(gl, primitives.type); + /** TODO: C++ implementation supports different index types, we use only int16. + Could it cause any issues? + + deUint32 indexGLType = getIndexGLType(primitives.indexType); + */ + + gl.drawElements(mode, primitives.indices.length, gl.UNSIGNED_SHORT, offset); +}; + +/** + * Enums for primitive types + * @enum + */ +gluDrawUtil.primitiveType = { + TRIANGLES: 0, + TRIANGLE_STRIP: 1, + TRIANGLE_FAN: 2, + + LINES: 3, + LINE_STRIP: 4, + LINE_LOOP: 5, + + POINTS: 6, + + PATCHES: 7 +}; + +/** + * get GL type from primitive type + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType + * @return {number} GL primitive type + */ +gluDrawUtil.getPrimitiveGLType = function(gl, type) { + switch (type) { + case gluDrawUtil.primitiveType.TRIANGLES: return gl.TRIANGLES; + case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return gl.TRIANGLE_STRIP; + case gluDrawUtil.primitiveType.TRIANGLE_FAN: return gl.TRIANGLE_FAN; + case gluDrawUtil.primitiveType.LINES: return gl.LINES; + case gluDrawUtil.primitiveType.LINE_STRIP: return gl.LINE_STRIP; + case gluDrawUtil.primitiveType.LINE_LOOP: return gl.LINE_LOOP; + case gluDrawUtil.primitiveType.POINTS: return gl.POINTS; +// case gluDrawUtil.primitiveType.PATCHES: return gl.PATCHES; + default: + throw new Error('Unknown primitive type ' + type); + } +}; + +/** + * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Points + * @param {number} numElements + */ +gluDrawUtil.pointsFromElements = function(numElements) { + return new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.POINTS, numElements); +}; + +/** + * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Triangles + * @param {Array<number>} indices + */ +gluDrawUtil.triangles = function(indices) { + return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.TRIANGLES, indices); +}; + +/** + * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Patches + * @param {Array<number>} indices + */ +gluDrawUtil.patches = function(indices) { + return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.PATCHES, indices); +}; + +/** + * Creates primitive list for Triangles or Patches, depending on type + * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType + * @param {number} numElements + * @constructor + */ +gluDrawUtil.PrimitiveList = function(type, numElements) { + this.type = type; + this.indices = 0; + this.numElements = numElements; +}; + +/** + * @param {gluDrawUtil.primitiveType} type + * @param {Array<number>} indices + * @return {gluDrawUtil.PrimitiveList} + */ +gluDrawUtil.newPrimitiveListFromIndices = function(type, indices) { + /** @type {gluDrawUtil.PrimitiveList} */ var primitiveList = new gluDrawUtil.PrimitiveList(type, 0); + primitiveList.indices = indices; + return primitiveList; +}; + +/** + * Create Element Array Buffer + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluDrawUtil.PrimitiveList} primitives to construct the buffer from + * @return {WebGLBuffer} indexObject buffer with elements + */ +gluDrawUtil.indexBuffer = function(gl, primitives) { + /** @type {WebGLBuffer} */ var indexObject = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(primitives.indices), gl.STATIC_DRAW); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + return indexObject; +}; + +/** + * Create Array Buffer + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluDrawUtil.VertexArrayBinding} vertexArray primitives, Array buffer descriptor + * @return {WebGLBuffer} buffer of vertices + */ +gluDrawUtil.vertexBuffer = function(gl, vertexArray) { + /** @type {goog.TypedArray} */ var typedArray; + switch (vertexArray.type) { + case gl.BYTE: typedArray = new Int8Array(vertexArray.data); break; + case gl.UNSIGNED_BYTE: typedArray = new Uint8Array(vertexArray.data); break; + case gl.SHORT: typedArray = new Int16Array(vertexArray.data); break; + case gl.UNSIGNED_SHORT: typedArray = new Uint16Array(vertexArray.data); break; + case gl.INT: typedArray = new Int32Array(vertexArray.data); break; + case gl.UNSIGNED_INT: typedArray = new Uint32Array(vertexArray.data); break; + default: typedArray = new Float32Array(vertexArray.data); break; + } + + /** @type {WebGLBuffer} */ var buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true); + gl.bufferData(gl.ARRAY_BUFFER, typedArray, gl.STATIC_DRAW); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true); + gl.enableVertexAttribArray(vertexArray.location); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'enableVertexAttribArray', false, true); + if (vertexArray.type === gl.FLOAT) { + gl.vertexAttribPointer(vertexArray.location, vertexArray.components, vertexArray.type, false, vertexArray.stride, vertexArray.offset); + } else { + gl.vertexAttribIPointer(vertexArray.location, vertexArray.components, vertexArray.type, vertexArray.stride, vertexArray.offset); + } + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'vertexAttribPointer', false, true); + return buffer; +}; + +/** + * @param {Array<number>} rgba + * @constructor + */ +gluDrawUtil.Pixel = function(rgba) { + this.rgba = rgba; +}; + +gluDrawUtil.Pixel.prototype.getRed = function() { + return this.rgba[0]; +}; +gluDrawUtil.Pixel.prototype.getGreen = function() { + return this.rgba[1]; +}; +gluDrawUtil.Pixel.prototype.getBlue = function() { + return this.rgba[2]; +}; +gluDrawUtil.Pixel.prototype.getAlpha = function() { + return this.rgba[3]; +}; +gluDrawUtil.Pixel.prototype.equals = function(otherPixel) { + return this.rgba[0] == otherPixel.rgba[0] && + this.rgba[1] == otherPixel.rgba[1] && + this.rgba[2] == otherPixel.rgba[2] && + this.rgba[3] == otherPixel.rgba[3]; +}; + +/** + * @constructor + */ +gluDrawUtil.Surface = function() { +}; + +gluDrawUtil.Surface.prototype.readSurface = function(gl, x, y, width, height) { + this.buffer = new Uint8Array(width * height * 4); + gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this.buffer); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + return this.buffer; +}; + +gluDrawUtil.Surface.prototype.getPixel = function(x, y) { + /** @type {number} */ var base = (x + y * this.width) * 4; + /** @type {Array<number>} */ + var rgba = [ + this.buffer[base], + this.buffer[base + 1], + this.buffer[base + 2], + this.buffer[base + 3] + ]; + return new gluDrawUtil.Pixel(rgba); +}; + +gluDrawUtil.Surface.prototype.getPixelUintRGB8 = function(x, y) { + /** @type {number} */ var base = (x + y * this.width) * 4; + /** @type {number} */ + return (this.buffer[base] << 16) + + (this.buffer[base + 1] << 8) + + this.buffer[base + 2]; +}; + +/** + * @enum + */ +gluDrawUtil.VertexComponentType = { + // Standard types: all conversion types apply. + VTX_COMP_UNSIGNED_INT8: 0, + VTX_COMP_UNSIGNED_INT16: 1, + VTX_COMP_UNSIGNED_INT32: 2, + VTX_COMP_SIGNED_INT8: 3, + VTX_COMP_SIGNED_INT16: 4, + VTX_COMP_SIGNED_INT32: 5, + + // Special types: only CONVERT_NONE is allowed. + VTX_COMP_FIXED: 6, + VTX_COMP_HALF_FLOAT: 7, + VTX_COMP_FLOAT: 8 +}; + +/** + * @enum + */ +gluDrawUtil.VertexComponentConversion = { + VTX_COMP_CONVERT_NONE: 0, //!< No conversion: integer types, or floating-point values. + VTX_COMP_CONVERT_NORMALIZE_TO_FLOAT: 1, //!< Normalize integers to range [0,1] or [-1,1] depending on type. + VTX_COMP_CONVERT_CAST_TO_FLOAT: 2 //!< Convert to floating-point directly. +}; + +/** + * gluDrawUtil.VertexArrayPointer + * @constructor + * @param {gluDrawUtil.VertexComponentType} componentType_ + * @param {gluDrawUtil.VertexComponentConversion} convert_ + * @param {number} numComponents_ + * @param {number} numElements_ + * @param {number} stride_ + * @const @param {Array<number>} data_ + */ +gluDrawUtil.VertexArrayPointer = function(componentType_, convert_, numComponents_, numElements_, stride_, data_) { + this.componentType = componentType_; + this.convert = convert_; + this.numComponents = numComponents_; + this.numElements = numElements_; + this.stride = stride_; + this.data = data_; +}; + +/** + * gluDrawUtil.BindingPoint + * @constructor + * @param {string} name + * @param {number} location + * @param {number=} offset + */ +gluDrawUtil.BindingPoint = function(name, location, offset) { + /** @type {string} */ this.name = name; + /** @type {number} */ this.location = location; + /** @type {number} */ this.offset = offset || 0; +}; + +/** + * bindingPointFromLocation + * @param {number} location + * return {gluDrawUtil.BindingPoint} + */ +gluDrawUtil.bindingPointFromLocation = function(location) { + return new gluDrawUtil.BindingPoint('', location); +}; + +/** + * bindingPointFromName + * @param {string} name + * @param {number=} location + * return {gluDrawUtil.BindingPoint} + */ +gluDrawUtil.bindingPointFromName = function(name, location) { + location = location === undefined ? -1 : location; + return new gluDrawUtil.BindingPoint(name, location); +}; + +/** + * @param {string} name + * @param {number} numComponents + * @param {number} numElements + * @param {number} stride + * @param {Array<number>} data + * @return {gluDrawUtil.VertexArrayBinding} + */ +gluDrawUtil.newInt32VertexArrayBinding = function(name, numComponents, numElements, stride, data) { + var bindingPoint = gluDrawUtil.bindingPointFromName(name); + var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_SIGNED_INT32, + gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); + return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.INT); +}; + +/** + * @param {string} name + * @param {number} numComponents + * @param {number} numElements + * @param {number} stride + * @param {Array<number>} data + * @return {gluDrawUtil.VertexArrayBinding} + */ +gluDrawUtil.newUint32VertexArrayBinding = function(name, numComponents, numElements, stride, data) { + var bindingPoint = gluDrawUtil.bindingPointFromName(name); + var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_UNSIGNED_INT32, + gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); + return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.UNSIGNED_INT); +}; + +/** + * @param {string} name + * @param {number} numComponents + * @param {number} numElements + * @param {number} stride + * @param {Array<number>} data + * @return {gluDrawUtil.VertexArrayBinding} + */ +gluDrawUtil.newFloatVertexArrayBinding = function(name, numComponents, numElements, stride, data) { + var bindingPoint = gluDrawUtil.bindingPointFromName(name); + var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT, + gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); + return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer); +}; + +/** + * @param {string} name + * @param {number} column + * @param {number} rows + * @param {number} numElements + * @param {number} stride + * @param {Array<number>} data + * @return {gluDrawUtil.VertexArrayBinding} + */ +gluDrawUtil.newFloatColumnVertexArrayBinding = function(name, column, rows, numElements, stride, data) { + var bindingPoint = gluDrawUtil.bindingPointFromName(name); + bindingPoint.location = column; + var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT, + gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, rows, numElements, stride, data); + return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer); +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js new file mode 100644 index 0000000000..38f8a28f9c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluObjectWrapper'); + +goog.scope(function() { + var gluObjectWrapper = framework.opengl.gluObjectWrapper; + + /** + * @typedef {function(this:WebGLRenderingContextBase): WebGLObject} + */ + gluObjectWrapper.funcGenT; + + /** + * @typedef {function(this:WebGLRenderingContextBase, WebGLObject)} + */ + gluObjectWrapper.funcDelT; + + /** + * @typedef {{name: string, funcGen: !gluObjectWrapper.funcGenT, funcDel: !gluObjectWrapper.funcDelT}} + */ + gluObjectWrapper.traitsT; + + /** + * Returns an object containing a configuration for an ObjectWrapper + * @param {string} name + * @param {gluObjectWrapper.funcGenT} funcGen + * @param {gluObjectWrapper.funcDelT} funcDel + * @return {gluObjectWrapper.traitsT} + */ + gluObjectWrapper.traits = function(name, funcGen, funcDel) { + return { + name: name, + funcGen: funcGen, + funcDel: funcDel + }; + }; + + /** + * @constructor + * @param {WebGLRenderingContextBase} gl + * @param {gluObjectWrapper.traitsT} traits + */ + gluObjectWrapper.ObjectWrapper = function(gl, traits) { + /** + * @protected + * @type {WebGLRenderingContextBase} + */ + this.m_gl = gl; + + /** + * @protected + * @type {gluObjectWrapper.traitsT} + */ + this.m_traits = traits; + + /** + * @protected + * @type {WebGLObject} + */ + this.m_object = this.m_traits.funcGen.call(gl); + + }; + + /** + * Destorys the WebGLObject associated with this object. + */ + gluObjectWrapper.ObjectWrapper.prototype.clear = function() { + this.m_traits.funcDel.call(this.m_gl, this.m_object); + }; + + /** + * Returns the WebGLObject associated with this object. + * @return {WebGLObject} + */ + gluObjectWrapper.ObjectWrapper.prototype.get = function() { + return this.m_object; + }; + + /** + * @constructor + * @extends {gluObjectWrapper.ObjectWrapper} + * @param {WebGLRenderingContextBase} gl + */ + gluObjectWrapper.Framebuffer = function(gl) { + gluObjectWrapper.ObjectWrapper.call(this, gl, gluObjectWrapper.traits( + 'framebuffer', + /** @type {gluObjectWrapper.funcGenT} */(gl.createFramebuffer), + /** @type {gluObjectWrapper.funcDelT} */(gl.deleteFramebuffer) + )); + }; + gluObjectWrapper.Framebuffer.prototype = Object.create(gluObjectWrapper.ObjectWrapper.prototype); + gluObjectWrapper.Framebuffer.prototype.constructor = gluObjectWrapper.Framebuffer; + + /** + * @return {WebGLFramebuffer} + */ + gluObjectWrapper.Framebuffer.prototype.get; +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js new file mode 100644 index 0000000000..04b81a2a1a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluPixelTransfer'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.opengl.gluTextureUtil'); + +goog.scope(function() { + +var gluPixelTransfer = framework.opengl.gluPixelTransfer; +var tcuTexture = framework.common.tcuTexture; +var deMath = framework.delibs.debase.deMath; +var gluTextureUtil = framework.opengl.gluTextureUtil; + +gluPixelTransfer.getTransferAlignment = function(format) { + var pixelSize = format.getPixelSize(); + if (deMath.deIsPowerOfTwo32(pixelSize)) + return Math.min(pixelSize, 8); + else + return 1; +}; + +gluPixelTransfer.readPixels = function(ctx, x, y, format, dst) { + var width = dst.getWidth(); + var height = dst.getHeight(); + var arrayType = tcuTexture.getTypedArray(format.type); + var transferFormat = gluTextureUtil.getTransferFormat(format); + ctx.pixelStorei(ctx.PACK_ALIGNMENT, gluPixelTransfer.getTransferAlignment(format)); + var resultPixel = dst.getAccess().getDataPtr(); + resultPixel = new arrayType(dst.getAccess().getBuffer()); + ctx.readPixels(x, y, width, height, transferFormat.format, transferFormat.dataType, resultPixel); +}; + +/* TODO: implement other functions in C++ file */ + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js new file mode 100644 index 0000000000..0c340ee380 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js @@ -0,0 +1,488 @@ +/*------------------------------------------------------------------------- + * drawElements Quality gluShaderProgram.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('framework.opengl.gluShaderProgram'); + +goog.scope(function() { + +var gluShaderProgram = framework.opengl.gluShaderProgram; + +/** + * gluShaderProgram.Shader type enum + * @enum {number} + */ +gluShaderProgram.shaderType = { + VERTEX: 0, + FRAGMENT: 1 +}; + +/** + * gluShaderProgram.Shader type enum name + * @param {gluShaderProgram.shaderType} shaderType + * @return {string} + */ +gluShaderProgram.getShaderTypeName = function(shaderType) { + var s_names = + [ + 'vertex', + 'fragment' + ]; + + return s_names[shaderType]; +}; + +/** + * Get GL shader type from gluShaderProgram.shaderType + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluShaderProgram.shaderType} type gluShaderProgram.Shader Type + * @return {number} GL shader type + */ +gluShaderProgram.getGLShaderType = function(gl, type) { + var _glShaderType; + switch (type) { + case gluShaderProgram.shaderType.VERTEX: _glShaderType = gl.VERTEX_SHADER; break; + case gluShaderProgram.shaderType.FRAGMENT: _glShaderType = gl.FRAGMENT_SHADER; break; + default: + throw new Error('Unknown shader type ' + type); + } + return _glShaderType; +}; + +/** + * Declares shader information + * @constructor + * @param {gluShaderProgram.shaderType} type + * @param {string=} source + */ +gluShaderProgram.ShaderInfo = function(type, source) { + this.type = type; /** gluShaderProgram.Shader type. */ + this.source = source; /** gluShaderProgram.Shader source. */ + this.infoLog; /** Compile info log. */ + this.compileOk = false; /** Did compilation succeed? */ + this.compileTimeUs = 0; /** Compile time in microseconds (us). */ +}; + +/** + * Generates vertex shader info from source + * @param {string} source + * @return {gluShaderProgram.ShaderInfo} vertex shader info + */ +gluShaderProgram.genVertexSource = function(source) { +/** @type {gluShaderProgram.ShaderInfo} */ var shader = new gluShaderProgram.ShaderInfo(gluShaderProgram.shaderType.VERTEX, source); + return shader; +}; + +/** + * Generates fragment shader info from source + * @param {string} source + * @return {gluShaderProgram.ShaderInfo} fragment shader info + */ +gluShaderProgram.genFragmentSource = function(source) { +/** @type {gluShaderProgram.ShaderInfo} */ var shader = new gluShaderProgram.ShaderInfo(gluShaderProgram.shaderType.FRAGMENT, source); + return shader; +}; + +/** + * Generates shader from WebGL context and type + * @constructor + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluShaderProgram.shaderType} type gluShaderProgram.Shader Type + */ +gluShaderProgram.Shader = function(gl, type) { + this.gl = gl; + this.info = new gluShaderProgram.ShaderInfo(type); /** Client-side clone of state for debug / perf reasons. */ + this.shader = gl.createShader(gluShaderProgram.getGLShaderType(gl, type)); + assertMsgOptions(gl.getError() == gl.NO_ERROR, 'gl.createShader()', false, true); + + this.setSources = function(source) { + this.gl.shaderSource(this.shader, source); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'glshaderSource()', false, true); + this.info.source = source; + }; + + this.getCompileStatus = function() { + return this.info.compileOk; + }; + + this.compile = function() { + this.info.compileOk = false; + this.info.compileTimeUs = 0; + this.info.infoLog = ''; + + /** @type {Date} */ var compileStart = new Date(); + this.gl.compileShader(this.shader); + /** @type {Date} */ var compileEnd = new Date(); + this.info.compileTimeUs = 1000 * (compileEnd.getTime() - compileStart.getTime()); + + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.compileShader()', false, true); + + var compileStatus = this.gl.getShaderParameter(this.shader, this.gl.COMPILE_STATUS); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'glGetShaderParameter()', false, true); + + this.info.compileOk = compileStatus; + this.info.infoLog = this.gl.getShaderInfoLog(this.shader); + }; + + this.getShader = function() { + return this.shader; + }; + + this.destroy = function() { + this.gl.deleteShader(this.shader); + }; + +}; +/** + * Creates gluShaderProgram.ProgramInfo + * @constructor + */ +gluShaderProgram.ProgramInfo = function() { + /** @type {string} */ this.infoLog = ''; /** Link info log. */ + /** @type {boolean} */ this.linkOk = false; /** Did link succeed? */ + /** @type {number} */ this.linkTimeUs = 0; /** Link time in microseconds (us). */ +}; + +/** + * Creates program. + * Inner methods: attach shaders, bind attributes location, link program and transform Feedback Varyings + * @constructor + * @param {WebGL2RenderingContext} gl WebGL context + * @param {WebGLProgram=} programID + */ +gluShaderProgram.Program = function(gl, programID) { + this.gl = gl; + this.program = programID || null; + this.info = new gluShaderProgram.ProgramInfo(); + + if (!programID) { + this.program = gl.createProgram(); + assertMsgOptions(gl.getError() == gl.NO_ERROR, 'gl.createProgram()', false, true); + } +}; + +/** + * @return {WebGLProgram} + */ +gluShaderProgram.Program.prototype.getProgram = function() { return this.program; }; + +/** + * @return {gluShaderProgram.ProgramInfo} + */ +gluShaderProgram.Program.prototype.getInfo = function() { return this.info; }; + +/** + * @param {WebGLShader} shader + */ +gluShaderProgram.Program.prototype.attachShader = function(shader) { + this.gl.attachShader(this.program, shader); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.attachShader()', false, true); +}; + +/** + * @param {WebGLShader} shader + */ +gluShaderProgram.Program.prototype.detachShader = function(shader) { + this.gl.detachShader(this.program, shader); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.detachShader()', false, true); +}; + +/** + * @param {number} location + * @param {string} name + */ +gluShaderProgram.Program.prototype.bindAttribLocation = function(location, name) { + this.gl.bindAttribLocation(this.program, location, name); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.bindAttribLocation()', false, true); +}; + +gluShaderProgram.Program.prototype.link = function() { + this.info.linkOk = false; + this.info.linkTimeUs = 0; + this.info.infoLog = ''; + + /** @type {Date} */ var linkStart = new Date(); + this.gl.linkProgram(this.program); + /** @type {Date} */ var linkEnd = new Date(); + this.info.linkTimeUs = 1000 * (linkEnd.getTime() - linkStart.getTime()); + + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.linkProgram()', false, true); + + var linkStatus = this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.getProgramParameter()', false, true); + this.info.linkOk = linkStatus; + this.info.infoLog = this.gl.getProgramInfoLog(this.program); + if (!this.info.linkOk) + bufferedLogToConsole("program linking: " + this.info.infoLog); +}; + +/** + * return {boolean} + */ +gluShaderProgram.Program.prototype.getLinkStatus = function() { + return this.info.linkOk; +}; + +/** + * @param {Array<string>} varyings + * @param {number} bufferMode + */ +gluShaderProgram.Program.prototype.transformFeedbackVaryings = function(varyings, bufferMode) { + this.gl.transformFeedbackVaryings(this.program, varyings, bufferMode); + assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.transformFeedbackVaryings()', false, true); +}; + +/** + * Assigns gl WebGL context and programSources. Declares array of shaders and new program() + * @constructor + * @param {WebGL2RenderingContext} gl WebGL context + * @param {gluShaderProgram.ProgramSources} programSources + */ +gluShaderProgram.ShaderProgram = function(gl, programSources) { + this.gl = gl; + this.programSources = programSources; + this.shaders = []; + this.program = new gluShaderProgram.Program(gl); + + /** @type {boolean} */ this.shadersOK = true; + + for (var i = 0; i < programSources.sources.length; i++) { + /** @type {gluShaderProgram.Shader} */ var shader = new gluShaderProgram.Shader(gl, programSources.sources[i].type); + shader.setSources(programSources.sources[i].source); + shader.compile(); + this.shaders.push(shader); + this.shadersOK = this.shadersOK && shader.getCompileStatus(); + if (!shader.getCompileStatus()) { + bufferedLogToConsole('gluShaderProgram.Shader:\n' + programSources.sources[i].source); + bufferedLogToConsole('Compile status: ' + shader.getCompileStatus()); + bufferedLogToConsole('Shader infoLog: ' + shader.info.infoLog); + } + } + + if (this.shadersOK) { + for (var i = 0; i < this.shaders.length; i++) + this.program.attachShader(this.shaders[i].getShader()); + + for (var attrib in programSources.attribLocationBindings) + this.program.bindAttribLocation(programSources.attribLocationBindings[attrib], attrib); + + if (programSources.transformFeedbackBufferMode) + if (programSources.transformFeedbackBufferMode === gl.NONE) + assertMsgOptions(programSources.transformFeedbackVaryings.length === 0, 'Transform feedback sanity check', false, true); + else + this.program.transformFeedbackVaryings(programSources.transformFeedbackVaryings, programSources.transformFeedbackBufferMode); + + /* TODO: GLES 3.1: set separable flag */ + + this.program.link(); + + } +}; + +/** + * return {WebGLProgram} + */ +gluShaderProgram.ShaderProgram.prototype.getProgram = function() { + return this.program.program; + }; + +/** + * @return {gluShaderProgram.ProgramInfo} + */ +gluShaderProgram.ShaderProgram.prototype.getProgramInfo = function() { + return this.program.info; +}; + +gluShaderProgram.ShaderProgram.prototype.isOk = function() { + return this.shadersOK && this.program.getLinkStatus(); +}; + +gluShaderProgram.containerTypes = { + ATTRIB_LOCATION_BINDING: 0, + TRANSFORM_FEEDBACK_MODE: 1, + TRANSFORM_FEEDBACK_VARYING: 2, + TRANSFORM_FEEDBACK_VARYINGS: 3, + SHADER_SOURCE: 4, + PROGRAM_SEPARABLE: 5, + PROGRAM_SOURCES: 6, + + CONTAINER_TYPE_LAST: 7, + ATTACHABLE_BEGIN: 0, // ATTRIB_LOCATION_BINDING + ATTACHABLE_END: 5 + 1 // PROGRAM_SEPARABLE + 1 +}; + +/** + * @constructor + */ +gluShaderProgram.AttribLocationBinding = function(name, location) { + this.name = name; + this.location = location; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.ATTRIB_LOCATION_BINDING; + }; +}; + +/** + * @constructor + */ +gluShaderProgram.TransformFeedbackMode = function(mode) { + this.mode = mode; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_MODE; + }; +}; + +/** + * @constructor + * @param {string} name + */ +gluShaderProgram.TransformFeedbackVarying = function(name) { + /** @type {string} */ this.name = name; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYING; + }; +}; + +/** + * @constructor + * @param {Array<string>} array + */ +gluShaderProgram.TransformFeedbackVaryings = function(array) { + /** @type {Array<string>} */ this.array = array; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYINGS; + }; +}; + +/** + * @constructor + */ +gluShaderProgram.ProgramSeparable = function(separable) { + this.separable = separable; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.PROGRAM_SEPARABLE; + }; +}; + +/** + * @constructor + */ +gluShaderProgram.VertexSource = function(str) { + this.shaderType = gluShaderProgram.shaderType.VERTEX; + this.source = str; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.SHADER_SOURCE; + }; +}; + +/** + * @constructor + */ +gluShaderProgram.FragmentSource = function(str) { + this.shaderType = gluShaderProgram.shaderType.FRAGMENT; + this.source = str; + + this.getContainerType = function() { + return gluShaderProgram.containerTypes.SHADER_SOURCE; + }; +}; + +/** + * Create gluShaderProgram.ProgramSources. + * @constructor + */ +gluShaderProgram.ProgramSources = function() { + /** @type {Array<gluShaderProgram.ShaderInfo>} */ this.sources = []; + this.attribLocationBindings = []; + /** @type {Array<string>} */ this.transformFeedbackVaryings = []; + this.transformFeedbackBufferMode = 0; + this.separable = false; +}; + +gluShaderProgram.ProgramSources.prototype.getContainerType = function() { + return gluShaderProgram.containerTypes.PROGRAM_SOURCES; +}; + +gluShaderProgram.ProgramSources.prototype.add = function(item) { + var type = undefined; + if (typeof(item.getContainerType) == 'function') { + type = item.getContainerType(); + if ( + typeof(type) != 'number' || + type < gluShaderProgram.containerTypes.ATTACHABLE_BEGIN || + type >= gluShaderProgram.containerTypes.ATTACHABLE_END + ) { + type = undefined; + } + } + + switch (type) { + case gluShaderProgram.containerTypes.ATTRIB_LOCATION_BINDING: + this.attribLocationBindings.push(item); + break; + + case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_MODE: + this.transformFeedbackBufferMode = item.mode; + break; + + case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYING: + this.transformFeedbackVaryings.push(item.name); + break; + + case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYINGS: + this.transformFeedbackVaryings = this.transformFeedbackVaryings.concat(item.array); + break; + + case gluShaderProgram.containerTypes.SHADER_SOURCE: + this.sources.push(new gluShaderProgram.ShaderInfo(item.shaderType, item.source)); + break; + + case gluShaderProgram.containerTypes.PROGRAM_SEPARABLE: + this.separable = item.separable; + break; + + default: + throw new Error('Type \"' + type + '\" cannot be added to gluShaderProgram.ProgramSources.'); + break; + } + + return this; +}; + +/** + * //! Helper for constructing vertex-fragment source pair. + * @param {string} vertexSrc + * @param {string} fragmentSrc + * @return {gluShaderProgram.ProgramSources} + */ +gluShaderProgram.makeVtxFragSources = function(vertexSrc, fragmentSrc) { + /** @type {gluShaderProgram.ProgramSources} */ var sources = new gluShaderProgram.ProgramSources(); + sources.sources.push(gluShaderProgram.genVertexSource(vertexSrc)); + sources.sources.push(gluShaderProgram.genFragmentSource(fragmentSrc)); + return sources; +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js new file mode 100644 index 0000000000..1604dbc613 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js @@ -0,0 +1,795 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluShaderUtil'); +goog.require('framework.delibs.debase.deMath'); + +goog.scope(function() { + +var gluShaderUtil = framework.opengl.gluShaderUtil; +var deMath = framework.delibs.debase.deMath; + +/** + * ShadingLanguageVersion + * @enum + */ +gluShaderUtil.GLSLVersion = { + V100_ES: 0, //!< GLSL ES 1.0 + V300_ES: 1 //!< GLSL ES 3.0 +}; + +/** + * gluShaderUtil.glslVersionUsesInOutQualifiers + * @param {gluShaderUtil.GLSLVersion} version + * @return {boolean} + */ +gluShaderUtil.glslVersionUsesInOutQualifiers = function(version) { + return version == gluShaderUtil.GLSLVersion.V300_ES; +}; + +/** + * gluShaderUtil.isGLSLVersionSupported + * @param {WebGL2RenderingContext|WebGLRenderingContextBase} ctx + * @param {gluShaderUtil.GLSLVersion} version + * @return {boolean} + */ +gluShaderUtil.isGLSLVersionSupported = function(ctx, version) { + return version <= gluShaderUtil.getGLSLVersion(ctx); +}; + +/** + * gluShaderUtil.getGLSLVersion - Returns a gluShaderUtil.GLSLVersion based on a given webgl context. + * @param {WebGL2RenderingContext|WebGLRenderingContextBase} gl + * @return {gluShaderUtil.GLSLVersion} + */ +gluShaderUtil.getGLSLVersion = function(gl) { + var glslversion = gl.getParameter(gl.SHADING_LANGUAGE_VERSION); + + // TODO: Versions are not yet well implemented... Firefox returns GLSL ES 1.0 in some cases, + // and Chromium returns GLSL ES 2.0 in some cases. Returning the right version for + // testing. + // return gluShaderUtil.GLSLVersion.V300_ES; + + if (glslversion.indexOf('WebGL GLSL ES 1.0') != -1) return gluShaderUtil.GLSLVersion.V100_ES; + if (glslversion.indexOf('WebGL GLSL ES 3.0') != -1) return gluShaderUtil.GLSLVersion.V300_ES; + + throw new Error('Invalid WebGL version'); +}; + +/** + * gluShaderUtil.getGLSLVersionDeclaration - Returns a string declaration for the glsl version in a shader. + * @param {gluShaderUtil.GLSLVersion} version + * @return {string} + */ +gluShaderUtil.getGLSLVersionDeclaration = function(version) { + /** @type {Array<string>} */ var s_decl = + [ + '#version 100', + '#version 300 es' + ]; + + if (version > s_decl.length - 1) + throw new Error('Unsupported GLSL version.'); + + return s_decl[version]; +}; + +/** + * gluShaderUtil.getGLSLVersionString - Returns the same thing as + * getGLSLVersionDeclaration() but without the substring '#version' + * @param {gluShaderUtil.GLSLVersion} version + * @return {string} + */ +gluShaderUtil.getGLSLVersionString = function(version) { + /** @type {Array<string>} */ var s_decl = + [ + '100', + '300 es' + ]; + + if (version > s_decl.length - 1) + throw new Error('Unsupported GLSL version.'); + + return s_decl[version]; +}; + +/** + * @enum + */ +gluShaderUtil.precision = { + PRECISION_LOWP: 0, + PRECISION_MEDIUMP: 1, + PRECISION_HIGHP: 2 +}; + +gluShaderUtil.getPrecisionName = function(prec) { + var s_names = [ + 'lowp', + 'mediump', + 'highp' + ]; + + return s_names[prec]; +}; + +/** + * The Type constants + * @enum {number} + */ +gluShaderUtil.DataType = { + INVALID: 0, + + FLOAT: 1, + FLOAT_VEC2: 2, + FLOAT_VEC3: 3, + FLOAT_VEC4: 4, + FLOAT_MAT2: 5, + FLOAT_MAT2X3: 6, + FLOAT_MAT2X4: 7, + FLOAT_MAT3X2: 8, + FLOAT_MAT3: 9, + FLOAT_MAT3X4: 10, + FLOAT_MAT4X2: 11, + FLOAT_MAT4X3: 12, + FLOAT_MAT4: 13, + + INT: 14, + INT_VEC2: 15, + INT_VEC3: 16, + INT_VEC4: 17, + + UINT: 18, + UINT_VEC2: 19, + UINT_VEC3: 20, + UINT_VEC4: 21, + + BOOL: 22, + BOOL_VEC2: 23, + BOOL_VEC3: 24, + BOOL_VEC4: 25, + + SAMPLER_2D: 26, + SAMPLER_CUBE: 27, + SAMPLER_2D_ARRAY: 28, + SAMPLER_3D: 29, + + SAMPLER_2D_SHADOW: 30, + SAMPLER_CUBE_SHADOW: 31, + SAMPLER_2D_ARRAY_SHADOW: 32, + + INT_SAMPLER_2D: 33, + INT_SAMPLER_CUBE: 34, + INT_SAMPLER_2D_ARRAY: 35, + INT_SAMPLER_3D: 36, + + UINT_SAMPLER_2D: 37, + UINT_SAMPLER_CUBE: 38, + UINT_SAMPLER_2D_ARRAY: 39, + UINT_SAMPLER_3D: 40 +}; + +/** + * Returns type of float scalars + * @param {gluShaderUtil.DataType} dataType + * @return {string} type of float scalar + */ +gluShaderUtil.getDataTypeFloatScalars = function(dataType) { + + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: return 'float'; + case gluShaderUtil.DataType.FLOAT_VEC2: return 'vec2'; + case gluShaderUtil.DataType.FLOAT_VEC3: return 'vec3'; + case gluShaderUtil.DataType.FLOAT_VEC4: return 'vec4'; + case gluShaderUtil.DataType.FLOAT_MAT2: return 'mat2'; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mat2x3'; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mat2x4'; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mat3x2'; + case gluShaderUtil.DataType.FLOAT_MAT3: return 'mat3'; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mat3x4'; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mat4x2'; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mat4x3'; + case gluShaderUtil.DataType.FLOAT_MAT4: return 'mat4'; + case gluShaderUtil.DataType.INT: return 'float'; + case gluShaderUtil.DataType.INT_VEC2: return 'vec2'; + case gluShaderUtil.DataType.INT_VEC3: return 'vec3'; + case gluShaderUtil.DataType.INT_VEC4: return 'vec4'; + case gluShaderUtil.DataType.UINT: return 'float'; + case gluShaderUtil.DataType.UINT_VEC2: return 'vec2'; + case gluShaderUtil.DataType.UINT_VEC3: return 'vec3'; + case gluShaderUtil.DataType.UINT_VEC4: return 'vec4'; + case gluShaderUtil.DataType.BOOL: return 'float'; + case gluShaderUtil.DataType.BOOL_VEC2: return 'vec2'; + case gluShaderUtil.DataType.BOOL_VEC3: return 'vec3'; + case gluShaderUtil.DataType.BOOL_VEC4: return 'vec4'; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * gluShaderUtil.getDataTypeVector + * @param {gluShaderUtil.DataType} scalarType + * @param {number} size + * @return {gluShaderUtil.DataType} + */ +gluShaderUtil.getDataTypeVector = function(scalarType, size) { + var floats = [gluShaderUtil.DataType.FLOAT, + gluShaderUtil.DataType.FLOAT_VEC2, + gluShaderUtil.DataType.FLOAT_VEC3, + gluShaderUtil.DataType.FLOAT_VEC4]; + var ints = [gluShaderUtil.DataType.INT, + gluShaderUtil.DataType.INT_VEC2, + gluShaderUtil.DataType.INT_VEC3, + gluShaderUtil.DataType.INT_VEC4]; + var uints = [gluShaderUtil.DataType.UINT, + gluShaderUtil.DataType.UINT_VEC2, + gluShaderUtil.DataType.UINT_VEC3, + gluShaderUtil.DataType.UINT_VEC4]; + var bools = [gluShaderUtil.DataType.BOOL, + gluShaderUtil.DataType.BOOL_VEC2, + gluShaderUtil.DataType.BOOL_VEC3, + gluShaderUtil.DataType.BOOL_VEC4]; + + switch (scalarType) { + case gluShaderUtil.DataType.FLOAT: return floats[size - 1]; + case gluShaderUtil.DataType.INT: return ints[size - 1]; + case gluShaderUtil.DataType.UINT: return uints[size - 1]; + case gluShaderUtil.DataType.BOOL: return bools[size - 1]; + default: + throw new Error('Scalar type is not a vectoe:' + scalarType); + } +}; + +/** + * gluShaderUtil.getDataTypeFloatVec + * @param {number} vecSize + * @return {gluShaderUtil.DataType} + */ +gluShaderUtil.getDataTypeFloatVec = function(vecSize) { + return gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.FLOAT, vecSize); +}; + +/** + * gluShaderUtil.isDataTypeBoolOrBVec + * @param {gluShaderUtil.DataType} dataType + * @return {boolean} + */ +gluShaderUtil.isDataTypeBoolOrBVec = function(dataType) { + return (dataType >= gluShaderUtil.DataType.BOOL) && (dataType <= gluShaderUtil.DataType.BOOL_VEC4); +}; + +/** + * Returns type of scalar + * @param {gluShaderUtil.DataType} dataType shader + * @return {string} type of scalar type + */ +gluShaderUtil.getDataTypeScalarType = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: return 'float'; + case gluShaderUtil.DataType.FLOAT_VEC2: return 'float'; + case gluShaderUtil.DataType.FLOAT_VEC3: return 'float'; + case gluShaderUtil.DataType.FLOAT_VEC4: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT2: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT3: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'float'; + case gluShaderUtil.DataType.FLOAT_MAT4: return 'float'; + case gluShaderUtil.DataType.INT: return 'int'; + case gluShaderUtil.DataType.INT_VEC2: return 'int'; + case gluShaderUtil.DataType.INT_VEC3: return 'int'; + case gluShaderUtil.DataType.INT_VEC4: return 'int'; + case gluShaderUtil.DataType.UINT: return 'uint'; + case gluShaderUtil.DataType.UINT_VEC2: return 'uint'; + case gluShaderUtil.DataType.UINT_VEC3: return 'uint'; + case gluShaderUtil.DataType.UINT_VEC4: return 'uint'; + case gluShaderUtil.DataType.BOOL: return 'bool'; + case gluShaderUtil.DataType.BOOL_VEC2: return 'bool'; + case gluShaderUtil.DataType.BOOL_VEC3: return 'bool'; + case gluShaderUtil.DataType.BOOL_VEC4: return 'bool'; + case gluShaderUtil.DataType.SAMPLER_2D: return 'sampler2D'; + case gluShaderUtil.DataType.SAMPLER_CUBE: return 'samplerCube'; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 'sampler2DArray'; + case gluShaderUtil.DataType.SAMPLER_3D: return 'sampler3D'; + case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 'sampler2DShadow'; + case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 'samplerCubeShadow'; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 'sampler2DArrayShadow'; + case gluShaderUtil.DataType.INT_SAMPLER_2D: return 'isampler2D'; + case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 'isamplerCube'; + case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 'isampler2DArray'; + case gluShaderUtil.DataType.INT_SAMPLER_3D: return 'isampler3D'; + case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 'usampler2D'; + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 'usamplerCube'; + case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 'usampler2DArray'; + case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 'usampler3D'; + } + throw new Error('Unrecognized datatype:' + dataType); +}; + +/** + * Returns type of scalar + * @param {?gluShaderUtil.DataType} dataType shader + * @return {gluShaderUtil.DataType} type of scalar type + */ +gluShaderUtil.getDataTypeScalarTypeAsDataType = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT; + case gluShaderUtil.DataType.INT: return gluShaderUtil.DataType.INT; + case gluShaderUtil.DataType.INT_VEC2: return gluShaderUtil.DataType.INT; + case gluShaderUtil.DataType.INT_VEC3: return gluShaderUtil.DataType.INT; + case gluShaderUtil.DataType.INT_VEC4: return gluShaderUtil.DataType.INT; + case gluShaderUtil.DataType.UINT: return gluShaderUtil.DataType.UINT; + case gluShaderUtil.DataType.UINT_VEC2: return gluShaderUtil.DataType.UINT; + case gluShaderUtil.DataType.UINT_VEC3: return gluShaderUtil.DataType.UINT; + case gluShaderUtil.DataType.UINT_VEC4: return gluShaderUtil.DataType.UINT; + case gluShaderUtil.DataType.BOOL: return gluShaderUtil.DataType.BOOL; + case gluShaderUtil.DataType.BOOL_VEC2: return gluShaderUtil.DataType.BOOL; + case gluShaderUtil.DataType.BOOL_VEC3: return gluShaderUtil.DataType.BOOL; + case gluShaderUtil.DataType.BOOL_VEC4: return gluShaderUtil.DataType.BOOL; + case gluShaderUtil.DataType.SAMPLER_2D: + case gluShaderUtil.DataType.SAMPLER_CUBE: + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: + case gluShaderUtil.DataType.SAMPLER_3D: + case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: + case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: + case gluShaderUtil.DataType.INT_SAMPLER_2D: + case gluShaderUtil.DataType.INT_SAMPLER_CUBE: + case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: + case gluShaderUtil.DataType.INT_SAMPLER_3D: + case gluShaderUtil.DataType.UINT_SAMPLER_2D: + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: + case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: + case gluShaderUtil.DataType.UINT_SAMPLER_3D: + return dataType; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * Checks if dataType is integer or vectors of integers + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType integer or integer vector + */ +gluShaderUtil.isDataTypeIntOrIVec = function(dataType) { + /** @type {boolean} */ var retVal = false; + switch (dataType) { + case gluShaderUtil.DataType.INT: + case gluShaderUtil.DataType.INT_VEC2: + case gluShaderUtil.DataType.INT_VEC3: + case gluShaderUtil.DataType.INT_VEC4: + retVal = true; + } + + return retVal; +}; + +/** + * Checks if dataType is unsigned integer or vectors of unsigned integers + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType unsigned integer or unsigned integer vector + */ +gluShaderUtil.isDataTypeUintOrUVec = function(dataType) { + /** @type {boolean} */ var retVal = false; + switch (dataType) { + case gluShaderUtil.DataType.UINT: + case gluShaderUtil.DataType.UINT_VEC2: + case gluShaderUtil.DataType.UINT_VEC3: + case gluShaderUtil.DataType.UINT_VEC4: + retVal = true; + } + + return retVal; +}; + +/** +* Returns type of scalar size +* @param {gluShaderUtil.DataType} dataType shader +* @return {number} with size of the type of scalar +*/ +gluShaderUtil.getDataTypeScalarSize = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: return 1; + case gluShaderUtil.DataType.FLOAT_VEC2: return 2; + case gluShaderUtil.DataType.FLOAT_VEC3: return 3; + case gluShaderUtil.DataType.FLOAT_VEC4: return 4; + case gluShaderUtil.DataType.FLOAT_MAT2: return 4; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 6; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 8; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 6; + case gluShaderUtil.DataType.FLOAT_MAT3: return 9; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 12; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 8; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 12; + case gluShaderUtil.DataType.FLOAT_MAT4: return 16; + case gluShaderUtil.DataType.INT: return 1; + case gluShaderUtil.DataType.INT_VEC2: return 2; + case gluShaderUtil.DataType.INT_VEC3: return 3; + case gluShaderUtil.DataType.INT_VEC4: return 4; + case gluShaderUtil.DataType.UINT: return 1; + case gluShaderUtil.DataType.UINT_VEC2: return 2; + case gluShaderUtil.DataType.UINT_VEC3: return 3; + case gluShaderUtil.DataType.UINT_VEC4: return 4; + case gluShaderUtil.DataType.BOOL: return 1; + case gluShaderUtil.DataType.BOOL_VEC2: return 2; + case gluShaderUtil.DataType.BOOL_VEC3: return 3; + case gluShaderUtil.DataType.BOOL_VEC4: return 4; + case gluShaderUtil.DataType.SAMPLER_2D: return 1; + case gluShaderUtil.DataType.SAMPLER_CUBE: return 1; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 1; + case gluShaderUtil.DataType.SAMPLER_3D: return 1; + case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 1; + case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 1; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 1; + case gluShaderUtil.DataType.INT_SAMPLER_2D: return 1; + case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 1; + case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 1; + case gluShaderUtil.DataType.INT_SAMPLER_3D: return 1; + case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 1; + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 1; + case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 1; + case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 1; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * Checks if dataType is float or vector + * @param {?gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType float or vector + */ +gluShaderUtil.isDataTypeFloatOrVec = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: + case gluShaderUtil.DataType.FLOAT_VEC2: + case gluShaderUtil.DataType.FLOAT_VEC3: + case gluShaderUtil.DataType.FLOAT_VEC4: + return true; + } + return false; +}; + +/** + * Checks if dataType is a matrix + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType matrix or not + */ +gluShaderUtil.isDataTypeMatrix = function(dataType) { + switch (dataType) { + 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: + return true; + } + return false; +}; + +/** + * Checks if dataType is a vector + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType vector or not + */ +gluShaderUtil.isDataTypeScalar = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: + case gluShaderUtil.DataType.INT: + case gluShaderUtil.DataType.UINT: + case gluShaderUtil.DataType.BOOL: + return true; + } + return false; +}; + +/** + * Checks if dataType is a vector + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType vector or not + */ +gluShaderUtil.isDataTypeVector = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT_VEC2: + case gluShaderUtil.DataType.FLOAT_VEC3: + case gluShaderUtil.DataType.FLOAT_VEC4: + case gluShaderUtil.DataType.INT_VEC2: + case gluShaderUtil.DataType.INT_VEC3: + case gluShaderUtil.DataType.INT_VEC4: + case gluShaderUtil.DataType.UINT_VEC2: + case gluShaderUtil.DataType.UINT_VEC3: + case gluShaderUtil.DataType.UINT_VEC4: + case gluShaderUtil.DataType.BOOL_VEC2: + case gluShaderUtil.DataType.BOOL_VEC3: + case gluShaderUtil.DataType.BOOL_VEC4: + return true; + } + return false; +}; + +/** + * Checks if dataType is a vector or a scalar type + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType vector or scalar or not + */ +gluShaderUtil.isDataTypeScalarOrVector = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT: + case gluShaderUtil.DataType.FLOAT_VEC2: + case gluShaderUtil.DataType.FLOAT_VEC3: + case gluShaderUtil.DataType.FLOAT_VEC4: + case gluShaderUtil.DataType.INT: + case gluShaderUtil.DataType.INT_VEC2: + case gluShaderUtil.DataType.INT_VEC3: + case gluShaderUtil.DataType.INT_VEC4: + case gluShaderUtil.DataType.UINT: + case gluShaderUtil.DataType.UINT_VEC2: + case gluShaderUtil.DataType.UINT_VEC3: + case gluShaderUtil.DataType.UINT_VEC4: + case gluShaderUtil.DataType.BOOL: + case gluShaderUtil.DataType.BOOL_VEC2: + case gluShaderUtil.DataType.BOOL_VEC3: + case gluShaderUtil.DataType.BOOL_VEC4: + return true; + } + return false; +}; + +/** + * Checks if dataType is a sampler + * @param {gluShaderUtil.DataType} dataType shader + * @return {boolean} Is dataType vector or scalar or not + */ +gluShaderUtil.isDataTypeSampler = function(dataType) { + return (dataType >= gluShaderUtil.DataType.SAMPLER_2D) && (dataType <= gluShaderUtil.DataType.UINT_SAMPLER_3D); +}; + +/** + * Returns a gluShaderUtil.DataType based on given rows and columns + * @param {number} numCols + * @param {number} numRows + * @return {gluShaderUtil.DataType} + */ +gluShaderUtil.getDataTypeMatrix = function(numCols, numRows) { + if (!(deMath.deInRange32(numCols, 2, 4) && deMath.deInRange32(numRows, 2, 4))) + throw new Error('Out of bounds: (' + numCols + ',' + numRows + ')'); + + var size = numCols.toString() + 'x' + numRows.toString(); + var datatypes = { + '2x2': gluShaderUtil.DataType.FLOAT_MAT2, + '2x3': gluShaderUtil.DataType.FLOAT_MAT2X3, + '2x4': gluShaderUtil.DataType.FLOAT_MAT2X4, + '3x2': gluShaderUtil.DataType.FLOAT_MAT3X2, + '3x3': gluShaderUtil.DataType.FLOAT_MAT3, + '3x4': gluShaderUtil.DataType.FLOAT_MAT3X4, + '4x2': gluShaderUtil.DataType.FLOAT_MAT4X2, + '4x3': gluShaderUtil.DataType.FLOAT_MAT4X3, + '4x4': gluShaderUtil.DataType.FLOAT_MAT4 + }; + return datatypes[size]; +}; + +/** +* Returns number of rows of a gluShaderUtil.DataType Matrix +* @param {gluShaderUtil.DataType} dataType shader +* @return {number} with number of rows depending on gluShaderUtil.DataType Matrix +*/ +gluShaderUtil.getDataTypeMatrixNumRows = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT_MAT2: return 2; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 3; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 4; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 2; + case gluShaderUtil.DataType.FLOAT_MAT3: return 3; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 4; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 2; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 3; + case gluShaderUtil.DataType.FLOAT_MAT4: return 4; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** +* Returns number of columns of a gluShaderUtil.DataType Matrix +* @param {gluShaderUtil.DataType} dataType shader +* @return {number} with number of columns depending on gluShaderUtil.DataType Matrix +*/ +gluShaderUtil.getDataTypeMatrixNumColumns = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.FLOAT_MAT2: return 2; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 2; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 2; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 3; + case gluShaderUtil.DataType.FLOAT_MAT3: return 3; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 3; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 4; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 4; + case gluShaderUtil.DataType.FLOAT_MAT4: return 4; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * @param {gluShaderUtil.DataType} dataType + * @return {number} + */ +gluShaderUtil.getDataTypeNumLocations = function(dataType) { + if (gluShaderUtil.isDataTypeScalarOrVector(dataType)) + return 1; + else if (gluShaderUtil.isDataTypeMatrix(dataType)) + return gluShaderUtil.getDataTypeMatrixNumColumns(dataType); + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * @param {gluShaderUtil.DataType} dataType + * @return {number} + */ +gluShaderUtil.getDataTypeNumComponents = function(dataType) { + if (gluShaderUtil.isDataTypeScalarOrVector(dataType)) + return gluShaderUtil.getDataTypeScalarSize(dataType); + else if (gluShaderUtil.isDataTypeMatrix(dataType)) + return gluShaderUtil.getDataTypeMatrixNumRows(dataType); + + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * Returns name of the dataType + * @param {?gluShaderUtil.DataType} dataType shader + * @return {string} dataType name + */ +gluShaderUtil.getDataTypeName = function(dataType) { + switch (dataType) { + case gluShaderUtil.DataType.INVALID: return 'invalid'; + + case gluShaderUtil.DataType.FLOAT: return 'float'; + case gluShaderUtil.DataType.FLOAT_VEC2: return 'vec2'; + case gluShaderUtil.DataType.FLOAT_VEC3: return 'vec3'; + case gluShaderUtil.DataType.FLOAT_VEC4: return 'vec4'; + case gluShaderUtil.DataType.FLOAT_MAT2: return 'mat2'; + case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mat2x3'; + case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mat2x4'; + case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mat3x2'; + case gluShaderUtil.DataType.FLOAT_MAT3: return 'mat3'; + case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mat3x4'; + case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mat4x2'; + case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mat4x3'; + case gluShaderUtil.DataType.FLOAT_MAT4: return 'mat4'; + + case gluShaderUtil.DataType.INT: return 'int'; + case gluShaderUtil.DataType.INT_VEC2: return 'ivec2'; + case gluShaderUtil.DataType.INT_VEC3: return 'ivec3'; + case gluShaderUtil.DataType.INT_VEC4: return 'ivec4'; + + case gluShaderUtil.DataType.UINT: return 'uint'; + case gluShaderUtil.DataType.UINT_VEC2: return 'uvec2'; + case gluShaderUtil.DataType.UINT_VEC3: return 'uvec3'; + case gluShaderUtil.DataType.UINT_VEC4: return 'uvec4'; + + case gluShaderUtil.DataType.BOOL: return 'bool'; + case gluShaderUtil.DataType.BOOL_VEC2: return 'bvec2'; + case gluShaderUtil.DataType.BOOL_VEC3: return 'bvec3'; + case gluShaderUtil.DataType.BOOL_VEC4: return 'bvec4'; + + case gluShaderUtil.DataType.SAMPLER_2D: return 'sampler2D'; + case gluShaderUtil.DataType.SAMPLER_CUBE: return 'samplerCube'; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 'sampler2DArray'; + case gluShaderUtil.DataType.SAMPLER_3D: return 'sampler3D'; + + case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 'sampler2DShadow'; + case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 'samplerCubeShadow'; + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 'sampler2DArrayShadow'; + + case gluShaderUtil.DataType.INT_SAMPLER_2D: return 'isampler2D'; + case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 'isamplerCube'; + case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 'isampler2DArray'; + case gluShaderUtil.DataType.INT_SAMPLER_3D: return 'isampler3D'; + + case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 'usampler2D'; + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 'usamplerCube'; + case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 'usampler2DArray'; + case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 'usampler3D'; + } + throw Error('Unrecognized dataType ' + dataType); +}; + +/** + * Returns the gluShaderUtil.DataType from the GL type + * @param {number} glType + * @return {gluShaderUtil.DataType} + */ +gluShaderUtil.getDataTypeFromGLType = function(glType) { + switch (glType) { + case gl.FLOAT: return gluShaderUtil.DataType.FLOAT; + case gl.FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT_VEC2; + case gl.FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT_VEC3; + case gl.FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT_VEC4; + + case gl.FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT_MAT2; + case gl.FLOAT_MAT2x3: return gluShaderUtil.DataType.FLOAT_MAT2X3; + case gl.FLOAT_MAT2x4: return gluShaderUtil.DataType.FLOAT_MAT2X4; + + case gl.FLOAT_MAT3x2: return gluShaderUtil.DataType.FLOAT_MAT3X2; + case gl.FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT_MAT3; + case gl.FLOAT_MAT3x4: return gluShaderUtil.DataType.FLOAT_MAT3X4; + + case gl.FLOAT_MAT4x2: return gluShaderUtil.DataType.FLOAT_MAT4X2; + case gl.FLOAT_MAT4x3: return gluShaderUtil.DataType.FLOAT_MAT4X3; + case gl.FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT_MAT4; + + case gl.INT: return gluShaderUtil.DataType.INT; + case gl.INT_VEC2: return gluShaderUtil.DataType.INT_VEC2; + case gl.INT_VEC3: return gluShaderUtil.DataType.INT_VEC3; + case gl.INT_VEC4: return gluShaderUtil.DataType.INT_VEC4; + + case gl.UNSIGNED_INT: return gluShaderUtil.DataType.UINT; + case gl.UNSIGNED_INT_VEC2: return gluShaderUtil.DataType.UINT_VEC2; + case gl.UNSIGNED_INT_VEC3: return gluShaderUtil.DataType.UINT_VEC3; + case gl.UNSIGNED_INT_VEC4: return gluShaderUtil.DataType.UINT_VEC4; + + case gl.BOOL: return gluShaderUtil.DataType.BOOL; + case gl.BOOL_VEC2: return gluShaderUtil.DataType.BOOL_VEC2; + case gl.BOOL_VEC3: return gluShaderUtil.DataType.BOOL_VEC3; + case gl.BOOL_VEC4: return gluShaderUtil.DataType.BOOL_VEC4; + + case gl.SAMPLER_2D: return gluShaderUtil.DataType.SAMPLER_2D; + case gl.SAMPLER_CUBE: return gluShaderUtil.DataType.SAMPLER_CUBE; + case gl.SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.SAMPLER_2D_ARRAY; + case gl.SAMPLER_3D: return gluShaderUtil.DataType.SAMPLER_3D; + + case gl.SAMPLER_2D_SHADOW: return gluShaderUtil.DataType.SAMPLER_2D_SHADOW; + case gl.SAMPLER_CUBE_SHADOW: return gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW; + case gl.SAMPLER_2D_ARRAY_SHADOW: return gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW; + + case gl.INT_SAMPLER_2D: return gluShaderUtil.DataType.INT_SAMPLER_2D; + case gl.INT_SAMPLER_CUBE: return gluShaderUtil.DataType.INT_SAMPLER_CUBE; + case gl.INT_SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY; + case gl.INT_SAMPLER_3D: return gluShaderUtil.DataType.INT_SAMPLER_3D; + + case gl.UNSIGNED_INT_SAMPLER_2D: return gluShaderUtil.DataType.UINT_SAMPLER_2D; + case gl.UNSIGNED_INT_SAMPLER_CUBE: return gluShaderUtil.DataType.UINT_SAMPLER_CUBE; + case gl.UNSIGNED_INT_SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY; + case gl.UNSIGNED_INT_SAMPLER_3D: return gluShaderUtil.DataType.UINT_SAMPLER_3D; + + default: + throw new Error('Unrecognized GL type:' + glType); + } +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js new file mode 100644 index 0000000000..b554db047a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js @@ -0,0 +1,166 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluStrUtil'); + +goog.scope(function() { + +var gluStrUtil = framework.opengl.gluStrUtil; + +gluStrUtil.getPixelFormatName = function(value) { + switch (value) { + case gl.LUMINANCE: return 'gl.LUMINANCE'; + case gl.LUMINANCE_ALPHA: return 'gl.LUMINANCE_ALPHA'; + case gl.ALPHA: return 'gl.ALPHA'; + case gl.RGB: return 'gl.RGB'; + case gl.RGBA: return 'gl.RGBA'; + case gl.RGBA4: return 'gl.RGBA4'; + case gl.RGB5_A1: return 'gl.RGB5_A1'; + case gl.RGB565: return 'gl.RGB565'; + case gl.DEPTH_COMPONENT16: return 'gl.DEPTH_COMPONENT16'; + case gl.STENCIL_INDEX8: return 'gl.STENCIL_INDEX8'; + case gl.RG: return 'gl.RG'; + case gl.RED: return 'gl.RED'; + case gl.RGBA_INTEGER: return 'gl.RGBA_INTEGER'; + case gl.RGB_INTEGER: return 'gl.RGB_INTEGER'; + case gl.RG_INTEGER: return 'gl.RG_INTEGER'; + case gl.RED_INTEGER: return 'gl.RED_INTEGER'; + case gl.DEPTH_COMPONENT: return 'gl.DEPTH_COMPONENT'; + case gl.DEPTH_STENCIL: return 'gl.DEPTH_STENCIL'; + case gl.RGBA32F: return 'gl.RGBA32F'; + case gl.RGBA32I: return 'gl.RGBA32I'; + case gl.RGBA32UI: return 'gl.RGBA32UI'; + // case gl.RGBA16: return 'gl.RGBA16'; + // case gl.RGBA16_SNORM: return 'gl.RGBA16_SNORM'; + case gl.RGBA16F: return 'gl.RGBA16F'; + case gl.RGBA16I: return 'gl.RGBA16I'; + case gl.RGBA16UI: return 'gl.RGBA16UI'; + case gl.RGBA8: return 'gl.RGBA8'; + case gl.RGBA8I: return 'gl.RGBA8I'; + case gl.RGBA8UI: return 'gl.RGBA8UI'; + case gl.SRGB8_ALPHA8: return 'gl.SRGB8_ALPHA8'; + case gl.RGB10_A2: return 'gl.RGB10_A2'; + case gl.RGB10_A2UI: return 'gl.RGB10_A2UI'; + case gl.RGBA8_SNORM: return 'gl.RGBA8_SNORM'; + case gl.RGB8: return 'gl.RGB8'; + case gl.R11F_G11F_B10F: return 'gl.R11F_G11F_B10F'; + case gl.RGB32F: return 'gl.RGB32F'; + case gl.RGB32I: return 'gl.RGB32I'; + case gl.RGB32UI: return 'gl.RGB32UI'; + // case gl.RGB16: return 'gl.RGB16'; + // case gl.RGB16_SNORM: return 'gl.RGB16_SNORM'; + case gl.RGB16F: return 'gl.RGB16F'; + case gl.RGB16I: return 'gl.RGB16I'; + case gl.RGB16UI: return 'gl.RGB16UI'; + case gl.RGB8_SNORM: return 'gl.RGB8_SNORM'; + case gl.RGB8I: return 'gl.RGB8I'; + case gl.RGB8UI: return 'gl.RGB8UI'; + case gl.SRGB8: return 'gl.SRGB8'; + case gl.RGB9_E5: return 'gl.RGB9_E5'; + case gl.RG32F: return 'gl.RG32F'; + case gl.RG32I: return 'gl.RG32I'; + case gl.RG32UI: return 'gl.RG32UI'; + // case gl.RG16: return 'gl.RG16'; + // case gl.RG16_SNORM: return 'gl.RG16_SNORM'; + case gl.RG16F: return 'gl.RG16F'; + case gl.RG16I: return 'gl.RG16I'; + case gl.RG16UI: return 'gl.RG16UI'; + case gl.RG8: return 'gl.RG8'; + case gl.RG8I: return 'gl.RG8I'; + case gl.RG8UI: return 'gl.RG8UI'; + case gl.RG8_SNORM: return 'gl.RG8_SNORM'; + case gl.R32F: return 'gl.R32F'; + case gl.R32I: return 'gl.R32I'; + case gl.R32UI: return 'gl.R32UI'; + // case gl.R16: return 'gl.R16'; + // case gl.R16_SNORM: return 'gl.R16_SNORM'; + case gl.R16F: return 'gl.R16F'; + case gl.R16I: return 'gl.R16I'; + case gl.R16UI: return 'gl.R16UI'; + case gl.R8: return 'gl.R8'; + case gl.R8I: return 'gl.R8I'; + case gl.R8UI: return 'gl.R8UI'; + case gl.R8_SNORM: return 'gl.R8_SNORM'; + case gl.DEPTH_COMPONENT32F: return 'gl.DEPTH_COMPONENT32F'; + case gl.DEPTH_COMPONENT24: return 'gl.DEPTH_COMPONENT24'; + case gl.DEPTH32F_STENCIL8: return 'gl.DEPTH32F_STENCIL8'; + case gl.DEPTH24_STENCIL8: return 'gl.DEPTH24_STENCIL8'; + // case gl.RGB10: return 'gl.RGB10'; + // case gl.DEPTH_COMPONENT32: return 'gl.DEPTH_COMPONENT32'; + case gl.SRGB: return 'gl.SRGB'; + // case gl.SRGB_ALPHA: return 'gl.SRGB_ALPHA'; + default: return ''; + } +}; + +gluStrUtil.getTypeName = function(value) { + switch (value) { + case gl.BYTE: return 'gl.BYTE'; + case gl.UNSIGNED_BYTE: return 'gl.UNSIGNED_BYTE'; + case gl.SHORT: return 'gl.SHORT'; + case gl.UNSIGNED_SHORT: return 'gl.UNSIGNED_SHORT'; + case gl.INT: return 'gl.INT'; + case gl.UNSIGNED_INT: return 'gl.UNSIGNED_INT'; + case gl.FLOAT: return 'gl.FLOAT'; + // case gl.FIXED: return 'gl.FIXED'; + case gl.UNSIGNED_SHORT_5_6_5: return 'gl.UNSIGNED_SHORT_5_6_5'; + case gl.UNSIGNED_SHORT_4_4_4_4: return 'gl.UNSIGNED_SHORT_4_4_4_4'; + case gl.UNSIGNED_SHORT_5_5_5_1: return 'gl.UNSIGNED_SHORT_5_5_5_1'; + case gl.HALF_FLOAT: return 'gl.HALF_FLOAT'; + case gl.INT_2_10_10_10_REV: return 'gl.INT_2_10_10_10_REV'; + case gl.UNSIGNED_INT_2_10_10_10_REV: return 'gl.UNSIGNED_INT_2_10_10_10_REV'; + case gl.UNSIGNED_INT_10F_11F_11F_REV: return 'gl.UNSIGNED_INT_10F_11F_11F_REV'; + case gl.UNSIGNED_INT_5_9_9_9_REV: return 'gl.UNSIGNED_INT_5_9_9_9_REV'; + case gl.UNSIGNED_INT_24_8: return 'gl.UNSIGNED_INT_24_8'; + case gl.FLOAT_32_UNSIGNED_INT_24_8_REV: return 'gl.FLOAT_32_UNSIGNED_INT_24_8_REV'; + case gl.SIGNED_NORMALIZED: return 'gl.SIGNED_NORMALIZED'; + case gl.UNSIGNED_NORMALIZED: return 'gl.UNSIGNED_NORMALIZED'; + // case gl.HALF_FLOAT_OES: return 'gl.HALF_FLOAT_OES'; + default: return ''; + } +}; + +gluStrUtil.getErrorName = function(value) { + switch (value) { + case gl.NO_ERROR: return 'gl.NO_ERROR'; + case gl.INVALID_ENUM: return 'gl.INVALID_ENUM'; + case gl.INVALID_VALUE: return 'gl.INVALID_VALUE'; + case gl.INVALID_OPERATION: return 'gl.INVALID_OPERATION'; + case gl.OUT_OF_MEMORY: return 'gl.OUT_OF_MEMORY'; + // case gl.INVALID_FRAMEBUFFER_OPERATION: return 'gl.INVALID_FRAMEBUFFER_OPERATION'; + default: return ''; + } +}; + +gluStrUtil.getFramebufferStatusName = function(value) { + switch (value) { + case gl.FRAMEBUFFER_COMPLETE: return 'gl.FRAMEBUFFER_COMPLETE'; + case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return 'gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT'; + case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return 'gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT'; + case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: return 'gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS'; + case gl.FRAMEBUFFER_UNSUPPORTED: return 'gl.FRAMEBUFFER_UNSUPPORTED'; + case gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return 'gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE'; + // case: gl.FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return 'gl.FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS'; + default: return ''; + } +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js new file mode 100644 index 0000000000..fcc33588e1 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js @@ -0,0 +1,380 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluTexture'); +goog.require('framework.common.tcuCompressedTexture'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.opengl.gluTextureUtil'); + +goog.scope(function() { + +var gluTexture = framework.opengl.gluTexture; +var gluTextureUtil = framework.opengl.gluTextureUtil; +var tcuTexture = framework.common.tcuTexture; +var tcuCompressedTexture = framework.common.tcuCompressedTexture; +var deMath = framework.delibs.debase.deMath; + +var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); +}; + +/** @enum {number} */ +gluTexture.Type = { + TYPE_NONE: 0, + TYPE_2D: 1, + TYPE_CUBE_MAP: 2, + TYPE_2D_ARRAY: 3, + TYPE_3D: 4 +}; + +/** + * @constructor + */ +gluTexture.Texture2D = function(gl, format, isCompressed, refTexture) { + this.gl = gl; + this.m_glTexture = gl.createTexture(); + this.m_isCompressed = isCompressed; + this.m_format = format; // Internal format + this.m_refTexture = refTexture; + this.m_type = gluTexture.Type.TYPE_2D; +}; + +gluTexture.Texture2D.prototype.getType = function() { + return this.m_type; +}; + +gluTexture.Texture2D.prototype.getRefTexture = function() { + return this.m_refTexture; +}; + +gluTexture.Texture2D.prototype.getGLTexture = function() { + return this.m_glTexture; +}; + +gluTexture.texture2DFromFormat = function(gl, format, dataType, width, height) { + var tex = new gluTexture.Texture2D(gl, format, false, new tcuTexture.Texture2D(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height)); + return tex; +}; + +gluTexture.texture2DFromInternalFormat = function(gl, internalFormat, width, height) { + var tex = new gluTexture.Texture2D(gl, internalFormat, false, new tcuTexture.Texture2D(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height)); + return tex; +}; + +/** + * @param {number} numLevels + * @param {Array<tcuCompressedTexture.CompressedTexture>} levels + * @return {gluTexture.Texture2D} + */ +gluTexture.texture2DFromCompressedTexture = function(gl, numLevels, levels) { + var level = levels[0]; + var format = gluTextureUtil.getGLFormat(level.getFormat()); + var refTex = new tcuTexture.Texture2D(level.getUncompressedFormat(), level.getWidth(), level.getHeight()); + /** @type {gluTexture.Texture2D} */ var tex2d = new gluTexture.Texture2D(gl, format, true, refTex); + + tex2d.loadCompressed(numLevels, levels); + + return tex2d; +}; +/** + * @param {number} numLevels + * @param {Array<tcuCompressedTexture.CompressedTexture>} levels + */ +gluTexture.Texture2D.prototype.loadCompressed = function(numLevels, levels) { + /** @type {number} */ var compressedFormat = gluTextureUtil.getGLFormat(levels[0].getFormat()); + + assertMsgOptions(this.m_glTexture, 'm_glTexture not defined', false, true); + gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture); + + for (var levelNdx = 0; levelNdx < numLevels; levelNdx++) { + /** @type {tcuCompressedTexture.CompressedTexture} */ var level = levels[levelNdx]; + + // Decompress to reference texture. + this.m_refTexture.allocLevel(levelNdx); + /** @type {tcuTexture.PixelBufferAccess} */ var refLevelAccess = this.m_refTexture.getLevel(levelNdx); + assertMsgOptions(level.getWidth() == refLevelAccess.getWidth() && level.getHeight() == refLevelAccess.getHeight(), 'level and reference sizes not equal', false, true); + level.decompress(refLevelAccess); + + // Upload to GL texture in compressed form. + gl.compressedTexImage2D(gl.TEXTURE_2D, levelNdx, compressedFormat, + level.getWidth(), level.getHeight(), 0, level.getData()); + } +}; + +gluTexture.computePixelStore = function(/*const tcu::TextureFormat&*/ format) { + var pixelSize = format.getPixelSize(); + if (deMath.deIsPowerOfTwo32(pixelSize)) + return Math.min(pixelSize, 8); + else + return 1; +}; + +gluTexture.cubeFaceToGLFace = function(/*tcu::CubeFace*/ face) { + switch (face) { + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: return gl.TEXTURE_CUBE_MAP_NEGATIVE_X; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: return gl.TEXTURE_CUBE_MAP_POSITIVE_X; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: return gl.TEXTURE_CUBE_MAP_NEGATIVE_Y; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: return gl.TEXTURE_CUBE_MAP_POSITIVE_Y; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: return gl.TEXTURE_CUBE_MAP_NEGATIVE_Z; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: return gl.TEXTURE_CUBE_MAP_POSITIVE_Z; + } + throw new Error('Unrecognized face: ' + face); +}; + +gluTexture.Texture2D.prototype.upload = function() { + DE_ASSERT(!this.m_isCompressed); + + if (this.m_glTexture == null) + testFailedOptions('Failed to create GL texture', true); + + gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat())); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Setting pixel store failed', false, true); + + var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat()); + + for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) { + if (this.m_refTexture.isLevelEmpty(levelNdx)) + continue; // Don't upload. + + var access = this.m_refTexture.getLevel(levelNdx); + DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth()); + var data = access.getDataPtr(); + gl.texImage2D(gl.TEXTURE_2D, levelNdx, this.m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); + } + + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); +}; + +/** + * @constructor + * @extends {gluTexture.Texture2D} + */ +gluTexture.TextureCube = function(gl, format, isCompressed, refTexture) { + gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture); + this.m_type = gluTexture.Type.TYPE_CUBE_MAP; +}; + +gluTexture.TextureCube.prototype = Object.create(gluTexture.Texture2D.prototype); +gluTexture.TextureCube.prototype.constructor = gluTexture.TextureCube; + +gluTexture.TextureCube.prototype.upload = function() { + DE_ASSERT(!this.m_isCompressed); + + if (this.m_glTexture == null) + testFailedOptions('Failed to create GL texture', true); + + gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.m_glTexture); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat())); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Setting pixel store failed', false, true); + + var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat()); + + for (var face in tcuTexture.CubeFace) { + for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) { + if (this.m_refTexture.isLevelEmpty(tcuTexture.CubeFace[face], levelNdx)) + continue; // Don't upload. + + /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevelFace(levelNdx, tcuTexture.CubeFace[face]); + DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth()); + gl.texImage2D(gluTexture.cubeFaceToGLFace(tcuTexture.CubeFace[face]), levelNdx, this.m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); + } + } + + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); +}; + +gluTexture.cubeFromFormat = function(gl, format, dataType, size) { + var tex = new gluTexture.TextureCube(gl, format, false, new tcuTexture.TextureCube(gluTextureUtil.mapGLTransferFormat(format, dataType), size)); + return tex; +}; + +gluTexture.cubeFromInternalFormat = function(gl, internalFormat, size) { + var tex = new gluTexture.TextureCube(gl, internalFormat, false, new tcuTexture.TextureCube(gluTextureUtil.mapGLInternalFormat(internalFormat), size)); + return tex; +}; + +/** + * @constructor + * @extends {gluTexture.Texture2D} + */ +gluTexture.Texture2DArray = function(gl, format, isCompressed, refTexture) { + gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture); + this.m_type = gluTexture.Type.TYPE_2D_ARRAY; +}; + +gluTexture.Texture2DArray.prototype = Object.create(gluTexture.Texture2D.prototype); +gluTexture.Texture2DArray.prototype.constructor = gluTexture.Texture2DArray; + +gluTexture.Texture2DArray.prototype.upload = function() { + if (!gl.texImage3D) + throw new Error('gl.TexImage3D() is not supported'); + + gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.m_glTexture); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat())); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); + + var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat()); + + for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) { + if (this.m_refTexture.isLevelEmpty(levelNdx)) + continue; // Don't upload. + + /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevel(levelNdx); + DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth()); + DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize() * access.getWidth() * access.getHeight()); + gl.texImage3D(gl.TEXTURE_2D_ARRAY, levelNdx, this.m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); + } + + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); +}; + +gluTexture.texture2DArrayFromFormat = function(gl, format, dataType, width, height, numLayers) { + var tex = new gluTexture.Texture2DArray(gl, format, false, new tcuTexture.Texture2DArray(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height, numLayers)); + return tex; +}; + +gluTexture.texture2DArrayFromInternalFormat = function(gl, internalFormat, width, height, numLayers) { + var tex = new gluTexture.Texture2DArray(gl, internalFormat, false, new tcuTexture.Texture2DArray(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height, numLayers)); + return tex; +}; + +/** + * @constructor + * @extends {gluTexture.Texture2D} + */ +gluTexture.Texture3D = function(gl, format, isCompressed, refTexture) { + gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture); + this.m_type = gluTexture.Type.TYPE_3D; +}; + +gluTexture.Texture3D.prototype = Object.create(gluTexture.Texture2D.prototype); +gluTexture.Texture3D.prototype.constructor = gluTexture.Texture3D; + +gluTexture.Texture3D.prototype.upload = function() { + if (!gl.texImage3D) + throw new Error('gl.TexImage3D() is not supported'); + + gl.bindTexture(gl.TEXTURE_3D, this.m_glTexture); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat())); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); + + var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat()); + + for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) { + if (this.m_refTexture.isLevelEmpty(levelNdx)) + continue; // Don't upload. + + /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevel(levelNdx); + DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth()); + DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize() * access.getWidth() * access.getHeight()); + gl.texImage3D(gl.TEXTURE_3D, levelNdx, this.m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); + } + + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); +}; + +gluTexture.texture3DFromFormat = function(gl, format, dataType, width, height, depth) { + var tex = new gluTexture.Texture3D(gl, format, false, new tcuTexture.Texture3D(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height, depth)); + return tex; +}; + +gluTexture.texture3DFromInternalFormat = function(gl, internalFormat, width, height, depth) { + var tex = new gluTexture.Texture3D(gl, internalFormat, false, new tcuTexture.Texture3D(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height, depth)); + return tex; +}; + +/** + * @constructor + * @extends {gluTexture.Texture2D} + */ +gluTexture.Compressed2D = function(gl, format, isCompressed, refTexture) { + gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture); +}; + +gluTexture.Compressed2D.prototype = Object.create(gluTexture.Texture2D.prototype); +gluTexture.Compressed2D.prototype.constructor = gluTexture.Compressed2D; + +gluTexture.Compressed2D.prototype.uploadLevel = function(level, source) { + DE_ASSERT(this.m_isCompressed); + + if (this.m_glTexture == null) + testFailedOptions('Failed to create GL texture', true); + + gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture); + + gl.compressedTexImage2D(gl.TEXTURE_2D, level, this.m_format, source.m_width, source.m_height, 0 /* border */, source.m_data); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); +}; + +/** + * @constructor + * @extends {gluTexture.Texture2D} + */ +gluTexture.CompressedCube = function(gl, format, isCompressed, refTexture) { + gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture); +}; + +gluTexture.CompressedCube.prototype = Object.create(gluTexture.Texture2D.prototype); +gluTexture.CompressedCube.prototype.constructor = gluTexture.CompressedCube; + +gluTexture.CompressedCube.prototype.uploadLevel = function(level, source) { + DE_ASSERT(this.m_isCompressed); + + if (this.m_glTexture == null) + testFailedOptions('Failed to create GL texture', true); + + gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.m_glTexture); + + for (var face in tcuTexture.CubeFace) { + + // Upload to GL texture in compressed form. + gl.compressedTexImage2D(gluTexture.cubeFaceToGLFace(tcuTexture.CubeFace[face]), 0, this.m_format, + source.m_width, source.m_height, 0 /* border */, source.m_data); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true); + } + +}; + +gluTexture.compressed2DFromInternalFormat = function(gl, format, width, height, compressed) { + var tex = new gluTexture.Compressed2D(gl, gluTextureUtil.getGLFormat(format), true, new tcuTexture.Texture2D(compressed.getUncompressedFormat(), width, height)); + tex.m_refTexture.allocLevel(0); + compressed.decompress(tex.m_refTexture.getLevel(0)); + tex.uploadLevel(0, compressed); + return tex; +}; + +gluTexture.compressedCubeFromInternalFormat = function(gl, format, size, compressed) { + var tex = new gluTexture.CompressedCube(gl, gluTextureUtil.getGLFormat(format), true, new tcuTexture.TextureCube(compressed.getUncompressedFormat(), size)); + for (var face in tcuTexture.CubeFace) { + tex.m_refTexture.allocLevel(tcuTexture.CubeFace[face], 0); + + /*tcu::ConstPixelBufferAccess*/ var access = tex.m_refTexture.getLevelFace(0, tcuTexture.CubeFace[face]); + DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth()); + compressed.decompress(access); + } + tex.uploadLevel(0, compressed); + return tex; +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js new file mode 100644 index 0000000000..06f3f5289d --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js @@ -0,0 +1,1025 @@ +/*------------------------------------------------------------------------- + * 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. + * + */ + +/*--------------------------------------------------------------------*//*! + * \brief Map tcuTexture.TextureFormat to GL pixel transfer format. + * + * Maps generic texture format description to GL pixel transfer format. + * If no mapping is found, throws tcu::InternalError. + * + * \param texFormat Generic texture format. + * \return GL pixel transfer format. + *//*--------------------------------------------------------------------*/ +'use strict'; +goog.provide('framework.opengl.gluTextureUtil'); +goog.require('framework.common.tcuCompressedTexture'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deString'); +goog.require('framework.opengl.gluShaderUtil'); + +goog.scope(function() { + +var gluTextureUtil = framework.opengl.gluTextureUtil; +var deString = framework.delibs.debase.deString; +var tcuTexture = framework.common.tcuTexture; +var tcuTextureUtil = framework.common.tcuTextureUtil; +var tcuCompressedTexture = framework.common.tcuCompressedTexture; +var gluShaderUtil = framework.opengl.gluShaderUtil; + +/** + * @param {number} format + * @param {number} dataType + * @constructor + */ +gluTextureUtil.TransferFormat = function(format, dataType) { + this.format = format; //!< Pixel format. + this.dataType = dataType; //!< Data type. +}; + +/** + * Map tcuTexture.TextureFormat to GL pixel transfer format. + * + * Maps generic texture format description to GL pixel transfer format. + * If no mapping is found, throws tcu::InternalError. + * + * @param {tcuTexture.TextureFormat} texFormat Generic texture format. + * @return {gluTextureUtil.TransferFormat} GL pixel transfer format. + * @throws {Error} + */ +gluTextureUtil.getTransferFormat = function(/* tcuTexture.TextureFormat */ texFormat) { + var format = gl.NONE; + var type = gl.NONE; + /*boolean*/ var isInt = false; + + switch (texFormat.type) { + case tcuTexture.ChannelType.SIGNED_INT8: + case tcuTexture.ChannelType.SIGNED_INT16: + case tcuTexture.ChannelType.SIGNED_INT32: + case tcuTexture.ChannelType.UNSIGNED_INT8: + case tcuTexture.ChannelType.UNSIGNED_INT16: + case tcuTexture.ChannelType.UNSIGNED_INT32: + case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: + isInt = true; + break; + + default: + isInt = false; + break; + } + + switch (texFormat.order) { + case tcuTexture.ChannelOrder.A: format = gl.ALPHA; break; + case tcuTexture.ChannelOrder.L: format = gl.LUMINANCE; break; + case tcuTexture.ChannelOrder.LA: format = gl.LUMINANCE_ALPHA; break; + case tcuTexture.ChannelOrder.R: format = isInt ? gl.RED_INTEGER : gl.RED; break; + case tcuTexture.ChannelOrder.RG: format = isInt ? gl.RG_INTEGER : gl.RG; break; + case tcuTexture.ChannelOrder.RGB: format = isInt ? gl.RGB_INTEGER : gl.RGB; break; + case tcuTexture.ChannelOrder.RGBA: format = isInt ? gl.RGBA_INTEGER : gl.RGBA; break; + case tcuTexture.ChannelOrder.sRGB: format = gl.RGB; break; + case tcuTexture.ChannelOrder.sRGBA: format = gl.RGBA; break; + case tcuTexture.ChannelOrder.D: format = gl.DEPTH_COMPONENT; break; + case tcuTexture.ChannelOrder.DS: format = gl.DEPTH_STENCIL; break; + case tcuTexture.ChannelOrder.S: format = gl.STENCIL_INDEX; break; + + default: + throw new Error('Unknown ChannelOrder ' + texFormat.order); + } + + switch (texFormat.type) { + case tcuTexture.ChannelType.SNORM_INT8: type = gl.BYTE; break; + case tcuTexture.ChannelType.SNORM_INT16: type = gl.SHORT; break; + case tcuTexture.ChannelType.UNORM_INT8: type = gl.UNSIGNED_BYTE; break; + case tcuTexture.ChannelType.UNORM_INT16: type = gl.UNSIGNED_SHORT; break; + case tcuTexture.ChannelType.UNORM_SHORT_565: type = gl.UNSIGNED_SHORT_5_6_5; break; + case tcuTexture.ChannelType.UNORM_SHORT_4444: type = gl.UNSIGNED_SHORT_4_4_4_4; break; + case tcuTexture.ChannelType.UNORM_SHORT_5551: type = gl.UNSIGNED_SHORT_5_5_5_1; break; + case tcuTexture.ChannelType.SIGNED_INT8: type = gl.BYTE; break; + case tcuTexture.ChannelType.SIGNED_INT16: type = gl.SHORT; break; + case tcuTexture.ChannelType.SIGNED_INT32: type = gl.INT; break; + case tcuTexture.ChannelType.UNSIGNED_INT8: type = gl.UNSIGNED_BYTE; break; + case tcuTexture.ChannelType.UNSIGNED_INT16: type = gl.UNSIGNED_SHORT; break; + case tcuTexture.ChannelType.UNSIGNED_INT32: type = gl.UNSIGNED_INT; break; + case tcuTexture.ChannelType.FLOAT: type = gl.FLOAT; break; + case tcuTexture.ChannelType.UNORM_INT_101010: type = gl.UNSIGNED_INT_2_10_10_10_REV; break; + case tcuTexture.ChannelType.UNORM_INT_1010102_REV: type = gl.UNSIGNED_INT_2_10_10_10_REV; break; + case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: type = gl.UNSIGNED_INT_2_10_10_10_REV; break; + case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: type = gl.UNSIGNED_INT_10F_11F_11F_REV; break; + case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: type = gl.UNSIGNED_INT_5_9_9_9_REV; break; + case tcuTexture.ChannelType.HALF_FLOAT: type = gl.HALF_FLOAT; break; + case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: type = gl.FLOAT_32_UNSIGNED_INT_24_8_REV; break; + case tcuTexture.ChannelType.UNSIGNED_INT_24_8: type = texFormat.order == tcuTexture.ChannelOrder.D ? + gl.UNSIGNED_INT : gl.UNSIGNED_INT_24_8; break; + + default: + throw new Error("Can't map texture format to GL transfer format " + texFormat.type); + } + + return new gluTextureUtil.TransferFormat(format, type); +}; + +/** + * Map tcuTexture.TextureFormat to GL internal sized format. + * + * Maps generic texture format description to GL internal format. + * If no mapping is found, throws Error. + * + * @param {tcuTexture.TextureFormat} texFormat Generic texture format. + * @return {number} GL texture format. + * @throws {Error} + */ +gluTextureUtil.getInternalFormat = function(texFormat) { + + var stringify = function(order, type) { + return '' + order + ' ' + type; + }; + + switch (stringify(texFormat.order, texFormat.type)) { + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551): return gl.RGB5_A1; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444): return gl.RGBA4; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565): return gl.RGB565; + case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16): return gl.DEPTH_COMPONENT16; + case stringify(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.STENCIL_INDEX8; + + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT): return gl.RGBA32F; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT32): return gl.RGBA32I; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RGBA32UI; + // TODO: Check which ones are valid in WebGL 2 - case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT16): return gl.RGBA16; + //case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT16): return gl.RGBA16_SNORM; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.HALF_FLOAT): return gl.RGBA16F; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT16): return gl.RGBA16I; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RGBA16UI; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8): return gl.RGBA8; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT8): return gl.RGBA8I; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RGBA8UI; + case stringify(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8): return gl.SRGB8_ALPHA8; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT_1010102_REV): return gl.RGB10_A2; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV): return gl.RGB10_A2UI; + case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT8): return gl.RGBA8_SNORM; + + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8): return gl.RGB8; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV): return gl.R11F_G11F_B10F; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.FLOAT): return gl.RGB32F; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT32): return gl.RGB32I; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RGB32UI; + //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT16): return gl.RGB16; + //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT16): return gl.RGB16_SNORM; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.HALF_FLOAT): return gl.RGB16F; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT16): return gl.RGB16I; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RGB16UI; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT8): return gl.RGB8_SNORM; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT8): return gl.RGB8I; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RGB8UI; + case stringify(tcuTexture.ChannelOrder.sRGB, tcuTexture.ChannelType.UNORM_INT8): return gl.SRGB8; + case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV): return gl.RGB9_E5; + //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT_1010102_REV): return gl.RGB10; + + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.FLOAT): return gl.RG32F; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT32): return gl.RG32I; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RG32UI; + //case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT16): return gl.RG16; + //case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT16): return gl.RG16_SNORM; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.HALF_FLOAT): return gl.RG16F; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT16): return gl.RG16I; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RG16UI; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT8): return gl.RG8; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT8): return gl.RG8I; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RG8UI; + case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT8): return gl.RG8_SNORM; + + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.FLOAT): return gl.R32F; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT32): return gl.R32I; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.R32UI; + //case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT16): return gl.R16; + //case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT16): return gl.R16_SNORM; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.HALF_FLOAT): return gl.R16F; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT16): return gl.R16I; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.R16UI; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT8): return gl.R8; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT8): return gl.R8I; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.R8UI; + case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT8): return gl.R8_SNORM; + + case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT): return gl.DEPTH_COMPONENT32F; + case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8): return gl.DEPTH_COMPONENT24; + //case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.DEPTH_COMPONENT32; + case stringify(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV): return gl.DEPTH32F_STENCIL8; + case stringify(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.UNSIGNED_INT_24_8): return gl.DEPTH24_STENCIL8; + + default: + throw new Error("Can't map texture format to GL internal format"); + } +}; + +/** + * Enable WEBGL_compressed_texture_etc support if available, by merging it + * into the WebGL2RenderingContext. + * + * This function may be called many times. + * + * @return {boolean} True if enabled. + */ +gluTextureUtil.enableCompressedTextureETC = (function() { + var enabled = undefined; + return function() { + if (enabled === undefined) { + enabled = false; + + var WEBGL_compressed_texture_etc = gl.getExtension("WEBGL_compressed_texture_etc"); + if (WEBGL_compressed_texture_etc) { + // Extend gl with enums from WEBGL_compressed_texture_etc + // (if it doesn't already have the etc texture formats). + var proto = Object.getPrototypeOf(WEBGL_compressed_texture_etc); + for (var prop in proto) { + if (proto.hasOwnProperty(prop)) { + gl[prop] = proto[prop]; + } + } + enabled = true; + } + } + return enabled; + }; +})(); + +/** + * Map generic compressed format to GL compressed format enum. + * + * Maps generic compressed format to GL compressed format enum value. + * If no mapping is found, throws Error. + + * @param {tcuCompressedTexture.Format} format Generic compressed format. + * @return {number} GL compressed texture format. + * @throws {Error} + */ +gluTextureUtil.getGLFormat = function(/* tcuCompressedTexture.Format */ format) { + switch (format) { + // TODO: check which are available in WebGL 2 - case tcuCompressedTexture.Format.ETC1_RGB8: return gl.ETC1_RGB8_OES; + case tcuCompressedTexture.Format.EAC_R11: return gl.COMPRESSED_R11_EAC; + case tcuCompressedTexture.Format.EAC_SIGNED_R11: return gl.COMPRESSED_SIGNED_R11_EAC; + case tcuCompressedTexture.Format.EAC_RG11: return gl.COMPRESSED_RG11_EAC; + case tcuCompressedTexture.Format.EAC_SIGNED_RG11: return gl.COMPRESSED_SIGNED_RG11_EAC; + case tcuCompressedTexture.Format.ETC2_RGB8: return gl.COMPRESSED_RGB8_ETC2; + case tcuCompressedTexture.Format.ETC2_SRGB8: return gl.COMPRESSED_SRGB8_ETC2; + case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1: return gl.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: return gl.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case tcuCompressedTexture.Format.ETC2_EAC_RGBA8: return gl.COMPRESSED_RGBA8_ETC2_EAC; + case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + + /*case tcuCompressedTexture.Format.ASTC_4x4_RGBA: return gl.COMPRESSED_RGBA_ASTC_4x4_KHR; + case tcuCompressedTexture.Format.ASTC_5x4_RGBA: return gl.COMPRESSED_RGBA_ASTC_5x4_KHR; + case tcuCompressedTexture.Format.ASTC_5x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_5x5_KHR; + case tcuCompressedTexture.Format.ASTC_6x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_6x5_KHR; + case tcuCompressedTexture.Format.ASTC_6x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_6x6_KHR; + case tcuCompressedTexture.Format.ASTC_8x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x5_KHR; + case tcuCompressedTexture.Format.ASTC_8x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x6_KHR; + case tcuCompressedTexture.Format.ASTC_8x8_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x8_KHR; + case tcuCompressedTexture.Format.ASTC_10x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x5_KHR; + case tcuCompressedTexture.Format.ASTC_10x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x6_KHR; + case tcuCompressedTexture.Format.ASTC_10x8_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x8_KHR; + case tcuCompressedTexture.Format.ASTC_10x10_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x10_KHR; + case tcuCompressedTexture.Format.ASTC_12x10_RGBA: return gl.COMPRESSED_RGBA_ASTC_12x10_KHR; + case tcuCompressedTexture.Format.ASTC_12x12_RGBA: return gl.COMPRESSED_RGBA_ASTC_12x12_KHR; + case tcuCompressedTexture.Format.ASTC_4x4_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; + case tcuCompressedTexture.Format.ASTC_5x4_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; + case tcuCompressedTexture.Format.ASTC_5x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; + case tcuCompressedTexture.Format.ASTC_6x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; + case tcuCompressedTexture.Format.ASTC_6x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; + case tcuCompressedTexture.Format.ASTC_8x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; + case tcuCompressedTexture.Format.ASTC_8x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + case tcuCompressedTexture.Format.ASTC_8x8_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + case tcuCompressedTexture.Format.ASTC_10x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + case tcuCompressedTexture.Format.ASTC_10x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + case tcuCompressedTexture.Format.ASTC_10x8_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + case tcuCompressedTexture.Format.ASTC_10x10_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + case tcuCompressedTexture.Format.ASTC_12x10_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + case tcuCompressedTexture.Format.ASTC_12x12_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;*/ + + default: + throw new Error("Can't map compressed format to GL format"); + } +}; + +/** + * @param {number} dataType + * @param {boolean} normalized + * @return {tcuTexture.ChannelType} + * @throws {Error} + */ +gluTextureUtil.mapGLChannelType = function(/* deMath.deUint32 */ dataType, /*boolean*/ normalized) { + // \note Normalized bit is ignored where it doesn't apply. + + switch (dataType) { + case gl.UNSIGNED_BYTE: return normalized ? tcuTexture.ChannelType.UNORM_INT8 : tcuTexture.ChannelType.UNSIGNED_INT8; + case gl.BYTE: return normalized ? tcuTexture.ChannelType.SNORM_INT8 : tcuTexture.ChannelType.SIGNED_INT8; + case gl.UNSIGNED_SHORT: return normalized ? tcuTexture.ChannelType.UNORM_INT16 : tcuTexture.ChannelType.UNSIGNED_INT16; + case gl.SHORT: return normalized ? tcuTexture.ChannelType.SNORM_INT16 : tcuTexture.ChannelType.SIGNED_INT16; + case gl.UNSIGNED_INT: return normalized ? tcuTexture.ChannelType.UNORM_INT32 : tcuTexture.ChannelType.UNSIGNED_INT32; + case gl.INT: return normalized ? tcuTexture.ChannelType.SNORM_INT32 : tcuTexture.ChannelType.SIGNED_INT32; + case gl.FLOAT: return tcuTexture.ChannelType.FLOAT; + case gl.UNSIGNED_SHORT_4_4_4_4: return tcuTexture.ChannelType.UNORM_SHORT_4444; + case gl.UNSIGNED_SHORT_5_5_5_1: return tcuTexture.ChannelType.UNORM_SHORT_5551; + case gl.UNSIGNED_SHORT_5_6_5: return tcuTexture.ChannelType.UNORM_SHORT_565; + case gl.HALF_FLOAT: return tcuTexture.ChannelType.HALF_FLOAT; + case gl.UNSIGNED_INT_2_10_10_10_REV: return normalized ? tcuTexture.ChannelType.UNORM_INT_1010102_REV : tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV; + case gl.UNSIGNED_INT_10F_11F_11F_REV: return tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV; + case gl.UNSIGNED_INT_24_8: return tcuTexture.ChannelType.UNSIGNED_INT_24_8; + case gl.FLOAT_32_UNSIGNED_INT_24_8_REV: return tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV; + case gl.UNSIGNED_INT_5_9_9_9_REV: return tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV; + + default: + throw new Error('Unsupported dataType ' + dataType); + } +}; + +/** + * @param {number} format Generic compressed format. + * @param {number} dataType + * @return {tcuTexture.TextureFormat} GL texture format. + * @throws {Error} + */ +gluTextureUtil.mapGLTransferFormat = function(format, dataType) { + switch (format) { + case gl.ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.A, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.LUMINANCE: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.L, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.LUMINANCE_ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.LA, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.RGB: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.RGBA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, gluTextureUtil.mapGLChannelType(dataType, true)); + //case gl.BGRA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.BGRA, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.RG: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.RED: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.RGBA_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, gluTextureUtil.mapGLChannelType(dataType, false)); + case gl.RGB_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, gluTextureUtil.mapGLChannelType(dataType, false)); + case gl.RG_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, gluTextureUtil.mapGLChannelType(dataType, false)); + case gl.RED_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, gluTextureUtil.mapGLChannelType(dataType, false)); + + case gl.DEPTH_COMPONENT: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, gluTextureUtil.mapGLChannelType(dataType, true)); + case gl.DEPTH_STENCIL: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, gluTextureUtil.mapGLChannelType(dataType, true)); + + default: + throw new Error("Can't map GL pixel format (" + deString.enumToString(gl, format) + ', ' + deString.enumToString(gl, dataType) + ') to texture format'); + } +}; + + /** + * Map GL internal texture format to tcuTexture.TextureFormat. + * + * If no mapping is found, throws Error. + * @param {number} internalFormat + * @return {tcuTexture.TextureFormat} GL texture format. + * @throws {Error} + */ +gluTextureUtil.mapGLInternalFormat = function(/*deMath.deUint32*/ internalFormat) { + if (internalFormat === undefined) + throw new Error('internalformat is undefined'); + + switch (internalFormat) { + case gl.RGB5_A1: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551); + case gl.RGBA4: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444); + case gl.RGB565: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565); + case gl.DEPTH_COMPONENT16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16); + case gl.STENCIL_INDEX8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8); + + case gl.RGBA32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT); + case gl.RGBA32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT32); + case gl.RGBA32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT32); + //TODO: Check which are available in WebGL 2 case gl.RGBA16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT16); + //case gl.RGBA16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT16); + case gl.RGBA16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.HALF_FLOAT); + case gl.RGBA16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT16); + case gl.RGBA16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT16); + case gl.RGBA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8); + case gl.RGBA8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT8); + case gl.RGBA8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT8); + case gl.SRGB8_ALPHA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8); + case gl.RGB10_A2: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT_1010102_REV); + case gl.RGB10_A2UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV); + case gl.RGBA8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT8); + + case gl.RGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8); + case gl.R11F_G11F_B10F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV); + case gl.RGB32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.FLOAT); + case gl.RGB32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT32); + case gl.RGB32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT32); + //case gl.RGB16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT16); + //case gl.RGB16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT16); + case gl.RGB16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.HALF_FLOAT); + case gl.RGB16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT16); + case gl.RGB16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT16); + case gl.RGB8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT8); + case gl.RGB8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT8); + case gl.RGB8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT8); + case gl.SRGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGB, tcuTexture.ChannelType.UNORM_INT8); + case gl.RGB9_E5: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV); + //case gl.RGB10: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT_1010102_REV); + + case gl.RG32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.FLOAT); + case gl.RG32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT32); + case gl.RG32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT32); + //case gl.RG16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT16); + //case gl.RG16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT16); + case gl.RG16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.HALF_FLOAT); + case gl.RG16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT16); + case gl.RG16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT16); + case gl.RG8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT8); + case gl.RG8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT8); + case gl.RG8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT8); + case gl.RG8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT8); + + case gl.R32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.FLOAT); + case gl.R32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT32); + case gl.R32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT32); + //case gl.R16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT16); + //case gl.R16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT16); + case gl.R16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.HALF_FLOAT); + case gl.R16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT16); + case gl.R16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT16); + case gl.R8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT8); + case gl.R8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT8); + case gl.R8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT8); + case gl.R8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT8); + + case gl.DEPTH_COMPONENT32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT); + case gl.DEPTH_COMPONENT24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8); + //case gl.DEPTH_COMPONENT32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT32); + case gl.DEPTH32F_STENCIL8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV); + case gl.DEPTH24_STENCIL8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.UNSIGNED_INT_24_8); + + default: + throw new Error("Can't map GL sized internal format (" + internalFormat.toString(16) + ') to texture format'); + } +}; + +/** + * @param {number} format + * @return {boolean} + */ +gluTextureUtil.isGLInternalColorFormatFilterable = function(format) { + switch (format) { + case gl.R8: + case gl.R8_SNORM: + case gl.RG8: + case gl.RG8_SNORM: + case gl.RGB8: + case gl.RGB8_SNORM: + case gl.RGB565: + case gl.RGBA4: + case gl.RGB5_A1: + case gl.RGBA8: + case gl.RGBA8_SNORM: + case gl.RGB10_A2: + case gl.SRGB8: + case gl.SRGB8_ALPHA8: + case gl.R16F: + case gl.RG16F: + case gl.RGB16F: + case gl.RGBA16F: + case gl.R11F_G11F_B10F: + case gl.RGB9_E5: + return true; + + case gl.RGB10_A2UI: + case gl.R32F: + case gl.RG32F: + case gl.RGB32F: + case gl.RGBA32F: + case gl.R8I: + case gl.R8UI: + case gl.R16I: + case gl.R16UI: + case gl.R32I: + case gl.R32UI: + case gl.RG8I: + case gl.RG8UI: + case gl.RG16I: + case gl.RG16UI: + case gl.RG32I: + case gl.RG32UI: + case gl.RGB8I: + case gl.RGB8UI: + case gl.RGB16I: + case gl.RGB16UI: + case gl.RGB32I: + case gl.RGB32UI: + case gl.RGBA8I: + case gl.RGBA8UI: + case gl.RGBA16I: + case gl.RGBA16UI: + case gl.RGBA32I: + case gl.RGBA32UI: + return false; + + default: + throw new Error('Unrecognized format ' + format); + } +}; + +/** + * @param {number} wrapMode + * @return {tcuTexture.WrapMode} + */ +gluTextureUtil.mapGLWrapMode = function(wrapMode) { + switch (wrapMode) { + case gl.CLAMP_TO_EDGE: return tcuTexture.WrapMode.CLAMP_TO_EDGE; + case gl.REPEAT: return tcuTexture.WrapMode.REPEAT_GL; + case gl.MIRRORED_REPEAT: return tcuTexture.WrapMode.MIRRORED_REPEAT_GL; + default: + throw new Error("Can't map GL wrap mode " + deString.enumToString(gl, wrapMode)); + } +}; + +/** + * @param {number} filterMode + * @return {tcuTexture.FilterMode} + * @throws {Error} + */ +gluTextureUtil.mapGLFilterMode = function(filterMode) { + switch (filterMode) { + case gl.NEAREST: return tcuTexture.FilterMode.NEAREST; + case gl.LINEAR: return tcuTexture.FilterMode.LINEAR; + case gl.NEAREST_MIPMAP_NEAREST: return tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST; + case gl.NEAREST_MIPMAP_LINEAR: return tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR; + case gl.LINEAR_MIPMAP_NEAREST: return tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST; + case gl.LINEAR_MIPMAP_LINEAR: return tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR; + default: + throw new Error("Can't map GL filter mode" + filterMode); + } +}; + +/* TODO: Port the code below */ +// /*--------------------------------------------------------------------*//*! +// * \brief Map GL sampler parameters to tcu::Sampler. +// * +// * If no mapping is found, throws tcu::InternalError. +// * +// * \param wrapS S-component wrap mode +// * \param minFilter Minification filter mode +// * \param magFilter Magnification filter mode +// * \return Sampler description. +// *//*--------------------------------------------------------------------*/ +// /*tcu::Sampler mapGLSamplerWrapS (deUint32 wrapS, deUint32 minFilter, deUint32 magFilter) +// { +// return mapGLSampler(wrapS, wrapS, wrapS, minFilter, magFilter); +// } +// */ + +/** + * Map GL sampler parameters to tcu::Sampler. + * + * If no mapping is found, throws tcu::InternalError. + * + * @param {number} wrapS S-component wrap mode + * @param {number} wrapT T-component wrap mode + * @param {number} minFilter Minification filter mode + * @param {number} magFilter Magnification filter mode + * @return {tcuTexture.Sampler} + */ +gluTextureUtil.mapGLSamplerWrapST = function(wrapS, wrapT, minFilter, magFilter) { + return gluTextureUtil.mapGLSampler(wrapS, wrapT, wrapS, minFilter, magFilter); +}; + +/** + * Map GL sampler parameters to tcu::Sampler. + * + * If no mapping is found, throws tcu::InternalError. + * @param {number} wrapS S-component wrap mode + * @param {number} wrapT T-component wrap mode + * @param {number} wrapR R-component wrap mode + * @param {number} minFilter Minification filter mode + * @param {number} magFilter Magnification filter mode + * @return {tcuTexture.Sampler} + */ +gluTextureUtil.mapGLSampler = function(wrapS, wrapT, wrapR, minFilter, magFilter) { + return new tcuTexture.Sampler( + gluTextureUtil.mapGLWrapMode(wrapS), + gluTextureUtil.mapGLWrapMode(wrapT), + gluTextureUtil.mapGLWrapMode(wrapR), + gluTextureUtil.mapGLFilterMode(minFilter), + gluTextureUtil.mapGLFilterMode(magFilter), + 0.0, + true, + tcuTexture.CompareMode.COMPAREMODE_NONE, + 0, + [0.0, 0.0, 0.0, 0.0]); +}; + +// /*--------------------------------------------------------------------*//*! +// * \brief Map GL compare function to tcu::Sampler::CompareMode. +// * +// * If no mapping is found, throws tcu::InternalError. +// * +// * \param mode GL compare mode +// * \return Compare mode +// *//*--------------------------------------------------------------------*/ +/** + * @param {number} mode + */ +gluTextureUtil.mapGLCompareFunc = function(mode) { + switch (mode) { + case gl.LESS: return tcuTexture.CompareMode.COMPAREMODE_LESS; + case gl.LEQUAL: return tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL; + case gl.GREATER: return tcuTexture.CompareMode.COMPAREMODE_GREATER; + case gl.GEQUAL: return tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL; + case gl.EQUAL: return tcuTexture.CompareMode.COMPAREMODE_EQUAL; + case gl.NOTEQUAL: return tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL; + case gl.ALWAYS: return tcuTexture.CompareMode.COMPAREMODE_ALWAYS; + case gl.NEVER: return tcuTexture.CompareMode.COMPAREMODE_NEVER; + default: + throw new Error("Can't map GL compare mode " + mode); + } +}; + +/** + * Get GL wrap mode. + * + * If no mapping is found, throws tcu::InternalError. + * + * @param {tcuTexture.WrapMode} wrapMode + * @return {number} GL wrap mode + */ +gluTextureUtil.getGLWrapMode = function(wrapMode) { + switch (wrapMode) { + case tcuTexture.WrapMode.CLAMP_TO_EDGE: return gl.CLAMP_TO_EDGE; + case tcuTexture.WrapMode.REPEAT_GL: return gl.REPEAT; + case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: return gl.MIRRORED_REPEAT; + default: + throw new Error("Can't map wrap mode"); + } +}; + +/** + * Get GL filter mode. + * + * If no mapping is found, throws tcu::InternalError. + * + * @param {tcuTexture.FilterMode} filterMode Filter mode + * @return {number} GL filter mode + */ +gluTextureUtil.getGLFilterMode = function(filterMode) { + switch (filterMode) { + case tcuTexture.FilterMode.NEAREST: return gl.NEAREST; + case tcuTexture.FilterMode.LINEAR: return gl.LINEAR; + case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: return gl.NEAREST_MIPMAP_NEAREST; + case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: return gl.NEAREST_MIPMAP_LINEAR; + case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: return gl.LINEAR_MIPMAP_NEAREST; + case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: return gl.LINEAR_MIPMAP_LINEAR; + default: + throw new Error("Can't map filter mode"); + } +}; + +/** + * Get GL compare mode. + * + * If no mapping is found, throws tcu::InternalError. + * + * @param {tcuTexture.CompareMode} compareMode Compare mode + * @return {number} GL compare mode + */ +gluTextureUtil.getGLCompareFunc = function(compareMode) { + switch (compareMode) { + case tcuTexture.CompareMode.COMPAREMODE_NONE: return gl.NONE; + case tcuTexture.CompareMode.COMPAREMODE_LESS: return gl.LESS; + case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL: return gl.LEQUAL; + case tcuTexture.CompareMode.COMPAREMODE_GREATER: return gl.GREATER; + case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL: return gl.GEQUAL; + case tcuTexture.CompareMode.COMPAREMODE_EQUAL: return gl.EQUAL; + case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL: return gl.NOTEQUAL; + case tcuTexture.CompareMode.COMPAREMODE_ALWAYS: return gl.ALWAYS; + case tcuTexture.CompareMode.COMPAREMODE_NEVER: return gl.NEVER; + default: + throw new Error("Can't map compare mode"); + } +}; + +/** + * Get GL cube face. + * + * If no mapping is found, throws tcu::InternalError. + * + * @param {tcuTexture.CubeFace} face Cube face + * @return {number} GL cube face + */ +gluTextureUtil.getGLCubeFace = function(face) { + switch (face) { + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: + return gl.TEXTURE_CUBE_MAP_NEGATIVE_X; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: + return gl.TEXTURE_CUBE_MAP_POSITIVE_X; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: + return gl.TEXTURE_CUBE_MAP_NEGATIVE_Y; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: + return gl.TEXTURE_CUBE_MAP_POSITIVE_Y; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: + return gl.TEXTURE_CUBE_MAP_NEGATIVE_Z; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: + return gl.TEXTURE_CUBE_MAP_POSITIVE_Z; + default: + throw Error("Can't map cube face"); + } +}; + +// /*--------------------------------------------------------------------*//*! +// * \brief Get GLSL sampler type for texture format. +// * +// * If no mapping is found, glu::TYPE_LAST is returned. +// * +// * \param format Texture format +// * \return GLSL 1D sampler type for format +// *//*--------------------------------------------------------------------*/ +// DataType getSampler1DType (tcu::TextureFormat format) +// { +// using tcu::TextureFormat; + +// if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) +// return TYPE_SAMPLER_1D; + +// if (format.order == tcuTexture.ChannelOrder.S) +// return TYPE_LAST; + +// switch (tcu::getTextureChannelClass(format.type)) +// { +// case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: +// case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: +// case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: +// return glu::TYPE_SAMPLER_1D; + +// case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: +// return glu::TYPE_INT_SAMPLER_1D; + +// case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: +// return glu::TYPE_UINT_SAMPLER_1D; + +// default: +// return glu::TYPE_LAST; +// } +// } + +/** + * Get GLSL sampler type for texture format. + * If no mapping is found, glu::TYPE_LAST is returned. + * + * @param {tcuTexture.TextureFormat} format + * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format + */ +gluTextureUtil.getSampler2DType = function(format) { + if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) + return gluShaderUtil.DataType.SAMPLER_2D; + + if (format.order == tcuTexture.ChannelOrder.S) + return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length); + + switch (tcuTexture.getTextureChannelClass(format.type)) { + case tcuTexture.TextureChannelClass.FLOATING_POINT: + case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: + case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: + return gluShaderUtil.DataType.SAMPLER_2D; + + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + return gluShaderUtil.DataType.INT_SAMPLER_2D; + + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + return gluShaderUtil.DataType.UINT_SAMPLER_2D; + + default: + return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length); + } +}; + +/** + * + * @param {tcuTexture.TextureFormat} format + * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format + */ +gluTextureUtil.getSampler3DType = function(format) { + if (format.order === tcuTexture.ChannelOrder.D || format.order === tcuTexture.ChannelOrder.DS) + return gluShaderUtil.DataType.SAMPLER_3D; + + if (format.order === tcuTexture.ChannelOrder.S) + return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length); // shouldn't we throw an error instead? + + switch (tcuTexture.getTextureChannelClass(format.type)) { + case tcuTexture.TextureChannelClass.FLOATING_POINT: + case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: + case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: + return gluShaderUtil.DataType.SAMPLER_3D; + + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + return gluShaderUtil.DataType.INT_SAMPLER_3D; + + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + return gluShaderUtil.DataType.UINT_SAMPLER_3D; + + default: + return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length); + } +}; + +/** + * \brief Get GLSL sampler type for texture format. + * + * @param {tcuTexture.TextureFormat} format + * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format + */ +gluTextureUtil.getSamplerCubeType = function(format) { + if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) + return gluShaderUtil.DataType.SAMPLER_CUBE; + + if (format.order == tcuTexture.ChannelOrder.S) + throw new Error('No cube sampler'); + + switch (tcuTexture.getTextureChannelClass(format.type)) { + case tcuTexture.TextureChannelClass.FLOATING_POINT: + case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: + case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: + return gluShaderUtil.DataType.SAMPLER_CUBE; + + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + return gluShaderUtil.DataType.INT_SAMPLER_CUBE; + + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + return gluShaderUtil.DataType.UINT_SAMPLER_CUBE; + + default: + throw new Error('No cube sampler'); + } +}; + +/** + * \brief Get GLSL sampler type for texture format. + * + * If no mapping is found, glu::TYPE_LAST is returned. + * + * @param {tcuTexture.TextureFormat} format + * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format + */ +gluTextureUtil.getSampler2DArrayType = function(format) { + + if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) + return gluShaderUtil.DataType.SAMPLER_2D_ARRAY; + + if (format.order == tcuTexture.ChannelOrder.S) + throw new Error('No 2d array sampler'); + + switch (tcuTexture.getTextureChannelClass(format.type)) { + case tcuTexture.TextureChannelClass.FLOATING_POINT: + case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: + case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: + return gluShaderUtil.DataType.SAMPLER_2D_ARRAY; + + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + return gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY; + + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + return gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY; + + default: + throw new Error('No 2d array sampler'); + } +}; + +/** + * \brief Get GLSL sampler type for texture format. + * + * If no mapping is found, glu::TYPE_LAST is returned. + * + * @param {tcuTexture.TextureFormat} format + * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format + */ +gluTextureUtil.getSampler3D = function(format) { + if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) + return gluShaderUtil.DataType.SAMPLER_3D; + + if (format.order == tcuTexture.ChannelOrder.S) + throw new Error('No 3d sampler'); + + switch (tcuTexture.getTextureChannelClass(format.type)) { + case tcuTexture.TextureChannelClass.FLOATING_POINT: + case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT: + case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT: + return gluShaderUtil.DataType.SAMPLER_3D; + + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + return gluShaderUtil.DataType.INT_SAMPLER_3D; + + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + return gluShaderUtil.DataType.UINT_SAMPLER_3D; + + default: + throw new Error('No 3d sampler'); + } +}; + +gluTextureUtil.RenderableType = { + RENDERABLE_COLOR: (1<<0), + RENDERABLE_DEPTH: (1<<1), + RENDERABLE_STENCIL: (1<<2) +}; + +/** + * \brief Get renderable bits. + * \note Works currently only on ES3 context. + * + * @param {number} internalFormat + * @return {gluTextureUtil.RenderableType} + */ +gluTextureUtil.getRenderableBitsES3 = function(internalFormat) +{ + switch (internalFormat) + { + // Color-renderable formats + case gl.RGBA32I: + case gl.RGBA32UI: + case gl.RGBA16I: + case gl.RGBA16UI: + case gl.RGBA8: + case gl.RGBA8I: + case gl.RGBA8UI: + case gl.SRGB8_ALPHA8: + case gl.RGB10_A2: + case gl.RGB10_A2UI: + case gl.RGBA4: + case gl.RGB5_A1: + case gl.RGB8: + case gl.RGB565: + case gl.RG32I: + case gl.RG32UI: + case gl.RG16I: + case gl.RG16UI: + case gl.RG8: + case gl.RG8I: + case gl.RG8UI: + case gl.R32I: + case gl.R32UI: + case gl.R16I: + case gl.R16UI: + case gl.R8: + case gl.R8I: + case gl.R8UI: + return gluTextureUtil.RenderableType.RENDERABLE_COLOR; + + // EXT_color_buffer_float + case gl.RGBA32F: + case gl.R11F_G11F_B10F: + case gl.RG32F: + case gl.R32F: + case gl.RGBA16F: + case gl.RG16F: + case gl.R16F: + if (gl.getExtension("EXT_color_buffer_float")) + return gluTextureUtil.RenderableType.RENDERABLE_COLOR; + else + return 0; + + // Depth formats + case gl.DEPTH_COMPONENT32F: + case gl.DEPTH_COMPONENT24: + case gl.DEPTH_COMPONENT16: + return gluTextureUtil.RenderableType.RENDERABLE_DEPTH; + + // Depth+stencil formats + case gl.DEPTH32F_STENCIL8: + case gl.DEPTH24_STENCIL8: + return gluTextureUtil.RenderableType.RENDERABLE_DEPTH | gluTextureUtil.RenderableType.RENDERABLE_STENCIL; + + // Stencil formats + case gl.STENCIL_INDEX8: + return gluTextureUtil.RenderableType.RENDERABLE_STENCIL; + + default: + return 0; + } +} + +/** + * \brief Check if sized internal format is color-renderable. + * \note Works currently only on ES3 context. + * + * @param {number} sizedFormat + * @return {boolean} + */ +gluTextureUtil.isSizedFormatColorRenderable = function(sizedFormat) +{ + var renderable = 0; + renderable = gluTextureUtil.getRenderableBitsES3(sizedFormat); + return (renderable & gluTextureUtil.RenderableType.RENDERABLE_COLOR) != 0; +} + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js new file mode 100644 index 0000000000..a05f1c1e5c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js @@ -0,0 +1,814 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluVarType'); +goog.require('framework.opengl.gluShaderUtil'); + +goog.scope(function() { + + var gluVarType = framework.opengl.gluVarType; + var gluShaderUtil = framework.opengl.gluShaderUtil; + + /** + * gluVarType.VarType types enum + * @enum {number} + */ + gluVarType.Type = { + TYPE_BASIC: 0, + TYPE_ARRAY: 1, + TYPE_STRUCT: 2 + }; + + /** + * gluVarType.TypeArray struct + * @param {gluVarType.VarType} elementType + * @param {number} arraySize + * @constructor + */ + gluVarType.TypeArray = function(elementType, arraySize) { + /** @type {gluVarType.VarType} */ this.elementType = gluVarType.newClone(elementType); + /** @type {number} */ this.size = arraySize; + }; + + /** + * gluVarType.VarType class + * @constructor + */ + gluVarType.VarType = function() { + /** + * @type {gluShaderUtil.precision} + * @private + */ + this.m_flags; + + /** + * @type {number} + * @private + */ + this.m_type = -1; + + /** + * m_data used to be a 'Data' union in C++. Using a var is enough here. + * it will contain any necessary value. + * case TYPE_BASIC: number + * case TYPE_ARRAY: gluVarType.TypeArray + * case TYPE_STRUCT: gluVarType.StructType + * @private + * @type {(number|gluVarType.TypeArray|gluVarType.StructType)} + */ + this.m_data = null; + }; + + gluVarType.VarType.UNSIZED_ARRAY = -1; + + /** + * Creates a basic type gluVarType.VarType. Use this after the constructor call. + * @param {number} basicType + * @param {gluShaderUtil.precision} flags + * @return {gluVarType.VarType} The currently modified object + */ + gluVarType.VarType.prototype.VarTypeBasic = function(basicType, flags) { + this.m_type = gluVarType.Type.TYPE_BASIC; + this.m_flags = flags; + this.m_data = basicType; + + return this; + }; + + /** + * Creates a basic type gluVarType.VarType with type boolean and undefined precision. + * @param {number} basicType + * @return {gluVarType.VarType} The currently modified object + */ + gluVarType.VarType.prototype.VarTypeBoolean = function(basicType) { + this.m_type = gluVarType.Type.TYPE_BASIC; + this.m_data = basicType; + + return this; + }; + + /** + * Creates an array type gluVarType.VarType. Use this after the constructor call. + * @param {gluVarType.VarType} elementType + * @param {number} arraySize + * @return {gluVarType.VarType} The currently modified object + */ + gluVarType.VarType.prototype.VarTypeArray = function(elementType, arraySize) { + this.m_type = gluVarType.Type.TYPE_ARRAY; + if (!(arraySize >= 0 || arraySize == gluVarType.VarType.UNSIZED_ARRAY)) + throw new Error('Illegal array size: ' + arraySize); + this.m_data = new gluVarType.TypeArray(elementType, arraySize); + + return this; + }; + + /** + * Creates a struct type gluVarType.VarType. Use this after the constructor call. + * @param {gluVarType.StructType} structPtr + * @return {gluVarType.VarType} The currently modified object + */ + gluVarType.VarType.prototype.VarTypeStruct = function(structPtr) { + this.m_type = gluVarType.Type.TYPE_STRUCT; + this.m_data = structPtr; + + return this; + }; + + /** + * Creates a gluVarType.VarType, the same type as the passed in object. + * Use this after the constructor call. + * @param {gluVarType.VarType} object + * @return {gluVarType.VarType} The currently modified object + */ + gluVarType.VarType.prototype.VarTypeClone = function(object) { + + this.m_type = object.m_type; + + switch (this.m_type) { + case gluVarType.Type.TYPE_BASIC: + this.m_flags = object.m_flags; + this.m_data = object.m_data; + break; + case gluVarType.Type.TYPE_BASIC: + this.m_data = new gluVarType.TypeArray(object.m_data.elementType, object.m_data.size); + break; + case gluVarType.Type.TYPE_STRUCT: + this.m_data = object.m_data; + break; + default: + throw new Error('unknown type: ' + this.m_type); + } + + return this; + }; + + /** isBasicType + * @return {boolean} true if the gluVarType.VarType represents a basic type. + */ + gluVarType.VarType.prototype.isBasicType = function() { + return this.m_type == gluVarType.Type.TYPE_BASIC; + }; + + /** isArrayType + * @return {boolean} true if the gluVarType.VarType represents an array. + */ + gluVarType.VarType.prototype.isArrayType = function() { + return this.m_type == gluVarType.Type.TYPE_ARRAY; + }; + + /** isStructType + * @return {boolean} true if the gluVarType.VarType represents a struct. + */ + gluVarType.VarType.prototype.isStructType = function() { + return this.m_type == gluVarType.Type.TYPE_STRUCT; + }; + + /** getFlags + * @return {number} returns the flags of the gluVarType.VarType. + */ + gluVarType.VarType.prototype.getFlags = function() { + return this.m_flags; + }; + + /** getBasicType + * @return {gluShaderUtil.DataType<number>} returns the basic data type of the gluVarType.VarType. + */ + gluVarType.VarType.prototype.getBasicType = function() { + if (!this.isBasicType()) + throw new Error('VarType is not a basic type.'); + return /** @type {gluShaderUtil.DataType<number>} */ (this.m_data); + }; + + /** getPrecision + * @return {gluShaderUtil.precision} returns the precision flag. + */ + gluVarType.VarType.prototype.getPrecision = function() { + if (!this.isBasicType()) + throw new Error('VarType is not a basic type.'); + return this.m_flags; + }; + + /** getElementType + * @return {gluVarType.VarType} returns the gluVarType.VarType of the element in case of an Array. + */ + gluVarType.VarType.prototype.getElementType = function() { + if (!this.isArrayType()) + throw new Error('VarType is not an array type.'); + 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. + */ + gluVarType.VarType.prototype.getArraySize = function() { + if (!this.isArrayType()) + throw new Error('VarType is not an array type.'); + return this.m_data.size; + }; + + /** getStruct + * @return {gluVarType.StructType} returns the structure when it is a gluVarType.StructType. + */ + gluVarType.VarType.prototype.getStruct = function() { + if (!this.isStructType()) + throw new Error('VarType is not a struct type.'); + return /** @type {gluVarType.StructType} */ (this.m_data); + }; + + /** + * getScalarSize + * @return {number} size of the scalar + */ + gluVarType.VarType.prototype.getScalarSize = function() { + switch (this.m_type) { + case gluVarType.Type.TYPE_BASIC: { + return gluShaderUtil.getDataTypeScalarSize(/** @type {gluShaderUtil.DataType} */(this.getBasicType())); + } + + // TODO: check implementation below: return m_data.array.elementType->getScalarSize()*m_data.array.size; + case gluVarType.Type.TYPE_ARRAY: { + var m_data = /** @type {gluVarType.TypeArray} */(this.m_data); + return m_data.elementType.getScalarSize() * m_data.size; + } + + case gluVarType.Type.TYPE_STRUCT: { + var size = 0; + + var struct = /** @type {gluVarType.StructType} */ (this.m_data); + + // TODO: check loop conditions below + // for (gluVarType.StructType::ConstIterator iter = m_data.structPtr->begin(); iter != m_data.structPtr->end(); iter++) + for (var iter = 0; struct.m_members[iter] < struct.getSize(); iter++) + size += struct.getMember(iter).m_type.getScalarSize(); + return size; + } + + default: + // throw new Error('Unexpected type.'); + return 0; + } + }; + + /** + * is + * @return {boolean} returns true if the current object is equivalent to other. + */ + gluVarType.VarType.prototype.is = function(other) { + if (this.m_type != other.m_type) + return false; + + switch (this.m_type) { + case gluVarType.Type.TYPE_BASIC: + return this.m_data == other.m_data && + this.m_flags == other.m_flags; + + case gluVarType.Type.TYPE_ARRAY: + return this.m_data.elementType == other.m_data.elementType && + this.m_data.size == other.m_data.size; + + case gluVarType.Type.TYPE_STRUCT: + return this.m_data === other.m_data; + + default: + // throw new Error('Unexpected type.'); + return false; + } + }; + + /** + * isnt + * @return {boolean} returns true if the current object is not equivalent to other. + */ + gluVarType.VarType.prototype.isnt = function(other) { + return !(this.is(other)); + }; + + /** + * Creates a basic type gluVarType.VarType. + * @param {gluShaderUtil.DataType} basicType + * @param {framework.opengl.gluShaderUtil.precision=} flags + * @return {gluVarType.VarType} + */ + gluVarType.newTypeBasic = function(basicType, flags) { + if (!gluShaderUtil.isDataTypeBoolOrBVec(basicType)) + return new gluVarType.VarType().VarTypeBasic(basicType, /** @type {framework.opengl.gluShaderUtil.precision}*/ (flags)); + else + return new gluVarType.VarType().VarTypeBoolean(basicType); + }; + + /** + * Creates an array type gluVarType.VarType. + * @param {gluVarType.VarType} elementType + * @param {number} arraySize + * @return {gluVarType.VarType} + */ + gluVarType.newTypeArray = function(elementType, arraySize) { + return new gluVarType.VarType().VarTypeArray(elementType, arraySize); + }; + + /** + * Creates a struct type gluVarType.VarType. + * @param {gluVarType.StructType} structPtr + * @return {gluVarType.VarType} + */ + gluVarType.newTypeStruct = function(structPtr) { + return new gluVarType.VarType().VarTypeStruct(structPtr); + }; + + /** + * Creates a struct type gluVarType.VarType. + * @param {gluVarType.VarType} object + * @return {gluVarType.VarType} + */ + gluVarType.newClone = function(object) { + return new gluVarType.VarType().VarTypeClone(object); + }; + + /** + * gluVarType.StructMember class + * @constructor + */ + gluVarType.StructMember = function() { + /** @type {string} */ this.m_name; + /** @type {gluVarType.VarType} */ this.m_type; + /** @type {number} */ // this.m_flags = 0; // only in glsUniformBlockCase + }; + + /** + * Creates a gluVarType.StructMember. Use this after the constructor call. + * @param {string} name + * @param {gluVarType.VarType} type + * @return {gluVarType.StructMember} The currently modified object + */ + gluVarType.StructMember.prototype.Constructor = function(name, type) { + this.m_type = type; + this.m_name = name; + + return this; + }; + + /** getName + * @return {string} name of the gluVarType.StructMember object. + */ + gluVarType.StructMember.prototype.getName = function() { + return this.m_name; + }; + + /** getType + * @return {gluVarType.VarType} type of the gluVarType.StructMember object. + */ + gluVarType.StructMember.prototype.getType = function() { + return this.m_type; + }; + + /** + * Creates a gluVarType.StructMember. + * @param {string} name + * @param {gluVarType.VarType} type + * @return {gluVarType.StructMember} + */ + gluVarType.newStructMember = function(name, type) { + return new gluVarType.StructMember().Constructor(name, type); + }; + + /** + * gluVarType.StructType class + * @constructor + */ + gluVarType.StructType = function() { + /** @type {string} */ this.m_typeName = ''; + /** @type {Array<gluVarType.StructMember>} */ this.m_members = []; + }; + + /** + * Creates a gluVarType.StructType. Use this after the constructor call. + * @param {string} name + * @return {gluVarType.StructType} The currently modified object + */ + gluVarType.StructType.prototype.Constructor = function(name) { + /** @type {string}*/ this.m_typeName = this.setTypeName(name); + return this; + }; + + /** hasTypeName + * Checks if the gluVarType.StructType m_typeName is defined + * @return {boolean} + */ + gluVarType.StructType.prototype.hasTypeName = function() { + return (this.m_typeName !== 'undefined'); + }; + + /** setTypeName + * @param {string} name + * @return {string} returns gluVarType.StructType.m_typeName + */ + gluVarType.StructType.prototype.setTypeName = function(name) { + return this.m_typeName = name; + }; + + /** getTypeName + * @return {string} + */ + gluVarType.StructType.prototype.getTypeName = function() { + return this.m_typeName; + }; + + /** getNumMembers + * @return {number} + */ + gluVarType.StructType.prototype.getNumMembers = function() { + return this.m_members.length; + }; + + /** getMember + * @param {number} memberNdx The index of the member to retrieve. + * @return {gluVarType.StructMember} + */ + gluVarType.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 StructTypes members'); + } + }; + + /** getSize + * @return {number} The size of the m_members array. + */ + gluVarType.StructType.prototype.getSize = function() { + return this.m_members.length; + }; + + /** addMember + * @param {string} name + * @param {gluVarType.VarType} type + */ + gluVarType.StructType.prototype.addMember = function(name, type) { + var member = gluVarType.newStructMember(name, type); + this.m_members.push(member); + }; + + /** + * Creates a gluVarType.StructType. + * @param {string} name + * @return {gluVarType.StructType} + */ + gluVarType.newStructType = function(name) { + return new gluVarType.StructType().Constructor(name); + }; + + /** + * @param {number} level + * @return {string} + */ + gluVarType.indent = function(level) { + /** @type {string} */ var str = ''; + for (var i = 0; i < level; i++) + str += '\t'; + return str; + }; + + /** + * @param {gluVarType.VarType} varType + * @param {string} name + * @param {number=} level + * @return {string} + */ + gluVarType.declareVariable = function(varType, name, level) { + /** @type {string} */ var str = ''; + /** @type {gluVarType.VarType} */ var type = varType; + /** @type {gluVarType.VarType} */ var curType = type; + /** @type {Array<number>} */ var arraySizes = []; + + // Handle arrays. + while (curType.isArrayType()) { + arraySizes.push(curType.getArraySize()); + curType = curType.getElementType(); + } + + if (curType.isBasicType()) { + if (curType.getPrecision() !== undefined) + str += gluShaderUtil.getPrecisionName(curType.getPrecision()) + ' '; + str += gluShaderUtil.getDataTypeName(/** @type {gluShaderUtil.DataType} */(curType.getBasicType())); + } else if (curType.isStructType()) { + /** @type {gluVarType.StructType} */ var structPtr = curType.getStruct(); + + if (structPtr.hasTypeName()) + str += structPtr.getTypeName(); + else + str += gluVarType.declareStructType(structPtr, level); // Generate inline declaration. + } else + throw new Error('Unexpected Array typed VarType.'); + + str += ' ' + name; + + // Print array sizes. + for (var size = 0; size < arraySizes.length; size++) { //std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++) { + /** @type {number} */ var arrSize = arraySizes[size]; + if (arrSize == gluVarType.VarType.UNSIZED_ARRAY) + str += '[]'; + else + str += '[' + arrSize + ']'; + } + + return str; + }; + + /** + * @param {gluVarType.StructType} structType + * @param {number=} level + * @return {string} + */ + gluVarType.declareStructType = function(structType, level) { + /** @type {string} */ var str = 'struct'; + level = level || 0; + + // gluVarType.Type name is optional. + if (structType.hasTypeName()) + str += ' ' + structType.getTypeName(); + + str += '\n' + gluVarType.indent(level) + ' {\n'; + + for (var memberNdx = 0; memberNdx < structType.getSize(); memberNdx++) { //gluVarType.StructType::ConstIterator memberIter = decl.structPtr->begin(); memberIter != decl.structPtr->end(); memberIter++) { + /** @type {gluVarType.StructMember} */ var memberIter = structType.getMember(memberNdx); + str += gluVarType.indent(level + 1); + str += gluVarType.declareVariable(memberIter.getType(), memberIter.getName(), level + 1) + ';\n'; + } + + str += gluVarType.indent(level) + '}'; + + return str; + }; + + /** + * @param {*} T + * @param {number=} size + * @param {gluShaderUtil.precision=} precision + * @return {gluVarType.VarType} + */ + gluVarType.getVarTypeOf = function(T, size, precision) { + size = size || 1; + precision = precision || gluShaderUtil.precision.PRECISION_LOWP; + switch (size) { + case 4: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, precision); + case 3: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC3, precision); + case 2: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC2, precision); + } + switch (T) { + case 'float' : return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT, precision); + case 'vec4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, precision); + case 'vec3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC3, precision); + case 'vec2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC2, precision); + case 'mat2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2, precision); + case 'mat2x3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2X3, precision); + case 'mat2x4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2X4, precision); + case 'mat3x2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3X2, precision); + case 'mat3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3, precision); + case 'mat3x4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3X4, precision); + case 'mat4x2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4X2, precision); + case 'mat4x3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4X3, precision); + case 'mat4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4, precision); + } + throw new Error('Invalid input type ' + T + ' or size ' + size); + }; + + /** + * @enum + */ + gluVarType.Storage = { + STORAGE_IN: 0, + STORAGE_OUT: 1, + STORAGE_CONST: 2, + STORAGE_UNIFORM: 3, + STORAGE_BUFFER: 4 + }; + + /** + * @param {gluVarType.Storage} storage + * @return {string} + */ + gluVarType.getStorageName = function(storage) { + switch (storage) { + case gluVarType.Storage.STORAGE_IN: return 'in'; + case gluVarType.Storage.STORAGE_OUT: return 'out'; + case gluVarType.Storage.STORAGE_CONST: return 'const'; + case gluVarType.Storage.STORAGE_UNIFORM: return 'uniform'; + case gluVarType.Storage.STORAGE_BUFFER: return 'buffer'; + default: + throw new Error('Unknown storage: ' + storage); + } + }; + + /** + * @enum + */ + gluVarType.Interpolation = { + INTERPOLATION_SMOOTH: 0, + INTERPOLATION_FLAT: 1, + INTERPOLATION_CENTROID: 2 + }; + + /** + * @param {gluVarType.Interpolation} interpolation + * @return {string} + */ + gluVarType.getInterpolationName = function(interpolation) { + switch (interpolation) { + case gluVarType.Interpolation.INTERPOLATION_SMOOTH: return 'smooth'; + case gluVarType.Interpolation.INTERPOLATION_FLAT: return 'flat'; + case gluVarType.Interpolation.INTERPOLATION_CENTROID: return 'centrod'; + default: + throw new Error('Unknown interpolation: ' + interpolation); + } + }; + + /** + * @enum + */ + gluVarType.FormatLayout = { + FORMATLAYOUT_RGBA32F: 0, + FORMATLAYOUT_RGBA16F: 1, + FORMATLAYOUT_R32F: 2, + FORMATLAYOUT_RGBA8: 3, + FORMATLAYOUT_RGBA8_SNORM: 4, + + FORMATLAYOUT_RGBA32I: 5, + FORMATLAYOUT_RGBA16I: 6, + FORMATLAYOUT_RGBA8I: 7, + FORMATLAYOUT_R32I: 8, + + FORMATLAYOUT_RGBA32UI: 9, + FORMATLAYOUT_RGBA16UI: 10, + FORMATLAYOUT_RGBA8UI: 11, + FORMATLAYOUT_R32UI: 12 + }; + + /** + * @param {gluVarType.FormatLayout} layout + * @return {string} + */ + gluVarType.getFormatLayoutName = function(layout) { + switch (layout) { + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32F: return 'rgba32f'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16F: return 'rgba16f'; + case gluVarType.FormatLayout.FORMATLAYOUT_R32F: return 'r32f'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8: return 'rgba8'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8_SNORM: return 'rgba8_snorm'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32I: return 'rgba32i'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16I: return 'rgba16i'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8I: return 'rgba8i'; + case gluVarType.FormatLayout.FORMATLAYOUT_R32I: return 'r32i'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32UI: return 'rgba32ui'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16UI: return 'rgba16ui'; + case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8UI: return 'rgba8ui'; + case gluVarType.FormatLayout.FORMATLAYOUT_R32UI: return 'r32ui'; + default: + throw new Error('Unknown layout: ' + layout); + } + }; + + /** + * @enum + */ + gluVarType.MatrixOrder = { + MATRIXORDER_COLUMN_MAJOR: 0, + MATRIXORDER_ROW_MAJOR: 1 + }; + + /** + * @param {gluVarType.MatrixOrder} qualifier + * @return {string} + */ + gluVarType.getMatrixOrderName = function(qualifier) { + switch (qualifier) { + case gluVarType.MatrixOrder.MATRIXORDER_COLUMN_MAJOR: return 'column_major'; + case gluVarType.MatrixOrder.MATRIXORDER_ROW_MAJOR: return 'row_major'; + default: + throw new Error('Unknown qualifier: ' + qualifier); + } + }; + + gluVarType.MemoryAccessQualifier = { + MEMORYACCESSQUALIFIER_COHERENT_BIT: 0x01, + MEMORYACCESSQUALIFIER_VOLATILE_BIT: 0x02, + MEMORYACCESSQUALIFIER_RESTRICT_BIT: 0x04, + MEMORYACCESSQUALIFIER_READONLY_BIT: 0x08, + MEMORYACCESSQUALIFIER_WRITEONLY_BIT: 0x10 + }; + gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_MASK = (gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_WRITEONLY_BIT << 1) - 1; + + /** + * @param {number} qualifier + * @return {string} + */ + gluVarType.getMemoryAccessQualifierName = function(qualifier) { + switch (qualifier) { + case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_COHERENT_BIT: return 'coherent'; + case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_VOLATILE_BIT: return 'volatile'; + case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_RESTRICT_BIT: return 'restrict'; + case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_READONLY_BIT: return 'readonly'; + case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_WRITEONLY_BIT: return 'writeonly'; + default: + throw new Error('Unknown qualifier: ' + qualifier); + } + }; + + /** + * @constructor + * @param {number=} location + * @param {number=} binding + * @param {number=} offset + * @param {gluVarType.FormatLayout=} format + * @param {gluVarType.MatrixOrder=} matrixOrder + */ + gluVarType.Layout = function(location, binding, offset, format, matrixOrder) { + this.location = location; + this.binding = binding; + this.offset = offset; + this.format = format; + this.matrixOrder = matrixOrder; + }; + + gluVarType.Layout.prototype.toString = function() { + var strings = []; + var str = ''; + if (typeof this.location !== 'undefined') + strings.push('location=' + this.location); + if (typeof this.binding !== 'undefined') + strings.push('binding=' + this.binding); + if (typeof this.offset !== 'undefined') + strings.push('offset=' + this.offset); + if (typeof this.format !== 'undefined') + strings.push(gluVarType.getFormatLayoutName(this.format)); + if (typeof this.matrixOrder !== 'undefined') + strings.push(gluVarType.getMatrixOrderName(this.matrixOrder)); + + if (strings.length > 0) { + str += 'layout(' + strings[0]; + + for (var i = 1; i < strings.length; i++) + str += ', ' + strings[i]; + str += ')'; + } + + return str; + }; + + /** + * @constructor + * @param {gluVarType.VarType} varType + * @param {string} name + * @param {gluVarType.Storage=} storage + * @param {gluVarType.Interpolation=} interpolation + * @param {gluVarType.Layout=} layout + * @param {number=} memoryAccessQualifierBits + */ + gluVarType.VariableDeclaration = function(varType, name, storage, interpolation, layout, memoryAccessQualifierBits) { + this.varType = varType; + this.name = name; + this.storage = storage; + this.interpolation = interpolation; + this.layout = layout; + this.memoryAccessQualifierBits = memoryAccessQualifierBits || 0; + }; + + gluVarType.VariableDeclaration.prototype.toString = function() { + var str = ''; + if (typeof this.layout !== 'undefined') + str += this.layout.toString() + ' '; + + for (var bitNdx = 0; (1 << bitNdx) & gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_MASK; ++bitNdx) + if (this.memoryAccessQualifierBits & (1 << bitNdx)) + str += gluVarType.getMemoryAccessQualifierName((1 << bitNdx)) + ' '; + + if (typeof this.interpolation !== 'undefined') + str += gluVarType.getInterpolationName(this.interpolation) + ' '; + + if (typeof this.storage !== 'undefined') + str += gluVarType.getStorageName(this.storage) + ' '; + + str += gluVarType.declareVariable(this.varType, this.name); + + return str; + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js new file mode 100644 index 0000000000..30e198a606 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js @@ -0,0 +1,693 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.gluVarTypeUtil'); +goog.require('framework.opengl.gluShaderUtil'); +goog.require('framework.opengl.gluVarType'); + +goog.scope(function() { + + var gluVarTypeUtil = framework.opengl.gluVarTypeUtil; + var gluVarType = framework.opengl.gluVarType; + var gluShaderUtil = framework.opengl.gluShaderUtil; + + gluVarTypeUtil.isNum = function(c) { return /^[0-9]$/.test(c); }; + gluVarTypeUtil.isAlpha = function(c) { return /^[a-zA-Z]$/.test(c); }; + gluVarTypeUtil.isIdentifierChar = function(c) { return /^[a-zA-Z0-9_]$/.test(c); }; + gluVarTypeUtil.array_op_equivalent = function(arr1, arr2) { + if (arr1.length != arr2.length) return false; + for (var i = 0; i < arr1.length; ++i) { + if (arr1[i].isnt(arr2[1])) return false; + } + return true; + }; + + /** + * gluVarTypeUtil.VarTokenizer class. + * @param {string} str + * @constructor + */ + gluVarTypeUtil.VarTokenizer = function(str) { + + /** @private */ + this.m_str = str; + /** @private */ + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.length; + /** @private */ + this.m_tokenStart = 0; + /** @private */ + this.m_tokenLen = 0; + + this.advance(); + + }; + gluVarTypeUtil.VarTokenizer.s_Token = { + IDENTIFIER: 0, + LEFT_BRACKET: 1, + RIGHT_BRACKET: 2, + PERIOD: 3, + NUMBER: 4, + END: 5 + }; + gluVarTypeUtil.VarTokenizer.s_Token.length = Object.keys(gluVarTypeUtil.VarTokenizer.s_Token).length; + + gluVarTypeUtil.VarTokenizer.prototype.getToken = function() { + return this.m_token; + }; + gluVarTypeUtil.VarTokenizer.prototype.getIdentifier = function() { + return this.m_str.substr(this.m_tokenStart, this.m_tokenLen); + }; + gluVarTypeUtil.VarTokenizer.prototype.getNumber = function() { + return parseInt(this.getIdentifier(), 10); + }; + gluVarTypeUtil.VarTokenizer.prototype.getCurrentTokenStartLocation = function() { + return this.m_tokenStart; + }; + gluVarTypeUtil.VarTokenizer.prototype.getCurrentTokenEndLocation = function() { + return this.m_tokenStart + this.m_tokenLen; + }; + + gluVarTypeUtil.VarTokenizer.prototype.advance = function() { + + if (this.m_token == gluVarTypeUtil.VarTokenizer.s_Token.END) { + throw new Error('No more tokens.'); + } + + this.m_tokenStart += this.m_tokenLen; + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.length; + this.m_tokenLen = 1; + + if (this.m_tokenStart >= this.m_str.length) { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.END; + + } else if (this.m_str[this.m_tokenStart] == '[') { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.LEFT_BRACKET; + + } else if (this.m_str[this.m_tokenStart] == ']') { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.RIGHT_BRACKET; + + } else if (this.m_str[this.m_tokenStart] == '.') { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.PERIOD; + + } else if (gluVarTypeUtil.isNum(this.m_str[this.m_tokenStart])) { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.NUMBER; + while (gluVarTypeUtil.isNum(this.m_str[this.m_tokenStart + this.m_tokenLen])) { + this.m_tokenLen += 1; + } + + } else if (gluVarTypeUtil.isIdentifierChar(this.m_str[this.m_tokenStart])) { + this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER; + while (gluVarTypeUtil.isIdentifierChar(this.m_str[this.m_tokenStart + this.m_tokenLen])) { + this.m_tokenLen += 1; + } + + } else { + throw new Error('Unexpected character'); + } + + }; + + /** + * VarType subtype path utilities class. + * @param {gluVarTypeUtil.VarTypeComponent.s_Type} type + * @param {number} index + * @constructor + */ + gluVarTypeUtil.VarTypeComponent = function(type, index) { + /** @type {gluVarTypeUtil.VarTypeComponent.s_Type} */ this.type = type; + this.index = index || 0; + }; + + gluVarTypeUtil.VarTypeComponent.prototype.is = function(other) { + return this.type == other.type && this.index == other.index; + }; + gluVarTypeUtil.VarTypeComponent.prototype.isnt = function(other) { + return this.type != other.type || this.index != other.index; + }; + + /** + * @enum + */ + gluVarTypeUtil.VarTypeComponent.s_Type = { + STRUCT_MEMBER: 0, + ARRAY_ELEMENT: 1, + MATRIX_COLUMN: 2, + VECTOR_COMPONENT: 3 + }; + + /** + * Type path formatter. + * @param {gluVarType.VarType} type_ + * @param {Array<gluVarTypeUtil.VarTypeComponent>} path_ + * @constructor + */ + gluVarTypeUtil.TypeAccessFormat = function(type_, path_) { + this.type = type_; + this.path = path_; + }; + + gluVarTypeUtil.TypeAccessFormat.prototype.toString = function() { + var curType = this.type; + var str = ''; + + for (var i = 0; i < this.path.length; i++) { + var iter = this.path[i]; + switch (iter.type) { + case gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT: + curType = curType.getElementType(); // Update current type. + // Fall-through. + + case gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN: + case gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT: + str += '[' + iter.index + ']'; + break; + + case gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER: { + var member = curType.getStruct().getMember(i); + str += '.' + member.getName(); + curType = member.getType(); + break; + } + + default: + throw new Error('Unrecognized type:' + iter.type); + } + } + + return str; + }; + + /** gluVarTypeUtil.SubTypeAccess + * @param {gluVarType.VarType} type + * @constructor + */ + gluVarTypeUtil.SubTypeAccess = function(type) { + + this.m_type = null; // VarType + this.m_path = []; // TypeComponentVector + + }; + + /** @private */ + gluVarTypeUtil.SubTypeAccess.prototype.helper = function(type, ndx) { + this.m_path.push(new gluVarTypeUtil.VarTypeComponent(type, ndx)); + if (!this.isValid()) { + throw new Error; + } + return this; + }; + + gluVarTypeUtil.SubTypeAccess.prototype.member = function(ndx) { + return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, ndx); + }; + gluVarTypeUtil.SubTypeAccess.prototype.element = function(ndx) { + return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, ndx); + }; + gluVarTypeUtil.SubTypeAccess.prototype.column = function(ndx) { + return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, ndx); + }; + gluVarTypeUtil.SubTypeAccess.prototype.component = function(ndx) { + return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, ndx); + }; + gluVarTypeUtil.SubTypeAccess.prototype.parent = function() { + if (!this.m_path.length) { + throw new Error; + } + this.m_path.pop(); + return this; + }; + + gluVarTypeUtil.SubTypeAccess.prototype.isValid = function() { + return gluVarTypeUtil.isValidTypePath(this.m_type, this.m_path); + }; + gluVarTypeUtil.SubTypeAccess.prototype.getType = function() { + return gluVarTypeUtil.getVarType(this.m_type, this.m_path); + }; + gluVarTypeUtil.SubTypeAccess.prototype.getPath = function() { + return this.m_path; + }; + gluVarTypeUtil.SubTypeAccess.prototype.empty = function() { + return !this.m_path.length; + }; + gluVarTypeUtil.SubTypeAccess.prototype.is = function(other) { + return ( + gluVarTypeUtil.array_op_equivalent(this.m_path, other.m_path) && + this.m_type.is(other.m_type) + ); + }; + gluVarTypeUtil.SubTypeAccess.prototype.isnt = function(other) { + return ( + !gluVarTypeUtil.array_op_equivalent(this.m_path, other.m_path) || + this.m_type.isnt(other.m_type) + ); + }; + + /** + * Subtype iterator parent class. + * basic usage for all child classes: + * for (var i = new gluVarTypeUtil.BasicTypeIterator(type) ; !i.end() ; i.next()) { + * var j = i.getType(); + * } + * @constructor + */ + gluVarTypeUtil.SubTypeIterator = function(type) { + + /** @private */ + this.m_type = null; // const VarType* + /** @private */ + this.m_path = []; // TypeComponentVector + + if (type) { + this.m_type = type; + this.findNext(); + } + + }; + + gluVarTypeUtil.SubTypeIterator.prototype.isExpanded = function(type) { + throw new Error('This function must be overriden in child class'); + }; + + /** removeTraversed + * @private + */ + gluVarTypeUtil.SubTypeIterator.prototype.removeTraversed = function() { + + while (this.m_path.length) { + var curComp = this.m_path[this.m_path.length - 1]; // gluVarTypeUtil.VarTypeComponent& + var parentType = gluVarTypeUtil.getVarType(this.m_type, this.m_path, 0, this.m_path.length - 1); // VarType + + if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) { + if (!gluShaderUtil.isDataTypeMatrix(parentType.getBasicType())) { + throw new Error('Isn\'t a matrix.'); + } + if (curComp.index + 1 < gluShaderUtil.getDataTypeMatrixNumColumns(parentType.getBasicType())) { + break; + } + + } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) { + if (!gluShaderUtil.isDataTypeVector(parentType.getBasicType())) { + throw new Error('Isn\'t a vector.'); + } + if (curComp.index + 1 < gluShaderUtil.getDataTypeScalarSize(parentType.getBasicType())) { + break; + } + + } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) { + if (!parentType.isArrayType()) { + throw new Error('Isn\'t an array.'); + } + if (curComp.index + 1 < parentType.getArraySize()) { + break; + } + + } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) { + if (!parentType.isStructType()) { + throw new Error('Isn\'t a struct.'); + } + if (curComp.index + 1 < parentType.getStruct().getNumMembers()) { + break; + } + + } + + this.m_path.pop(); + } + }; + gluVarTypeUtil.SubTypeIterator.prototype.findNext = function() { + + if (this.m_path.length > 0) { + // Increment child counter in current level. + var curComp = this.m_path[this.m_path.length - 1]; // gluVarTypeUtil.VarTypeComponent& + curComp.index += 1; + } + + for (;;) { + + var curType = gluVarTypeUtil.getVarType(this.m_type, this.m_path); // VarType + + if (this.isExpanded(curType)) + break; + + // Recurse into child type. + if (curType.isBasicType()) { + var basicType = curType.getBasicType(); // DataType + + if (gluShaderUtil.isDataTypeMatrix(basicType)) { + this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, 0)); + + } else if (gluShaderUtil.isDataTypeVector(basicType)) { + this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, 0)); + + } else { + throw new Error('Cant expand scalars - isExpanded() is buggy.'); + } + + } else if (curType.isArrayType()) { + this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, 0)); + + } else if (curType.isStructType()) { + this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, 0)); + + } else { + throw new Error(); + } + } + + }; + gluVarTypeUtil.SubTypeIterator.prototype.end = function() { + return (this.m_type == null); + }; + /** next + * equivelant to operator++(), doesnt return. + */ + gluVarTypeUtil.SubTypeIterator.prototype.next = function() { + if (this.m_path.length > 0) { + // Remove traversed nodes. + this.removeTraversed(); + + if (this.m_path.length > 0) + this.findNext(); + else + this.m_type = null; // Unset type to signal end. + } else { + if (!this.isExpanded(gluVarTypeUtil.getVarType(this.m_type, this.m_path))) { + throw new Error('First type was already expanded.'); + } + this.m_type = null; + } + }; + gluVarTypeUtil.SubTypeIterator.prototype.getType = function() { + return gluVarTypeUtil.getVarType(this.m_type, this.m_path); + }; + gluVarTypeUtil.SubTypeIterator.prototype.getPath = function() { + return this.m_path; + }; + + gluVarTypeUtil.SubTypeIterator.prototype.toString = function() { + var x = new gluVarTypeUtil.TypeAccessFormat(this.m_type, this.m_path); + return x.toString(); + }; + + /** gluVarTypeUtil.BasicTypeIterator + * @param {gluVarType.VarType} type + * @constructor + * @extends {gluVarTypeUtil.SubTypeIterator} + */ + gluVarTypeUtil.BasicTypeIterator = function(type) { + gluVarTypeUtil.SubTypeIterator.call(this, type); + }; + gluVarTypeUtil.BasicTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype); + gluVarTypeUtil.BasicTypeIterator.prototype.constructor = gluVarTypeUtil.BasicTypeIterator; + + gluVarTypeUtil.BasicTypeIterator.prototype.isExpanded = function(type) { + return type.isBasicType(); + }; + + /** gluVarTypeUtil.VectorTypeIterator + * @param {gluVarType.VarType} type + * @constructor + * @extends {gluVarTypeUtil.SubTypeIterator} + */ + gluVarTypeUtil.VectorTypeIterator = function(type) { + gluVarTypeUtil.SubTypeIterator.call(this, type); + }; + gluVarTypeUtil.VectorTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype); + gluVarTypeUtil.VectorTypeIterator.prototype.constructor = gluVarTypeUtil.VectorTypeIterator; + + gluVarTypeUtil.VectorTypeIterator.prototype.isExpanded = function(type) { + return type.isBasicType() && gluShaderUtil.isDataTypeScalarOrVector(type.getBasicType()); + }; + + /** gluVarTypeUtil.ScalarTypeIterator + * @param {gluVarType.VarType} type + * @constructor + * @extends {gluVarTypeUtil.SubTypeIterator} + */ + gluVarTypeUtil.ScalarTypeIterator = function(type) { + gluVarTypeUtil.SubTypeIterator.call(this, type); + }; + gluVarTypeUtil.ScalarTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype); + gluVarTypeUtil.ScalarTypeIterator.prototype.constructor = gluVarTypeUtil.ScalarTypeIterator; + + gluVarTypeUtil.ScalarTypeIterator.prototype.isExpanded = function(type) { + return type.isBasicType() && gluShaderUtil.isDataTypeScalar(type.getBasicType()); + }; + + gluVarTypeUtil.inBounds = (function(x, a, b) { return a <= x && x < b; }); + + /** gluVarTypeUtil.isValidTypePath + * @param {gluVarType.VarType} type + * @param {Array<gluVarTypeUtil.VarTypeComponent>} array + * @param {number=} begin + * @param {number=} end + * @return {boolean} + */ + gluVarTypeUtil.isValidTypePath = function(type, array, begin, end) { + + if (typeof(begin) == 'undefined') {begin = 0;} + if (typeof(end) == 'undefined') {begin = array.length;} + + var curType = type; // const VarType* + var pathIter = begin; // Iterator + + // Process struct member and array element parts of path. + while (pathIter != end) { + var element = array[pathIter]; + + if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) { + + if (!curType.isStructType() || !gluVarTypeUtil.inBounds(element.index, 0, curType.getStruct().getNumMembers())) { + return false; + } + + curType = curType.getStruct().getMember(element.index).getType(); + + } else if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) { + if ( + !curType.isArrayType() || + ( + curType.getArraySize() != gluVarType.VarType.UNSIZED_ARRAY && + !gluVarTypeUtil.inBounds(element.index, 0, curType.getArraySize()) + ) + ) { + return false; + } + + curType = curType.getElementType(); + } else { + break; + } + + ++pathIter; + } + + if (pathIter != end) { + if (!( + array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN || + array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT + )) { + throw new Error('Not a matrix or a vector'); + } + + // Current type should be basic type. + if (!curType.isBasicType()) { + return false; + } + + var basicType = curType.getBasicType(); // DataType + + if (array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) { + if (!gluShaderUtil.isDataTypeMatrix(basicType)) { + return false; + } + + basicType = gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType)); + ++pathIter; + } + + if (pathIter != end && array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) { + if (!gluShaderUtil.isDataTypeVector(basicType)) + return false; + + basicType = gluShaderUtil.getDataTypeScalarType(basicType); + ++pathIter; + } + } + + return pathIter == end; + }; + + /** gluVarTypeUtil.getVarType + * @param {gluVarType.VarType} type + * @param {Array<gluVarTypeUtil.VarTypeComponent>} array + * @param {number=} start + * @param {number=} end + * @return {gluVarType.VarType} + */ + gluVarTypeUtil.getVarType = function(type, array, start, end) { + + if (typeof(start) == 'undefined') start = 0; + if (typeof(end) == 'undefined') end = array.length; + + if (!gluVarTypeUtil.isValidTypePath(type, array, start, end)) { + throw new Error('Type is invalid'); + } + + var curType = type; // const VarType* + var element = null; // Iterator + var pathIter = 0; + + // Process struct member and array element parts of path. + for (pathIter = start; pathIter != end; ++pathIter) { + element = array[pathIter]; + + if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) { + curType = curType.getStruct().getMember(element.index).getType(); + + } else if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) { + curType = curType.getElementType(); + + } else { + break; + + } + } + + if (pathIter != end) { + + var basicType = curType.getBasicType(); // DataType + var precision = curType.getPrecision(); // Precision + + if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) { + basicType = gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType)); + element = array[++pathIter]; + } + + if (pathIter != end && element.type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) { + basicType = gluShaderUtil.getDataTypeScalarTypeAsDataType(basicType); + element = array[++pathIter]; + } + + if (pathIter != end) { + throw new Error(); + } + return gluVarType.newTypeBasic(basicType, precision); + } else { + /* TODO: Original code created an object copy. We are returning reference to the same object */ + return curType; + } + }; + + gluVarTypeUtil.parseVariableName = function(nameWithPath) { + var tokenizer = new gluVarTypeUtil.VarTokenizer(nameWithPath); + if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) { + throw new Error('Not an identifier.'); + } + return tokenizer.getIdentifier(); + }; + + // returns an array (TypeComponentVector& path) + // params: const char*, const VarType& + gluVarTypeUtil.parseTypePath = function(nameWithPath, type) { + + var tokenizer = new gluVarTypeUtil.VarTokenizer(nameWithPath); + + if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) { + tokenizer.advance(); + } + + var path = []; + + while (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.END) { + + var curType = gluVarTypeUtil.getVarType(type, path); + + if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.PERIOD) { + + tokenizer.advance(); + if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) { + throw new Error(); + } + if (!curType.isStructType()) { + throw new Error('Invalid field selector'); + } + + // Find member. + var memberName = tokenizer.getIdentifier(); + var ndx = 0; + for (; ndx < curType.getStruct().getSize(); ++ndx) { + + if (memberName == curType.getStruct().getMember(ndx).getName()) { + break; + } + + } + if (ndx >= curType.getStruct().getSize()) { + throw new Error('Member not found in type: ' + memberName); + } + + path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, ndx)); + tokenizer.advance(); + + } else if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.LEFT_BRACKET) { + + tokenizer.advance(); + if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.NUMBER) { + throw new Error(); + } + + var ndx = tokenizer.getNumber(); + + if (curType.isArrayType()) { + if (!gluVarTypeUtil.inBounds(ndx, 0, curType.getArraySize())) throw new Error; + path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, ndx)); + + } else if (curType.isBasicType() && gluShaderUtil.isDataTypeMatrix(curType.getBasicType())) { + if (!gluVarTypeUtil.inBounds(ndx, 0, gluShaderUtil.getDataTypeMatrixNumColumns(curType.getBasicType()))) throw new Error; + path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, ndx)); + + } else if (curType.isBasicType() && gluShaderUtil.isDataTypeVector(curType.getBasicType())) { + if (!gluVarTypeUtil.inBounds(ndx, 0, gluShaderUtil.getDataTypeScalarSize(curType.getBasicType()))) throw new Error; + path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, ndx)); + + } else { + //TCU_FAIL + throw new Error('Invalid subscript'); + } + + tokenizer.advance(); + if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.RIGHT_BRACKET) { + throw new Error('Expected token RIGHT_BRACKET'); + } + tokenizer.advance(); + + } else { + // TCU_FAIL + throw new Error('Unexpected token'); + } + } + + return path; + + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt new file mode 100644 index 0000000000..7db3d9d5c7 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt @@ -0,0 +1 @@ +referencecontext.html
\ No newline at end of file diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html new file mode 100644 index 0000000000..f3ba0ed262 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html @@ -0,0 +1,32 @@ +<html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>Reference context test</title> +<link rel="stylesheet" href="../../../../resources/js-test-style.css"/> +<script src="../../../../js/js-test-pre.js"></script> +<script src="../../../../js/webgl-test-utils.js"></script> + +<script src="../../../../closure-library/closure/goog/base.js"></script> +<script src="../../../deqp-deps.js"></script> +<script>goog.require('framework.opengl.simplereference.sglrReferenceContextTest');</script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas" width="200" height="100"> </canvas> +<script> +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext('canvas', {preserveDrawingBuffer: true}, 2); + + try { + framework.opengl.simplereference.sglrReferenceContextTest.run(gl); + } + catch(err) + { + bufferedLogToConsole(err); + } + +</script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js new file mode 100644 index 0000000000..13f75e8f5e --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js @@ -0,0 +1,231 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.simplereference.sglrGLContext'); +goog.require('framework.common.tcuPixelFormat'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.delibs.debase.deUtil'); +goog.require('framework.opengl.gluShaderProgram'); +goog.require('framework.opengl.gluShaderUtil'); +goog.require('framework.opengl.gluTextureUtil'); +goog.require('framework.opengl.simplereference.sglrShaderProgram'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess'); +goog.require('framework.referencerenderer.rrRenderState'); +goog.require('framework.referencerenderer.rrRenderer'); +goog.require('framework.referencerenderer.rrVertexAttrib'); + +goog.scope(function() { + + var sglrGLContext = framework.opengl.simplereference.sglrGLContext; + var tcuTexture = framework.common.tcuTexture; + var deUtil = framework.delibs.debase.deUtil; + var deMath = framework.delibs.debase.deMath; + var tcuTextureUtil = framework.common.tcuTextureUtil; + var tcuPixelFormat = framework.common.tcuPixelFormat; + var gluShaderProgram = framework.opengl.gluShaderProgram; + var gluShaderUtil = framework.opengl.gluShaderUtil; + var gluTextureUtil = framework.opengl.gluTextureUtil; + var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram; + var rrDefs = framework.referencerenderer.rrDefs; + var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess; + var rrRenderer = framework.referencerenderer.rrRenderer; + var rrRenderState = framework.referencerenderer.rrRenderState; + var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + /** + * sglrGLContext.GLContext wraps the standard WebGL context to be able to be used interchangeably with the ReferenceContext + * @constructor + * @extends {WebGL2RenderingContext} + * @param {?WebGL2RenderingContext} context + * @param {Array<number>=} viewport + */ + sglrGLContext.GLContext = function(context, viewport) { + DE_ASSERT(context); + + var functionwrapper = function(context, fname) { + return function() { + return context[fname].apply(context, arguments); + }; + }; + + var wrap = {}; + for (var i in context) { + try { + if (typeof context[i] == 'function') { + wrap[i] = functionwrapper(context, i); + } else { + wrap[i] = context[i]; + } + } catch (e) { + throw new Error('GLContext: Error accessing ' + i); + } + } + if (viewport) + context.viewport(viewport[0], viewport[1], viewport[2], viewport[3]); + + /** + * createProgram + * @override + * @param {sglrShaderProgram.ShaderProgram=} shader + * @return {!WebGLProgram} + */ + this.createProgram = function(shader) { + var program = new gluShaderProgram.ShaderProgram( + context, + gluShaderProgram.makeVtxFragSources( + shader.m_vertSrc, + shader.m_fragSrc + ) + ); + + if (!program.isOk()) { + bufferedLogToConsole(program.toString()); + testFailedOptions('Compile failed', true); + } + return program.getProgram(); + }; + wrap['createProgram'] = this.createProgram; + + /** + * Draws quads from vertex arrays + * @param {number} primitive Primitive type + * @param {number} first First vertex to begin drawing with + * @param {number} count Number of vertices + */ + var drawQuads = function(primitive, first, count) { + context.drawArrays(primitive, first, count); + }; + wrap['drawQuads'] = drawQuads; + + /** + * @return {number} + */ + var getWidth = function() { + if(viewport) + return viewport[2]; + else + return context.drawingBufferWidth; + }; + wrap['getWidth'] = getWidth; + + /** + * @return {number} + */ + var getHeight = function() { + if(viewport) + return viewport[3]; + else + return context.drawingBufferHeight; + }; + wrap['getHeight'] = getHeight; + + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + * @param {number} format + * @param {number} dataType + * @param {ArrayBuffer|ArrayBufferView} data + */ + var readPixels = function(x, y, width, height, format, dataType, data) { + /** @type {?ArrayBufferView} */ var dataArr; + if (!ArrayBuffer.isView(data)) { + var type = gluTextureUtil.mapGLChannelType(dataType, true); + var dataArrType = tcuTexture.getTypedArray(type); + dataArr = new dataArrType(data); + } else { + dataArr = /** @type {?ArrayBufferView} */ (data); + } + + context.readPixels(x, y, width, height, format, dataType, dataArr); + }; + wrap['readPixels'] = readPixels; + + /** + * @param {number} target + * @param {number} level + * @param {number} internalFormat + * @param {number} width + * @param {number} height + */ + var texImage2DDelegate = function(target, level, internalFormat, width, height) { + var format; + var dataType; + + switch(internalFormat) + { + case gl.ALPHA: + case gl.LUMINANCE: + case gl.LUMINANCE_ALPHA: + case gl.RGB: + case gl.RGBA: + format = internalFormat; + dataType = gl.UNSIGNED_BYTE; + break; + default: + { + var transferFmt = gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(internalFormat)); + format = transferFmt.format; + dataType = transferFmt.dataType; + break; + } + } + context.texImage2D(target, level, internalFormat, width, height, 0, format, dataType, null); + }; + wrap['texImage2DDelegate'] = texImage2DDelegate; + + return wrap; + }; + + /** + * createProgram - This had to be added here as dummy to remove a warning when the only context used is GLContext (no reference context) + * @override + * @param {sglrShaderProgram.ShaderProgram=} shader + * @return {!WebGLProgram} + */ + sglrGLContext.GLContext.prototype.createProgram = function(shader) {return this.createProgram();}; + + /** + * @param ctx GL-like context + * @param {string} name + * @return {boolean} + */ + sglrGLContext.isExtensionSupported = function(ctx, name) { + var extns = ctx.getSupportedExtensions(); + var found = false; + if (extns) { + var index = extns.indexOf(name); + if (index != -1) + found = true; + } + return found; + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js new file mode 100644 index 0000000000..523dbe607f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js @@ -0,0 +1,4986 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.simplereference.sglrReferenceContext'); +goog.require('framework.common.tcuMatrix'); +goog.require('framework.common.tcuMatrixUtil'); +goog.require('framework.common.tcuPixelFormat'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.opengl.gluShaderUtil'); +goog.require('framework.opengl.gluTextureUtil'); +goog.require('framework.opengl.simplereference.sglrReferenceUtils'); +goog.require('framework.opengl.simplereference.sglrShaderProgram'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess'); +goog.require('framework.referencerenderer.rrRenderState'); +goog.require('framework.referencerenderer.rrRenderer'); +goog.require('framework.referencerenderer.rrVertexAttrib'); + +goog.scope(function() { + + var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext; + var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess; + var tcuTexture = framework.common.tcuTexture; + var deMath = framework.delibs.debase.deMath; + var gluTextureUtil = framework.opengl.gluTextureUtil; + var tcuTextureUtil = framework.common.tcuTextureUtil; + var tcuPixelFormat = framework.common.tcuPixelFormat; + var gluShaderUtil = framework.opengl.gluShaderUtil; + var rrRenderer = framework.referencerenderer.rrRenderer; + var rrDefs = framework.referencerenderer.rrDefs; + var rrGenericVector = framework.referencerenderer.rrGenericVector; + var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; + var rrRenderState = framework.referencerenderer.rrRenderState; + var sglrReferenceUtils = framework.opengl.simplereference.sglrReferenceUtils; + var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram; + var tcuMatrix = framework.common.tcuMatrix; + var tcuMatrixUtil = framework.common.tcuMatrixUtil; + + sglrReferenceContext.rrMPBA = rrMultisamplePixelBufferAccess; + + //TODO: Implement automatic error checking in sglrReferenceContext, optional on creation. + + /** @typedef {WebGLRenderbuffer|WebGLTexture|sglrReferenceContext.Renderbuffer|sglrReferenceContext.TextureContainer} */ sglrReferenceContext.AnyRenderbuffer; + + /** @typedef {WebGLFramebuffer|sglrReferenceContext.Framebuffer} */ sglrReferenceContext.AnyFramebuffer; + + /** + * @param {number} error + * @param {number} message + * @throws {Error} + */ + sglrReferenceContext.GLU_EXPECT_NO_ERROR = function(error, message) { + if (error !== gl.NONE) { + bufferedLogToConsole('Assertion failed message:' + message); + } + }; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + // /* TODO: remove */ + // /** @type {WebGL2RenderingContext} */ var gl; + + sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2 = 14; + sglrReferenceContext.MAX_TEXTURE_SIZE = 1 << sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2; + + /** + * @param {number} width + * @param {number} height + * @return {number} + */ + sglrReferenceContext.getNumMipLevels2D = function(width, height) { + return Math.floor(Math.log2(Math.max(width, height)) + 1); + }; + + /** + * @param {number} width + * @param {number} height + * @param {number} depth + * @return {number} + */ + sglrReferenceContext.getNumMipLevels3D = function(width, height, depth) { + return Math.floor(Math.log2(Math.max(width, height, depth)) + 1); + }; + + /** + * @param {number} baseLevelSize + * @param {number} levelNdx + * @return {number} + */ + sglrReferenceContext.getMipLevelSize = function(baseLevelSize, levelNdx) { + return Math.max(baseLevelSize >> levelNdx, 1); + }; + + sglrReferenceContext.mapGLCubeFace = function(face) { + switch (face) { + case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; + case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X; + case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y; + case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y; + case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z; + case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z; + default: throw new Error('Invalid cube face: ' + face); + } + }; + + /** + * @param {tcuTexture.FilterMode} mode + * @return {boolean} + */ + sglrReferenceContext.isMipmapFilter = function(/*const tcu::Sampler::FilterMode*/ mode) { + return mode != tcuTexture.FilterMode.NEAREST && mode != tcuTexture.FilterMode.LINEAR; + }; + + sglrReferenceContext.getNumMipLevels1D = function(size) { + return Math.floor(Math.log2(size)) + 1; + }; + + /** + * @param {?sglrReferenceContext.TextureType} type + * @return {sglrReferenceContext.TexTarget} + */ + sglrReferenceContext.texLayeredTypeToTarget = function(type) { + switch (type) { + case sglrReferenceContext.TextureType.TYPE_2D_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY; + case sglrReferenceContext.TextureType.TYPE_3D: return sglrReferenceContext.TexTarget.TEXTARGET_3D; + case sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY; + default: throw new Error('Invalid texture type: ' + type); + } + }; + + /** + * @param {rrDefs.IndexType} indexType + * @return {number} + * @throws {Error} + */ + sglrReferenceContext.getFixedRestartIndex = function(indexType) { + switch (indexType) { + case rrDefs.IndexType.INDEXTYPE_UINT8: return 0xFF; + case rrDefs.IndexType.INDEXTYPE_UINT16: return 0xFFFF; + case rrDefs.IndexType.INDEXTYPE_UINT32: return 0xFFFFFFFF; + default: + throw new Error('Unrecognized index type: ' + indexType); + } + }; + + /** + * @constructor + * @param {sglrShaderProgram.ShaderProgram} program + */ + sglrReferenceContext.ShaderProgramObjectContainer = function(program) { + this.m_program = program; + /** @type {boolean} */ this.m_deleteFlag = false; + }; + + /** + * @param {WebGL2RenderingContext} gl + * @constructor + */ + sglrReferenceContext.ReferenceContextLimits = function(gl) { + /** @type {number} */ this.maxTextureImageUnits = 16; + /** @type {number} */ this.maxTexture2DSize = 2048; + /** @type {number} */ this.maxTextureCubeSize = 2048; + /** @type {number} */ this.maxTexture2DArrayLayers = 256; + /** @type {number} */ this.maxTexture3DSize = 256; + /** @type {number} */ this.maxRenderbufferSize = 2048; + /** @type {number} */ this.maxVertexAttribs = 16; + + if (gl) { + this.maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)); + this.maxTexture2DSize = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_SIZE)); + this.maxTextureCubeSize = /** @type {number} */ (gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)); + this.maxRenderbufferSize = /** @type {number} */ (gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)); + this.maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS)); + this.maxTexture2DArrayLayers = /** @type {number} */ (gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS)); + this.maxTexture3DSize = /** @type {number} */ (gl.getParameter(gl.MAX_3D_TEXTURE_SIZE)); + + // Limit texture sizes to supported values + this.maxTexture2DSize = Math.min(this.maxTexture2DSize, sglrReferenceContext.MAX_TEXTURE_SIZE); + this.maxTextureCubeSize = Math.min(this.maxTextureCubeSize, sglrReferenceContext.MAX_TEXTURE_SIZE); + this.maxTexture3DSize = Math.min(this.maxTexture3DSize, sglrReferenceContext.MAX_TEXTURE_SIZE); + + sglrReferenceContext.GLU_EXPECT_NO_ERROR(gl.getError(), gl.NO_ERROR); + } + + /* TODO: Port + // \todo [pyry] Figure out following things: + // + supported fbo configurations + // ... + + // \todo [2013-08-01 pyry] Do we want to make these conditional based on renderCtx? + addExtension("gl.EXT_color_buffer_half_float"); + addExtension("gl.WEBGL_color_buffer_float"); + */ + }; + + /** + * @enum + */ + sglrReferenceContext.TextureType = { + TYPE_2D: 0, + TYPE_CUBE_MAP: 1, + TYPE_2D_ARRAY: 2, + TYPE_3D: 3, + TYPE_CUBE_MAP_ARRAY: 4 + }; + + /** + * @constructor + * @implements {rrDefs.Sampler} + * @param {sglrReferenceContext.TextureType} type + */ + sglrReferenceContext.Texture = function(type) { + // NamedObject.call(this, name); + /** @type {sglrReferenceContext.TextureType} */ this.m_type = type; + /** @type {boolean} */ this.m_immutable = false; + /** @type {number} */ this.m_baseLevel = 0; + /** @type {number} */ this.m_maxLevel = 1000; + /** @type {tcuTexture.Sampler} */ this.m_sampler = new tcuTexture.Sampler( + tcuTexture.WrapMode.REPEAT_GL, + tcuTexture.WrapMode.REPEAT_GL, + tcuTexture.WrapMode.REPEAT_GL, + tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR, + tcuTexture.FilterMode.LINEAR, + 0, + true, + tcuTexture.CompareMode.COMPAREMODE_NONE, + 0, + [0, 0, 0, 0], + true); + }; + + /** + * @param {Array<number>} pos + * @param {number=} lod + * @throws {Error} + */ + sglrReferenceContext.Texture.prototype.sample = function(pos, lod) {throw new Error('Intentionally empty. Call method from child class instead'); }; + + /** + * @param {Array<Array<number>>} packetTexcoords + * @param {number} lodBias + * @throws {Error} + */ + sglrReferenceContext.Texture.prototype.sample4 = function(packetTexcoords, lodBias) {throw new Error('Intentionally empty. Call method from child class instead'); }; + + // sglrReferenceContext.Texture.prototype = Object.create(NamedObject.prototype); + // sglrReferenceContext.Texture.prototype.constructor = sglrReferenceContext.Texture; + + /** + * @return {number} + */ + sglrReferenceContext.Texture.prototype.getType = function() { return this.m_type; }; + + /** + * @return {number} + */ + sglrReferenceContext.Texture.prototype.getBaseLevel = function() { return this.m_baseLevel; }; + + /** + * @return {number} + */ + sglrReferenceContext.Texture.prototype.getMaxLevel = function() { return this.m_maxLevel; }; + + /** + * @return {boolean} + */ + sglrReferenceContext.Texture.prototype.isImmutable = function() { return this.m_immutable; }; + + /** + * @param {number} baseLevel + */ + sglrReferenceContext.Texture.prototype.setBaseLevel = function(baseLevel) { this.m_baseLevel = baseLevel; }; + + /** + * @param {number} maxLevel + */ + sglrReferenceContext.Texture.prototype.setMaxLevel = function(maxLevel) { this.m_maxLevel = maxLevel; }; + + /** + */ + sglrReferenceContext.Texture.prototype.setImmutable = function() { this.m_immutable = true; }; + + /** + * @return {tcuTexture.Sampler} + */ + sglrReferenceContext.Texture.prototype.getSampler = function() { return this.m_sampler; }; + + /** + * @constructor + */ + sglrReferenceContext.TextureLevelArray = function() { + /** @type {Array<ArrayBuffer>} */ this.m_data = []; + /** @type {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = []; + }; + + /** + * @param {number} level + * @return {boolean} + */ + sglrReferenceContext.TextureLevelArray.prototype.hasLevel = function(level) { return this.m_data[level] != null; }; + + /** + * @param {number} level + * @return {tcuTexture.PixelBufferAccess} + * @throws {Error} + */ + sglrReferenceContext.TextureLevelArray.prototype.getLevel = function(level) { + if (!this.hasLevel(level)) + throw new Error('Level: ' + level + ' is not defined.'); + + return this.m_access[level]; + }; + + /** + * @return {Array<tcuTexture.PixelBufferAccess>} + */ + sglrReferenceContext.TextureLevelArray.prototype.getLevels = function() { return this.m_access; }; + + /** + * @param {number} level + * @param {tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + * @param {number} depth + */ + sglrReferenceContext.TextureLevelArray.prototype.allocLevel = function(level, format, width, height, depth) { + /** @type {number} */ var dataSize = format.getPixelSize() * width * height * depth; + if (this.hasLevel(level)) + this.clearLevel(level); + + this.m_data[level] = new ArrayBuffer(dataSize); + this.m_access[level] = new tcuTexture.PixelBufferAccess({ + format: format, + width: width, + height: height, + depth: depth, + data: this.m_data[level]}); + }; + + /** + * @param {number} level + */ + sglrReferenceContext.TextureLevelArray.prototype.clearLevel = function(level) { + delete this.m_data[level]; + delete this.m_access[level]; + }; + + /** + */ + sglrReferenceContext.TextureLevelArray.prototype.clear = function() { + for (var key in this.m_data) + delete this.m_data[key]; + + for (var key in this.m_access) + delete this.m_access[key]; + }; + + /** + * @constructor + * @extends {sglrReferenceContext.Texture} + */ + sglrReferenceContext.Texture2D = function() { + sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D); + /** @type {tcuTexture.Texture2DView} */ this.m_view = new tcuTexture.Texture2DView(0, null); + /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray(); + }; + + /** + */ + sglrReferenceContext.Texture2D.prototype = Object.create(sglrReferenceContext.Texture.prototype); + sglrReferenceContext.Texture2D.prototype.constructor = sglrReferenceContext.Texture2D; + + sglrReferenceContext.Texture2D.prototype.clearLevels = function() { this.m_levels.clear(); }; + + /** + * @param {number} level + * @return {boolean} + */ + sglrReferenceContext.Texture2D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); }; + + /** + * @param {number} level + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.Texture2D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); }; + + /** + * @param {number} level + * @param {?tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.Texture2D.prototype.allocLevel = function(level, format, width, height) { this.m_levels.allocLevel(level, format, width, height, 1); }; + + /** + * @return {boolean} + */ + sglrReferenceContext.Texture2D.prototype.isComplete = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel); + /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + + if (mipmap) { + /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat(); + /** @type {number} */ var w = level0.getWidth(); + /** @type {number} */ var h = level0.getHeight(); + /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h)); + + for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) { + if (this.hasLevel(baseLevel + levelNdx)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx); + /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx); + /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx); + + if (level.getWidth() != expectedW || + level.getHeight() != expectedH || + !level.getFormat().isEqual(format)) + return false; + } else + return false; + } + } + + return true; + } else + return false; + }; + + /** + */ + sglrReferenceContext.Texture2D.prototype.updateView = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) { + // Update number of levels in mipmap pyramid. + /** @type {number} */ var width = this.getLevel(baseLevel).getWidth(); + /** @type {number} */ var height = this.getLevel(baseLevel).getHeight(); + /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1; + + this.m_view = new tcuTexture.Texture2DView(numLevels, this.m_levels.getLevels().slice(baseLevel)); + } else + this.m_view = new tcuTexture.Texture2DView(0, null); + }; + + /** + * @param {Array<number>} pos + * @param {number=} lod + * @return {Array<number>} + */ + sglrReferenceContext.Texture2D.prototype.sample = function(pos, lod) { + return this.m_view.sample(this.getSampler(), pos, lod); + }; + + /** + * @param {Array<Array<number>>} packetTexcoords 4 vec2 coordinates + * @param {number} lodBias_ + * @return {Array<Array<number>>} 4 vec4 samples + */ + sglrReferenceContext.Texture2D.prototype.sample4 = function(packetTexcoords, lodBias_) { + /** @type {number} */ var lodBias = lodBias_ || 0; + /** @type {number} */ var texWidth = this.m_view.getWidth(); + /** @type {number} */ var texHeight = this.m_view.getHeight(); + /** @type {Array<Array<number>>}*/ var output = []; + + /** @type {Array<number>}*/ var dFdx0 = deMath.subtract(packetTexcoords[1], packetTexcoords[0]); + /** @type {Array<number>}*/ var dFdx1 = deMath.subtract(packetTexcoords[3], packetTexcoords[2]); + /** @type {Array<number>}*/ var dFdy0 = deMath.subtract(packetTexcoords[2], packetTexcoords[0]); + /** @type {Array<number>}*/ var dFdy1 = deMath.subtract(packetTexcoords[3], packetTexcoords[1]); + + for (var fragNdx = 0; fragNdx < 4; ++fragNdx) { + /** @type {Array<number>}*/var dFdx = (fragNdx & 2) ? dFdx1 : dFdx0; + /** @type {Array<number>}*/var dFdy = (fragNdx & 1) ? dFdy1 : dFdy0; + + /** @type {number} */ var mu = Math.max(Math.abs(dFdx[0]), Math.abs(dFdy[0])); + /** @type {number} */ var mv = Math.max(Math.abs(dFdx[1]), Math.abs(dFdy[1])); + /** @type {number} */ var p = Math.max(mu * texWidth, mv * texHeight); + + /** @type {number} */ var lod = Math.log2(p) + lodBias; + + output.push(this.sample([packetTexcoords[fragNdx][0], packetTexcoords[fragNdx][1]], lod)); + } + + return output; + }; + + /** + * @constructor + * @extends {sglrReferenceContext.Texture} + */ + sglrReferenceContext.TextureCube = function() { + sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_CUBE_MAP); + /** @type {tcuTexture.TextureCubeView} */ this.m_view = new tcuTexture.TextureCubeView(0, null); + /** @type {Array<sglrReferenceContext.TextureLevelArray>} */ this.m_levels = []; + for (var face in tcuTexture.CubeFace) + this.m_levels[tcuTexture.CubeFace[face]] = new sglrReferenceContext.TextureLevelArray(); + }; + + /** + */ + sglrReferenceContext.TextureCube.prototype = Object.create(sglrReferenceContext.Texture.prototype); + sglrReferenceContext.TextureCube.prototype.constructor = sglrReferenceContext.Texture2D; + + sglrReferenceContext.TextureCube.prototype.clearLevels = function() { + for (var face in tcuTexture.CubeFace) + this.m_levels[tcuTexture.CubeFace[face]].clear(); + }; + + /** + * @param {number} level + * @param {tcuTexture.CubeFace} face + * @return {boolean} + */ + sglrReferenceContext.TextureCube.prototype.hasFace = function(level, face) { return this.m_levels[face].hasLevel(level); }; + + /** + * @param {number} level + * @param {tcuTexture.CubeFace} face + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.TextureCube.prototype.getFace = function(level, face) { return this.m_levels[face].getLevel(level); }; + + /** + * @param {number} level + * @param {tcuTexture.CubeFace} face + * @param {?tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.TextureCube.prototype.allocLevel = function(level, face, format, width, height) { + this.m_levels[face].allocLevel(level, format, width, height, 1); + }; + + sglrReferenceContext.TextureCube.prototype.isComplete = function() { + var baseLevel = this.getBaseLevel(); + + if (this.hasFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X)) { + var level = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X); + var width = level.getWidth(); + var height = level.getHeight(); + var format = level.getFormat(); + var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + var numLevels = mipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1; + + if (width != height) + return false; // Non-square is not supported. + + // \note Level 0 is always checked for consistency + for (var levelNdx = 0; levelNdx < numLevels; levelNdx++) { + var levelW = sglrReferenceContext.getMipLevelSize(width, levelNdx); + var levelH = sglrReferenceContext.getMipLevelSize(height, levelNdx); + + for (var face in tcuTexture.CubeFace) { + if (this.hasFace(baseLevel + levelNdx, tcuTexture.CubeFace[face])) { + level = this.getFace(baseLevel + levelNdx, tcuTexture.CubeFace[face]); + + if (level.getWidth() != levelW || + level.getHeight() != levelH || + !level.getFormat().isEqual(format)) + return false; + } else + return false; + } + } + + return true; + } else + return false; + }; + + sglrReferenceContext.TextureCube.prototype.updateView = function() { + + var baseLevel = this.getBaseLevel(); + var faces = []; + + if (this.isComplete()) { + var size = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X).getWidth(); + var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels1D(size)) : 1; + + for (var face in tcuTexture.CubeFace) + faces[tcuTexture.CubeFace[face]] = this.m_levels[tcuTexture.CubeFace[face]].getLevels().slice(baseLevel); + + this.m_view = new tcuTexture.TextureCubeView(numLevels, faces); + } else + this.m_view = new tcuTexture.TextureCubeView(0, null); + }; + + /** + * @param {Array<number>} pos + * @param {number=} lod + * @return {Array<number>} + */ + sglrReferenceContext.TextureCube.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) }; + + /** + * @constructor + * @extends {sglrReferenceContext.Texture} + */ + sglrReferenceContext.Texture2DArray = function() { + sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY); + /** @type {tcuTexture.Texture2DArrayView} */ this.m_view = new tcuTexture.Texture2DArrayView(0, null); + /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray(); + }; + + /** + */ + sglrReferenceContext.Texture2DArray.prototype = Object.create(sglrReferenceContext.Texture.prototype); + sglrReferenceContext.Texture2DArray.prototype.constructor = sglrReferenceContext.Texture2DArray; + + sglrReferenceContext.Texture2DArray.prototype.clearLevels = function() { this.m_levels.clear(); }; + + /** + * @param {number} level + * @return {boolean} + */ + sglrReferenceContext.Texture2DArray.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); }; + + /** + * @param {number} level + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.Texture2DArray.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); }; + + /** + * @param {number} level + * @param {?tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + * @param {number} numLayers + */ + sglrReferenceContext.Texture2DArray.prototype.allocLevel = function(level, format, width, height, numLayers) { + this.m_levels.allocLevel(level, format, width, height, numLayers); + }; + + /** + * @return {boolean} + */ + sglrReferenceContext.Texture2DArray.prototype.isComplete = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel); + /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + + if (mipmap) { + /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat(); + /** @type {number} */ var w = level0.getWidth(); + /** @type {number} */ var h = level0.getHeight(); + /** @type {number} */ var numLayers = level0.getDepth(); + /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h)); + + for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) { + if (this.hasLevel(baseLevel + levelNdx)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx); + /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx); + /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx); + + if (level.getWidth() != expectedW || + level.getHeight() != expectedH || + level.getDepth() != numLayers || + !level.getFormat().isEqual(format)) + return false; + } else + return false; + } + } + + return true; + } else + return false; + }; + + /** + */ + sglrReferenceContext.Texture2DArray.prototype.updateView = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) { + // Update number of levels in mipmap pyramid. + /** @type {number} */ var width = this.getLevel(baseLevel).getWidth(); + /** @type {number} */ var height = this.getLevel(baseLevel).getHeight(); + /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1; + + this.m_view = new tcuTexture.Texture2DArrayView(numLevels, this.m_levels.getLevels().slice(baseLevel)); + } else + this.m_view = new tcuTexture.Texture2DArrayView(0, null); + }; + + /** + * @param {Array<number>} pos + * @param {number=} lod + * @return {Array<number>} + */ + sglrReferenceContext.Texture2DArray.prototype.sample = function(pos, lod) { + return this.m_view.sample(this.getSampler(), pos, lod); + }; + + /** + * @constructor + * @extends {sglrReferenceContext.Texture} + */ + sglrReferenceContext.Texture3D = function() { + sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY); + /** @type {tcuTexture.Texture3DView} */ this.m_view = new tcuTexture.Texture3DView(0, null); + /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray(); + }; + + /** + */ + sglrReferenceContext.Texture3D.prototype = Object.create(sglrReferenceContext.Texture.prototype); + sglrReferenceContext.Texture3D.prototype.constructor = sglrReferenceContext.Texture3D; + + sglrReferenceContext.Texture3D.prototype.clearLevels = function() { this.m_levels.clear(); }; + + /** + * @param {number} level + * @return {boolean} + */ + sglrReferenceContext.Texture3D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); }; + + /** + * @param {number} level + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.Texture3D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); }; + + /** + * @param {number} level + * @param {?tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + * @param {number} depth + */ + sglrReferenceContext.Texture3D.prototype.allocLevel = function(level, format, width, height, depth) { + this.m_levels.allocLevel(level, format, width, height, depth); + }; + + /** + * @return {boolean} + */ + sglrReferenceContext.Texture3D.prototype.isComplete = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel); + /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + + if (mipmap) { + /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat(); + /** @type {number} */ var w = level0.getWidth(); + /** @type {number} */ var h = level0.getHeight(); + /** @type {number} */ var d = level0.getDepth(); + /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels3D(w, h, d)); + + for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) { + if (this.hasLevel(baseLevel + levelNdx)) { + /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx); + /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx); + /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx); + /** @type {number} */ var expectedD = sglrReferenceContext.getMipLevelSize(d, levelNdx); + + if (level.getWidth() != expectedW || + level.getHeight() != expectedH || + level.getDepth() != expectedD || + !level.getFormat().isEqual(format)) + return false; + } else + return false; + } + } + + return true; + } else + return false; + }; + + /** + */ + sglrReferenceContext.Texture3D.prototype.updateView = function() { + /** @type {number} */ var baseLevel = this.getBaseLevel(); + + if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) { + // Update number of levels in mipmap pyramid. + /** @type {number} */ var width = this.getLevel(baseLevel).getWidth(); + /** @type {number} */ var height = this.getLevel(baseLevel).getHeight(); + /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter); + /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1; + + this.m_view = new tcuTexture.Texture3DView(numLevels, this.m_levels.getLevels().slice(baseLevel)); + } else + this.m_view = new tcuTexture.Texture3DView(0, null); + }; + + /** + * @param {Array<number>} pos + * @param {number=} lod + * @return {Array<number>} + */ + sglrReferenceContext.Texture3D.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) }; + + /** + * A container object for storing one of texture types; + * @constructor + */ + sglrReferenceContext.TextureContainer = function() { + /** @type {sglrReferenceContext.Texture2D | sglrReferenceContext.TextureCube|sglrReferenceContext.Texture2DArray|sglrReferenceContext.Texture3D} */ + this.texture = null; + /** @type {?sglrReferenceContext.TextureType} */ this.textureType = null; + }; + + /** + * @return {?sglrReferenceContext.TextureType} + */ + sglrReferenceContext.TextureContainer.prototype.getType = function() { return this.textureType; }; + + /** + * @param {number} target + * @throws {Error} + */ + sglrReferenceContext.TextureContainer.prototype.init = function(target) { + switch (target) { + case gl.TEXTURE_2D: + this.texture = new sglrReferenceContext.Texture2D(); + this.textureType = sglrReferenceContext.TextureType.TYPE_2D; + break; + case gl.TEXTURE_CUBE_MAP: + this.texture = new sglrReferenceContext.TextureCube(); + this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP; + break; + case gl.TEXTURE_2D_ARRAY: + this.texture = new sglrReferenceContext.Texture2DArray(); + this.textureType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY; + break; + case gl.TEXTURE_3D: + this.texture = new sglrReferenceContext.Texture3D(); + this.textureType = sglrReferenceContext.TextureType.TYPE_3D; + break; + /* TODO: Implement other types */ + // case gl.TEXTURE_CUBE_MAP_ARRAY: + // this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY; + // break; + default: throw new Error('Unrecognized target: ' + target); + } + }; + + /** + * @enum + */ + sglrReferenceContext.AttachmentPoint = { + ATTACHMENTPOINT_COLOR0: 0, + ATTACHMENTPOINT_DEPTH: 1, + ATTACHMENTPOINT_STENCIL: 2 + }; + + /** + * @param {number} attachment + * @return {sglrReferenceContext.AttachmentPoint} + * @throws {Error} + */ + sglrReferenceContext.mapGLAttachmentPoint = function(attachment) { + switch (attachment) { + case gl.COLOR_ATTACHMENT0: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0; + case gl.DEPTH_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH; + case gl.STENCIL_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL; + default: throw new Error('Wrong attachment point:' + attachment); + } + }; + + /** + * @enum + */ + sglrReferenceContext.AttachmentType = { + ATTACHMENTTYPE_RENDERBUFFER: 0, + ATTACHMENTTYPE_TEXTURE: 1 + }; + + /** + * @enum + */ + sglrReferenceContext.TexTarget = { + TEXTARGET_2D: 0, + TEXTARGET_CUBE_MAP_POSITIVE_X: 1, + TEXTARGET_CUBE_MAP_POSITIVE_Y: 2, + TEXTARGET_CUBE_MAP_POSITIVE_Z: 3, + TEXTARGET_CUBE_MAP_NEGATIVE_X: 4, + TEXTARGET_CUBE_MAP_NEGATIVE_Y: 5, + TEXTARGET_CUBE_MAP_NEGATIVE_Z: 6, + TEXTARGET_2D_ARRAY: 7, + TEXTARGET_3D: 8, + TEXTARGET_CUBE_MAP_ARRAY: 9 + }; + + /** + * @param {?sglrReferenceContext.TexTarget} target + * @return {tcuTexture.CubeFace} + */ + sglrReferenceContext.texTargetToFace = function(target) { + switch (target) { + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X; + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y; + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y; + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z; + case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z; + default: throw new Error('Invalid target ' + target); + } + }; + + /** + * @param {sglrReferenceContext.TexTarget} target + * @return {sglrReferenceContext.TexTarget} + * @throws {Error} + */ + sglrReferenceContext.mapGLFboTexTarget = function(target) { + switch (target) { + case gl.TEXTURE_2D: return sglrReferenceContext.TexTarget.TEXTARGET_2D; + case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X; + case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y; + case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z; + case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X; + case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y; + case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z; + default: throw new Error('Wrong texture target:' + target); + } + }; + + /** + * @constructor + */ + sglrReferenceContext.Attachment = function() { + /** @type {?sglrReferenceContext.AttachmentType} */ this.type = null; + /** @type {sglrReferenceContext.TextureContainer|sglrReferenceContext.Renderbuffer} */ this.object = null; // TODO: fix reserved word + /** @type {?sglrReferenceContext.TexTarget} */ this.texTarget = null; + /** @type {number} */ this.level = 0; + /** @type {number} */ this.layer = 0; + }; + + /** + * @constructor + */ + sglrReferenceContext.Framebuffer = function() { + /** @type {Array<sglrReferenceContext.Attachment>} */ this.m_attachments = []; + for (var key in sglrReferenceContext.AttachmentPoint) + this.m_attachments[sglrReferenceContext.AttachmentPoint[key]] = new sglrReferenceContext.Attachment(); + }; + + /** + * @param {sglrReferenceContext.AttachmentPoint} point + * @return {sglrReferenceContext.Attachment} + */ + sglrReferenceContext.Framebuffer.prototype.getAttachment = function(point) { return this.m_attachments[point]; }; + + /** + * @param {sglrReferenceContext.AttachmentPoint} point + * @param {sglrReferenceContext.Attachment} attachment + */ + sglrReferenceContext.Framebuffer.prototype.setAttachment = function(point, attachment) { this.m_attachments[point] = attachment; }; + + // /** + // * @enum + // */ + // var Format = { + // FORMAT_DEPTH_COMPONENT16: 0, + // FORMAT_RGBA4: 1, + // FORMAT_RGB5_A1: 2, + // FORMAT_RGB565: 3, + // FORMAT_STENCIL_INDEX8: 4 + // }; + + /** + * @constructor + */ + sglrReferenceContext.Renderbuffer = function() { + /** @type {tcuTexture.TextureLevel} */ this.m_data; + }; + + /** + * @param {tcuTexture.TextureFormat} format + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.Renderbuffer.prototype.setStorage = function(format, width, height) { + this.m_data = new tcuTexture.TextureLevel(format, width, height); + }; + + /** + * @return {number} + */ + sglrReferenceContext.Renderbuffer.prototype.getWidth = function() { return this.m_data.getWidth(); }; + + /** + * @return {number} + */ + sglrReferenceContext.Renderbuffer.prototype.getHeight = function() { return this.m_data.getHeight(); }; + + /** + * @return {?tcuTexture.TextureFormat} + */ + sglrReferenceContext.Renderbuffer.prototype.getFormat = function() { return this.m_data.getFormat(); }; + + /** + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.Renderbuffer.prototype.getAccess = function() { return this.m_data.getAccess(); }; + + /** + * @constructor + * @param {number} maxVertexAttribs + */ + sglrReferenceContext.VertexArray = function(maxVertexAttribs) { + /** @type {sglrReferenceContext.DataBuffer} */ this.m_elementArrayBufferBinding = null; + + /** @type {Array<sglrReferenceContext.VertexArray.VertexAttribArray>} */this.m_arrays = []; + for (var i = 0; i < maxVertexAttribs; i++) + this.m_arrays.push(new sglrReferenceContext.VertexArray.VertexAttribArray()); + }; + + /** @constructor */ + sglrReferenceContext.VertexArray.VertexAttribArray = function() { + this.enabled = false; + this.size = 4; + this.stride = 0; + this.type = gl.FLOAT; + + this.normalized = false; + this.integer = false; + this.divisor = 0; + this.offset = 0; + this.bufferBinding = null; + }; + + /** + * @constructor + */ + sglrReferenceContext.DataBuffer = function() { + /** @type {?ArrayBuffer} */ this.m_data = null; + }; + + /** + * @param {number} size + */ + sglrReferenceContext.DataBuffer.prototype.setStorage = function(size) {this.m_data = new ArrayBuffer(size); }; + + /** + * @return {number} + */ + sglrReferenceContext.DataBuffer.prototype.getSize = function() { + /** @type {number} */ var size = 0; + if (this.m_data) + size = this.m_data.byteLength; + return size; + }; + + /** + * @return {?ArrayBuffer} + */ + sglrReferenceContext.DataBuffer.prototype.getData = function() { return this.m_data; }; + + /** + * @param {ArrayBuffer|goog.NumberArray} data + */ + sglrReferenceContext.DataBuffer.prototype.setData = function(data) { + /** @type {ArrayBuffer} */ var buffer; + /** @type {number} */ var offset = 0; + /** @type {number} */ var byteLength = data.byteLength; + if (data instanceof ArrayBuffer) + buffer = data; + else { + buffer = data.buffer; + offset = data.byteOffset; + } + + if (!buffer) + throw new Error('Invalid buffer'); + + this.m_data = buffer.slice(offset, offset + byteLength); + }; + + /** + * @param {number} offset + * @param {goog.NumberArray} data + */ + sglrReferenceContext.DataBuffer.prototype.setSubData = function(offset, data) { + /** @type {ArrayBuffer} */ var buffer; + /** @type {number} */ var srcOffset = 0; + /** @type {number} */ var byteLength = data.byteLength; + if (data instanceof ArrayBuffer) + buffer = data; + else { + buffer = data.buffer; + srcOffset = data.byteOffset; + } + + if (!buffer) + throw new Error('Invalid buffer'); + + /** @type {goog.NumberArray} */ var src = new Uint8Array(buffer, srcOffset, byteLength); + /** @type {goog.NumberArray} */ var dst = new Uint8Array(this.m_data, offset, byteLength); + dst.set(src); + }; + + // /** + // * @constructor + // */ + // var ObjectManager = function() { + // this.m_objects = {}; + // }; + + // ObjectManager.prototype.insert = function(obj) { + // var name = obj.getName(); + // if (!name) + // throw new Error("Cannot insert unnamed object"); + // this.m_objects[name] = obj; + // }; + + // ObjectManager.prototype.find = function(name) { return this.m_objects[name]; }; + + // ObjectManager.prototype.acquireReference = function(obj) { + // if (this.find(obj.getName()) !== obj) + // throw new Error("Object is not in the object manager"); + // obj.incRefCount(); + // }; + + // ObjectManager.prototype.releaseReference = function(obj) { + // if (this.find(obj.getName()) !== obj) + // throw new Error("Object is not in the object manager"); + + // obj.decRefCount(); + + // if (obj.getRefCount() == 0) + // delete this.m_objects[obj.getName()]; + // }; + + // ObjectManager.prototype.getAll = function() { return this.m_objects; }; + + /** + * @constructor + */ + sglrReferenceContext.TextureUnit = function() { + /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DBinding = null; + /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeBinding = null; + /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DArrayBinding = null; + /** @type {?sglrReferenceContext.TextureContainer} */ this.tex3DBinding = null; + /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeArrayBinding = null; + }; + + /** + * @constructor + */ + sglrReferenceContext.StencilState = function() { + /** @type {number} */ this.func = gl.ALWAYS; + /** @type {number} */ this.ref = 0; + /** @type {number} */ this.opMask = ~0; + /** @type {number} */ this.opStencilFail = gl.KEEP; + /** @type {number} */ this.opDepthFail = gl.KEEP; + /** @type {number} */ this.opDepthPass = gl.KEEP; + /** @type {number} */ this.writeMask = ~0; + }; + + /** + * @param {tcuPixelFormat.PixelFormat} pixelFmt + * @return {tcuTexture.TextureFormat} + * @throws {Error} + */ + sglrReferenceContext.toTextureFormat = function(pixelFmt) { + if (pixelFmt.equals(8, 8, 8, 8)) + return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8); + else if (pixelFmt.equals(8, 8, 8, 0)) + return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8); + else if (pixelFmt.equals(4, 4, 4, 4)) + return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444); + else if (pixelFmt.equals(5, 5, 5, 1)) + return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551); + else if (pixelFmt.equals(5, 6, 5, 0)) + return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565); + + throw new Error('Could not map pixel format:' + pixelFmt); + }; + + /** + * @param {number} depthBits + * @return {tcuTexture.TextureFormat} + * @throws {Error} + */ + sglrReferenceContext.getDepthFormat = function(depthBits) { + switch (depthBits) { + case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT8); + case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16); + case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8); + case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT); + default: + throw new Error("Can't map depth buffer format, bits: " + depthBits); + } + }; + + /** + * @param {number} stencilBits + * @return {tcuTexture.TextureFormat} + * @throws {Error} + */ + sglrReferenceContext.getStencilFormat = function(stencilBits) { + switch (stencilBits) { + case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8); + case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT16); + case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT_24_8); + case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT32); + default: + throw new Error("Can't map stencil buffer format, bits: " + stencilBits); + } + }; + + /** + * @constructor + * @param {tcuPixelFormat.PixelFormat} colorBits + * @param {number} depthBits + * @param {number} stencilBits + * @param {number} width + * @param {number} height + * @param {number=} samples_ + */ + sglrReferenceContext.ReferenceContextBuffers = function(colorBits, depthBits, stencilBits, width, height, samples_) { + if (samples_ === undefined) + samples_ = 1; + + /** @type {number} */ var samples = samples_; + /** @type {tcuTexture.TextureLevel} */ this.m_colorbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.toTextureFormat(colorBits), samples, width, height); + + if (depthBits > 0) + /** @type {tcuTexture.TextureLevel} */ this.m_depthbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getDepthFormat(depthBits), samples, width, height); + + if (stencilBits > 0) + /** @type {tcuTexture.TextureLevel} */ this.m_stencilbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getStencilFormat(stencilBits), samples, width, height); + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContextBuffers.prototype.getColorbuffer = function() { return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_colorbuffer.getAccess()); }; + + /** + * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContextBuffers.prototype.getDepthbuffer = function() { return this.m_depthbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_depthbuffer.getAccess()) : null; }; + + /** + * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContextBuffers.prototype.getStencilbuffer = function() { return this.m_stencilbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_stencilbuffer.getAccess()) : null; }; + + /** + * @param {sglrReferenceContext.ReferenceContextLimits} limits + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} colorbuffer + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} depthbuffer + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} stencilbuffer + * @constructor + */ + sglrReferenceContext.ReferenceContext = function(limits, colorbuffer, depthbuffer, stencilbuffer) { + /** @type {sglrReferenceContext.ReferenceContextLimits} */ this.m_limits = limits; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultColorbuffer = colorbuffer; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultDepthbuffer = depthbuffer; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultStencilbuffer = stencilbuffer; + /** @type {Array<number>} */ this.m_viewport = [0, 0, colorbuffer.raw().getHeight(), colorbuffer.raw().getDepth()]; + /** @type {Array<sglrReferenceContext.TextureUnit>} */ this.m_textureUnits = []; + for (var i = 0; i < this.m_limits.maxTextureImageUnits; i++) + this.m_textureUnits.push(new sglrReferenceContext.TextureUnit()); + /** @type {number} */ this.m_activeTexture = 0; + /** @type {number} */ this.m_lastError = gl.NO_ERROR; + // this.m_textures = new ObjectManager(); + /** @type {number} */ this.m_pixelUnpackRowLength = 0; + /** @type {number} */ this.m_pixelUnpackSkipRows = 0; + /** @type {number} */ this.m_pixelUnpackSkipPixels = 0; + /** @type {number} */ this.m_pixelUnpackImageHeight = 0; + /** @type {number} */ this.m_pixelUnpackSkipImages = 0; + /** @type {number} */ this.m_pixelUnpackAlignment = 4; + /** @type {number} */ this.m_pixelPackAlignment = 4; + /** @type {Array<number>} */ this.m_clearColor = [0, 0, 0, 0]; + /** @type {number} */ this.m_clearDepth = 1; + /** @type {number} */ this.m_clearStencil = 0; + /** @type {Array<number>} */ this.m_scissorBox = this.m_viewport; + /** @type {boolean} */ this.m_blendEnabled = false; + /** @type {boolean} */ this.m_scissorEnabled = false; + /** @type {boolean} */ this.m_depthTestEnabled = false; + /** @type {boolean} */ this.m_stencilTestEnabled = false; + /** @type {boolean} */ this.m_polygonOffsetFillEnabled = false; + /** @type {boolean} */ this.m_primitiveRestartFixedIndex = true; //always on + /** @type {boolean} */ this.m_primitiveRestartSettableIndex = true; //always on + /** @type {Array<sglrReferenceContext.StencilState>} */ this.m_stencil = []; + for (var type in rrDefs.FaceType) + this.m_stencil[rrDefs.FaceType[type]] = new sglrReferenceContext.StencilState(); + /** @type {number} */ this.m_depthFunc = gl.LESS; + /** @type {number} */ this.m_depthRangeNear = 0; + /** @type {number} */ this.m_depthRangeFar = 1; + /** @type {number} */ this.m_polygonOffsetFactor = 0; + /** @type {number} */ this.m_polygonOffsetUnits = 0; + /** @type {number} */ this.m_blendModeRGB = gl.FUNC_ADD; + /** @type {number} */ this.m_blendModeAlpha = gl.FUNC_ADD; + /** @type {number} */ this.m_blendFactorSrcRGB = gl.ONE; + /** @type {number} */ this.m_blendFactorDstRGB = gl.ZERO; + /** @type {number} */ this.m_blendFactorSrcAlpha = gl.ONE; + /** @type {number} */ this.m_blendFactorDstAlpha = gl.ZERO; + /** @type {Array<number>} */ this.m_blendColor = [0, 0, 0, 0]; + /** @type {boolean} */ this.m_sRGBUpdateEnabled = true; + /** @type {Array<boolean>} */ this.m_colorMask = [true, true, true, true]; + /** @type {boolean} */ this.m_depthMask = true; + /** @type {sglrReferenceContext.VertexArray} */ this.m_defaultVAO = new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs); + /** @type {sglrReferenceContext.VertexArray} */ this.m_vertexArrayBinding = this.m_defaultVAO; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_arrayBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyReadBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyWriteBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_drawIndirectBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelPackBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelUnpackBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_transformFeedbackBufferBinding = null; + /** @type {sglrReferenceContext.DataBuffer} */ this.m_uniformBufferBinding = null; + /** @type {sglrReferenceContext.Framebuffer} */ this.m_readFramebufferBinding = null; + /** @type {sglrReferenceContext.Framebuffer} */ this.m_drawFramebufferBinding = null; + /** @type {sglrReferenceContext.Renderbuffer} */ this.m_renderbufferBinding = null; + /** @type {sglrShaderProgram.ShaderProgram} */ this.m_currentProgram = null; + /** @type {Array<rrGenericVector.GenericVec4>} */ this.m_currentAttribs = []; + for (var i = 0; i < this.m_limits.maxVertexAttribs; i++) + this.m_currentAttribs.push(new rrGenericVector.GenericVec4()); + /** @type {number} */ this.m_lineWidth = 1; + + /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2D = new sglrReferenceContext.TextureContainer(); + this.m_emptyTex2D.init(gl.TEXTURE_2D); + this.m_emptyTex2D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex2D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex2D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex2D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex2D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1); + this.m_emptyTex2D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0); + this.m_emptyTex2D.texture.updateView(); + + /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTexCube = new sglrReferenceContext.TextureContainer(); + this.m_emptyTexCube.init(gl.TEXTURE_CUBE_MAP); + this.m_emptyTexCube.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTexCube.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTexCube.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTexCube.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST; + + for (var face in tcuTexture.CubeFace) { + this.m_emptyTexCube.texture.allocLevel(0, tcuTexture.CubeFace[face], + new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1); + this.m_emptyTexCube.texture.getFace(0, tcuTexture.CubeFace[face]).setPixel([0, 0, 0, 1], 0, 0); + } + this.m_emptyTexCube.texture.updateView(); + + /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2DArray = new sglrReferenceContext.TextureContainer(); + this.m_emptyTex2DArray.init(gl.TEXTURE_2D_ARRAY); + this.m_emptyTex2DArray.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex2DArray.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex2DArray.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex2DArray.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex2DArray.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex2DArray.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1); + this.m_emptyTex2DArray.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0); + this.m_emptyTex2DArray.texture.updateView(); + + /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex3D = new sglrReferenceContext.TextureContainer(); + this.m_emptyTex3D.init(gl.TEXTURE_3D); + this.m_emptyTex3D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex3D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex3D.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE; + this.m_emptyTex3D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex3D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST; + this.m_emptyTex3D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1); + this.m_emptyTex3D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0); + this.m_emptyTex3D.texture.updateView(); + + /** @type {sglrReferenceContext.TextureType} */ this.m_type; + + /** @type {boolean} */ this.m_immutable; + + /** @type {tcuTexture.Sampler} */ this.m_sampler; + /** @type {number} */ this.m_baseLevel; + /** @type {number} */ this.m_maxLevel; + }; + + /** + * @return {number} + */ + sglrReferenceContext.ReferenceContext.prototype.getWidth = function() { return this.m_defaultColorbuffer.raw().getHeight(); }; + + /** + * @return {number} + */ + sglrReferenceContext.ReferenceContext.prototype.getHeight = function() { return this.m_defaultColorbuffer.raw().getDepth(); }; + + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.viewport = function(x, y, width, height) { this.m_viewport = [x, y, width, height]; }; + + /** + * @param {number} texture + */ + sglrReferenceContext.ReferenceContext.prototype.activeTexture = function(texture) { + if (deMath.deInBounds32(texture, gl.TEXTURE0, gl.TEXTURE0 + this.m_textureUnits.length)) + this.m_activeTexture = texture - gl.TEXTURE0; + else + this.setError(gl.INVALID_ENUM); + }; + + /** + * @param {number} error + */ + sglrReferenceContext.ReferenceContext.prototype.setError = function(error) { + if (this.m_lastError == gl.NO_ERROR) + this.m_lastError = error; + }; + + /** + * @return {number} error + */ + sglrReferenceContext.ReferenceContext.prototype.getError = function() { + /** @type {number} */ var err = this.m_lastError; + this.m_lastError = gl.NO_ERROR; + return err; + }; + + /** + * @param {boolean} condition + * @param {number} error + */ + sglrReferenceContext.ReferenceContext.prototype.conditionalSetError = function(condition, error) { + if (condition) + this.setError(error); + return condition; + }; + + /** + * @param {number} target + * @param {sglrReferenceContext.TextureContainer} texture + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.bindTexture = function(target, texture) { + /** @type {number} */ var unitNdx = this.m_activeTexture; + + if (this.conditionalSetError((target != gl.TEXTURE_2D && + target != gl.TEXTURE_CUBE_MAP && + target != gl.TEXTURE_2D_ARRAY && + target != gl.TEXTURE_3D), // && + // target != gl.TEXTURE_CUBE_MAP_ARRAY), + gl.INVALID_ENUM)) + return; + + if (!texture) { + // Clear binding. + switch (target) { + case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, null); break; + case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, null); break; + case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, null); break; + case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, null); break; + default: + throw new Error('Unrecognized target: ' + target); + } + } else { + if (texture.textureType == null) { + texture.init(target); + } else { + // Validate type. + /** @type {sglrReferenceContext.TextureType} */ var expectedType; + switch (target) { + case gl.TEXTURE_2D: expectedType = sglrReferenceContext.TextureType.TYPE_2D; break; + case gl.TEXTURE_CUBE_MAP: expectedType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP; break; + case gl.TEXTURE_2D_ARRAY: expectedType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY; break; + case gl.TEXTURE_3D: expectedType = sglrReferenceContext.TextureType.TYPE_3D; break; + default: throw new Error('Unrecognized target: ' + target); + } + if (this.conditionalSetError((texture.textureType != expectedType), gl.INVALID_OPERATION)) + return; + } + switch (target) { + case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, texture); break; + case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, texture); break; + case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, texture); break; + case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, texture); break; + default: + throw new Error('Unrecognized target: ' + target); + } + } + }; + + /** + * @param {number} unitNdx + * @param {?sglrReferenceContext.TextureContainer} texture + */ + sglrReferenceContext.ReferenceContext.prototype.setTexCubeBinding = function(unitNdx, texture) { + if (this.m_textureUnits[unitNdx].texCubeBinding) { + this.m_textureUnits[unitNdx].texCubeBinding = null; + } + + if (texture) { + this.m_textureUnits[unitNdx].texCubeBinding = texture; + } + }; + + /** + * @param {number} unitNdx + * @param {?sglrReferenceContext.TextureContainer} texture + */ + sglrReferenceContext.ReferenceContext.prototype.setTex2DBinding = function(unitNdx, texture) { + if (this.m_textureUnits[unitNdx].tex2DBinding) { + // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DBinding); + this.m_textureUnits[unitNdx].tex2DBinding = null; + } + + if (texture) { + // this.m_textures.acquireReference(texture); + this.m_textureUnits[unitNdx].tex2DBinding = texture; + } + }; + + /** + * @param {number} unitNdx + * @param {?sglrReferenceContext.TextureContainer} texture + */ + sglrReferenceContext.ReferenceContext.prototype.setTex2DArrayBinding = function(unitNdx, texture) { + if (this.m_textureUnits[unitNdx].tex2DArrayBinding) { + // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DArrayBinding); + this.m_textureUnits[unitNdx].tex2DArrayBinding = null; + } + + if (texture) { + // this.m_textures.acquireReference(texture); + this.m_textureUnits[unitNdx].tex2DArrayBinding = texture; + } + }; + + /** + * @param {number} unitNdx + * @param {?sglrReferenceContext.TextureContainer} texture + */ + sglrReferenceContext.ReferenceContext.prototype.setTex3DBinding = function(unitNdx, texture) { + if (this.m_textureUnits[unitNdx].tex3DBinding) { + // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex3DBinding); + this.m_textureUnits[unitNdx].tex3DBinding = null; + } + + if (texture) { + // this.m_textures.acquireReference(texture); + this.m_textureUnits[unitNdx].tex3DBinding = texture; + } + }; + + /** + * @return {sglrReferenceContext.TextureContainer} + */ + sglrReferenceContext.ReferenceContext.prototype.createTexture = function() { return new sglrReferenceContext.TextureContainer(); }; + + /** + * @param {sglrReferenceContext.Texture} texture + */ + sglrReferenceContext.ReferenceContext.prototype.deleteTexture = function(texture) { /*empty*/ }; + + /** + * @param {number} target + * @param {framework.opengl.simplereference.sglrReferenceContext.Framebuffer} fbo + */ + sglrReferenceContext.ReferenceContext.prototype.bindFramebuffer = function(target, fbo) { + if (this.conditionalSetError((target != gl.FRAMEBUFFER && + target != gl.DRAW_FRAMEBUFFER && + target != gl.READ_FRAMEBUFFER), gl.INVALID_ENUM)) + return; + for (var ndx = 0; ndx < 2; ndx++) { + /** @type {number} */ var bindingTarget = ndx ? gl.DRAW_FRAMEBUFFER : gl.READ_FRAMEBUFFER; + + if (target != gl.FRAMEBUFFER && target != bindingTarget) + continue; // Doesn't match this target. + + if (ndx) + this.m_drawFramebufferBinding = fbo; + else + this.m_readFramebufferBinding = fbo; + } + }; + + /** + * @return {sglrReferenceContext.Framebuffer} + */ + sglrReferenceContext.ReferenceContext.prototype.createFramebuffer = function() { return new sglrReferenceContext.Framebuffer(); }; + + /** + * @param {sglrReferenceContext.Framebuffer} fbo + */ + sglrReferenceContext.ReferenceContext.prototype.deleteFramebuffer = function(fbo) { /*empty*/ }; + + /** + * @param {number} target + * @param {sglrReferenceContext.Renderbuffer} rbo + */ + sglrReferenceContext.ReferenceContext.prototype.bindRenderbuffer = function(target, rbo) { + if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM)) + return; + + this.m_renderbufferBinding = rbo; + }; + + /** + * @return {sglrReferenceContext.Renderbuffer} + */ + sglrReferenceContext.ReferenceContext.prototype.createRenderbuffer = function() { return new sglrReferenceContext.Renderbuffer(); }; + + /** + * @param {sglrReferenceContext.Renderbuffer} rbo + */ + sglrReferenceContext.ReferenceContext.prototype.deleteRenderbuffer = function(rbo) { /*empty*/ }; + + /** + * @param {number} pname + * @param {number} param + */ + sglrReferenceContext.ReferenceContext.prototype.pixelStorei = function(pname, param) { + switch (pname) { + case gl.UNPACK_ALIGNMENT: + if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return; + this.m_pixelUnpackAlignment = param; + break; + + case gl.PACK_ALIGNMENT: + if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return; + this.m_pixelPackAlignment = param; + break; + + case gl.UNPACK_ROW_LENGTH: + if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return; + this.m_pixelUnpackRowLength = param; + break; + + case gl.UNPACK_SKIP_ROWS: + if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return; + this.m_pixelUnpackSkipRows = param; + break; + + case gl.UNPACK_SKIP_PIXELS: + if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return; + this.m_pixelUnpackSkipPixels = param; + break; + + case gl.UNPACK_IMAGE_HEIGHT: + if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return; + this.m_pixelUnpackImageHeight = param; + break; + + case gl.UNPACK_SKIP_IMAGES: + if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return; + this.m_pixelUnpackSkipImages = param; + break; + + default: + this.setError(gl.INVALID_ENUM); + } + }; + + /** + * @param {number} red + * @param {number} green + * @param {number} blue + * @param {number} alpha + */ + sglrReferenceContext.ReferenceContext.prototype.clearColor = function(red, green, blue, alpha) { + this.m_clearColor = [deMath.clamp(red, 0, 1), + deMath.clamp(green, 0, 1), + deMath.clamp(blue, 0, 1), + deMath.clamp(alpha, 0, 1)]; + }; + + /** + * @param {number} depth + */ + sglrReferenceContext.ReferenceContext.prototype.clearDepthf = function(depth) { + this.m_clearDepth = deMath.clamp(depth, 0, 1); + }; + + /** + * @param {number} stencil + */ + sglrReferenceContext.ReferenceContext.prototype.clearStencil = function(stencil) { + this.m_clearStencil = stencil; + }; + + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.scissor = function(x, y, width, height) { + if (this.conditionalSetError(width < 0 || height < 0, gl.INVALID_VALUE)) + return; + this.m_scissorBox = [x, y, width, height]; + }; + + /** + * @param {number} cap + */ + sglrReferenceContext.ReferenceContext.prototype.enable = function(cap) { + switch (cap) { + case gl.BLEND: this.m_blendEnabled = true; break; + case gl.SCISSOR_TEST: this.m_scissorEnabled = true; break; + case gl.DEPTH_TEST: this.m_depthTestEnabled = true; break; + case gl.STENCIL_TEST: this.m_stencilTestEnabled = true; break; + case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = true; break; + + case gl.DITHER: + // Not implemented - just ignored. + break; + + default: + this.setError(gl.INVALID_ENUM); + break; + } + }; + + /** + * @param {number} cap + */ + sglrReferenceContext.ReferenceContext.prototype.disable = function(cap) { + switch (cap) { + case gl.BLEND: this.m_blendEnabled = false; break; + case gl.SCISSOR_TEST: this.m_scissorEnabled = false; break; + case gl.DEPTH_TEST: this.m_depthTestEnabled = false; break; + case gl.STENCIL_TEST: this.m_stencilTestEnabled = false; break; + case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = false; break; + + case gl.DITHER: + // Not implemented - just ignored. + break; + + default: + this.setError(gl.INVALID_ENUM); + break; + } + }; + + /** + * @param {number} func + * @param {number} ref + * @param {number} mask + */ + sglrReferenceContext.ReferenceContext.prototype.stencilFunc = function(func, ref, mask) { + this.stencilFuncSeparate(gl.FRONT_AND_BACK, func, ref, mask); + }; + + /** + * @param {number} face + * @param {number} func + * @param {number} ref + * @param {number} mask + */ + sglrReferenceContext.ReferenceContext.prototype.stencilFuncSeparate = function(face, func, ref, mask) { + /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK; + /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK; + + if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM)) + return; + + for (var key in rrDefs.FaceType) { + /** @type {number} */ var type = rrDefs.FaceType[key]; + if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) || + (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) { + this.m_stencil[type].func = func; + this.m_stencil[type].ref = ref; + this.m_stencil[type].opMask = mask; + } + } + }; + + /** + * @param {number} func + * @return {boolean} + */ + sglrReferenceContext.isValidCompareFunc = function(func) { + switch (func) { + case gl.NEVER: + case gl.LESS: + case gl.LEQUAL: + case gl.GREATER: + case gl.GEQUAL: + case gl.EQUAL: + case gl.NOTEQUAL: + case gl.ALWAYS: + return true; + + default: + return false; + } + }; + + /** + * @param {number} op + * @return {boolean} + */ + sglrReferenceContext.isValidStencilOp = function(op) { + switch (op) { + case gl.KEEP: + case gl.ZERO: + case gl.REPLACE: + case gl.INCR: + case gl.INCR_WRAP: + case gl.DECR: + case gl.DECR_WRAP: + case gl.INVERT: + return true; + + default: + return false; + } + }; + + /** + * @param {number} sfail + * @param {number} dpfail + * @param {number} dppass + */ + sglrReferenceContext.ReferenceContext.prototype.stencilOp = function(sfail, dpfail, dppass) { + this.stencilOpSeparate(gl.FRONT_AND_BACK, sfail, dpfail, dppass); + }; + + /** + * @param {number} face + * @param {number} sfail + * @param {number} dpfail + * @param {number} dppass + */ + sglrReferenceContext.ReferenceContext.prototype.stencilOpSeparate = function(face, sfail, dpfail, dppass) { + /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK; + /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK; + + if (this.conditionalSetError((!sglrReferenceContext.isValidStencilOp(sfail) || + !sglrReferenceContext.isValidStencilOp(dpfail) || + !sglrReferenceContext.isValidStencilOp(dppass)), + gl.INVALID_ENUM)) + return; + + if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM)) + return; + + for (var key in rrDefs.FaceType) { + /** @type {number} */ var type = rrDefs.FaceType[key]; + if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) || + (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) { + this.m_stencil[type].opStencilFail = sfail; + this.m_stencil[type].opDepthFail = dpfail; + this.m_stencil[type].opDepthPass = dppass; + } + } + }; + + /** + * @param {number} func + */ + sglrReferenceContext.ReferenceContext.prototype.depthFunc = function(func) { + if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM)) + return; + this.m_depthFunc = func; + }; + + /** + * @param {number} n + * @param {number} f + */ + sglrReferenceContext.ReferenceContext.prototype.depthRange = function(n, f) { + this.m_depthRangeNear = deMath.clamp(n, 0, 1); + this.m_depthRangeFar = deMath.clamp(f, 0, 1); + }; + + /** + * @param {number} factor + * @param {number} units + */ + sglrReferenceContext.ReferenceContext.prototype.polygonOffset = function(factor, units) { + this.m_polygonOffsetFactor = factor; + this.m_polygonOffsetUnits = units; + }; + + /** + * @param {number} mode + * @return {boolean} + */ + sglrReferenceContext.isValidBlendEquation = function(mode) { + return mode == gl.FUNC_ADD || + mode == gl.FUNC_SUBTRACT || + mode == gl.FUNC_REVERSE_SUBTRACT || + mode == gl.MIN || + mode == gl.MAX; + }; + + /** + * @param {number} factor + * @return {boolean} + */ + sglrReferenceContext.isValidBlendFactor = function(factor) { + switch (factor) { + case gl.ZERO: + case gl.ONE: + case gl.SRC_COLOR: + case gl.ONE_MINUS_SRC_COLOR: + case gl.DST_COLOR: + case gl.ONE_MINUS_DST_COLOR: + case gl.SRC_ALPHA: + case gl.ONE_MINUS_SRC_ALPHA: + case gl.DST_ALPHA: + case gl.ONE_MINUS_DST_ALPHA: + case gl.CONSTANT_COLOR: + case gl.ONE_MINUS_CONSTANT_COLOR: + case gl.CONSTANT_ALPHA: + case gl.ONE_MINUS_CONSTANT_ALPHA: + case gl.SRC_ALPHA_SATURATE: + return true; + + default: + return false; + } + }; + + /** + * @param {number} mode + */ + sglrReferenceContext.ReferenceContext.prototype.blendEquation = function(mode) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(mode), gl.INVALID_ENUM)) + return; + this.m_blendModeRGB = mode; + this.m_blendModeAlpha = mode; + }; + + /** + * @param {number} modeRGB + * @param {number} modeAlpha + */ + sglrReferenceContext.ReferenceContext.prototype.blendEquationSeparate = function(modeRGB, modeAlpha) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(modeRGB) || + !sglrReferenceContext.isValidBlendEquation(modeAlpha), + gl.INVALID_ENUM)) + return; + + this.m_blendModeRGB = modeRGB; + this.m_blendModeAlpha = modeAlpha; + }; + + /** + * @param {number} src + * @param {number} dst + */ + sglrReferenceContext.ReferenceContext.prototype.blendFunc = function(src, dst) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(src) || + !sglrReferenceContext.isValidBlendFactor(dst), + gl.INVALID_ENUM)) + return; + + this.m_blendFactorSrcRGB = src; + this.m_blendFactorSrcAlpha = src; + this.m_blendFactorDstRGB = dst; + this.m_blendFactorDstAlpha = dst; + }; + + /** + * @param {number} srcRGB + * @param {number} dstRGB + * @param {number} srcAlpha + * @param {number} dstAlpha + */ + sglrReferenceContext.ReferenceContext.prototype.blendFuncSeparate = function(srcRGB, dstRGB, srcAlpha, dstAlpha) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(srcRGB) || + !sglrReferenceContext.isValidBlendFactor(dstRGB) || + !sglrReferenceContext.isValidBlendFactor(srcAlpha) || + !sglrReferenceContext.isValidBlendFactor(dstAlpha), + gl.INVALID_ENUM)) + return; + + this.m_blendFactorSrcRGB = srcRGB; + this.m_blendFactorSrcAlpha = srcAlpha; + this.m_blendFactorDstRGB = dstRGB; + this.m_blendFactorDstAlpha = dstAlpha; + }; + + /** + * @param {number} red + * @param {number} green + * @param {number} blue + * @param {number} alpha + */ + sglrReferenceContext.ReferenceContext.prototype.blendColor = function(red, green, blue, alpha) { + this.m_blendColor = [deMath.clamp(red, 0, 1), + deMath.clamp(green, 0, 1), + deMath.clamp(blue, 0, 1), + deMath.clamp(alpha, 0, 1)]; + }; + + /** + * @param {boolean} r + * @param {boolean} g + * @param {boolean} b + * @param {boolean} a + */ + sglrReferenceContext.ReferenceContext.prototype.colorMask = function(r, g, b, a) { + this.m_colorMask = [r, g, b, a]; + }; + + /** + * @param {boolean} mask + */ + sglrReferenceContext.ReferenceContext.prototype.depthMask = function(mask) { + this.m_depthMask = mask; + }; + + /** + * @param {number} mask + */ + sglrReferenceContext.ReferenceContext.prototype.stencilMask = function(mask) { + this.stencilMaskSeparate(gl.FRONT_AND_BACK, mask); + }; + + /** + * @param {number} face + * @param {number} mask + */ + sglrReferenceContext.ReferenceContext.prototype.stencilMaskSeparate = function(face, mask) { + /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK; + /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK; + + if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM)) + return; + + if (setFront) this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask = mask; + if (setBack) this.m_stencil[rrDefs.FaceType.FACETYPE_BACK].writeMask = mask; + }; + + /** + * @param {sglrReferenceContext.VertexArray} array + */ + sglrReferenceContext.ReferenceContext.prototype.bindVertexArray = function(array) { + if (array) + this.m_vertexArrayBinding = array; + else + this.m_vertexArrayBinding = this.m_defaultVAO; + }; + + /** + * @return {sglrReferenceContext.VertexArray} + */ + sglrReferenceContext.ReferenceContext.prototype.createVertexArray = function() { return new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs); }; + + /** + * @param {number} array + */ + sglrReferenceContext.ReferenceContext.prototype.deleteVertexArray = function(array) {}; + + /** + * @param {number} index + * @param {number} rawSize + * @param {number} type + * @param {boolean} normalized + * @param {number} stride + * @param {number} offset + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttribPointer = function(index, rawSize, type, normalized, stride, offset) { + /** @type {boolean} */ var allowBGRA = false; + /** @type {number} */ var effectiveSize = rawSize; + + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(effectiveSize <= 0 || effectiveSize > 4, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE && + type != gl.SHORT && type != gl.UNSIGNED_SHORT && + type != gl.INT && type != gl.UNSIGNED_INT && + type != gl.FLOAT && type != gl.HALF_FLOAT && + type != gl.INT_2_10_10_10_REV && type != gl.UNSIGNED_INT_2_10_10_10_REV, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(normalized != true && normalized != false, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError((type == gl.INT_2_10_10_10_REV || type == gl.UNSIGNED_INT_2_10_10_10_REV) && effectiveSize != 4, gl.INVALID_OPERATION)) + return; + if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION)) + return; + + /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type + + array_.size = rawSize; + array_.stride = stride; + array_.type = type; + array_.normalized = normalized; + array_.integer = false; + array_.offset = offset; + + array_.bufferBinding = this.m_arrayBufferBinding; + }; + + /** + * @param {number} index + * @param {number} size + * @param {number} type + * @param {number} stride + * @param {number} offset + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttribIPointer = function(index, size, type, stride, offset) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(size <= 0 || size > 4, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE && + type != gl.SHORT && type != gl.UNSIGNED_SHORT && + type != gl.INT && type != gl.UNSIGNED_INT, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION)) + return; + + /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type + + array_.size = size; + array_.stride = stride; + array_.type = type; + array_.normalized = false; + array_.integer = true; + array_.offset = offset; + + array_.bufferBinding = this.m_arrayBufferBinding; + }; + + /** + * @param {number} index + */ + sglrReferenceContext.ReferenceContext.prototype.enableVertexAttribArray = function(index) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_vertexArrayBinding.m_arrays[index].enabled = true; + }; + + /** + * @param {number} index + */ + sglrReferenceContext.ReferenceContext.prototype.disableVertexAttribArray = function(index) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_vertexArrayBinding.m_arrays[index].enabled = false; + }; + + /** + * @param {number} index + * @param {number} divisor + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttribDivisor = function(index, divisor) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_vertexArrayBinding.m_arrays[index].divisor = divisor; + }; + + /** + * @param {number} index + * @param {number} x + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttrib1f = function(index, x) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, 0, 0, 1); + }; + + /** + * @param {number} index + * @param {number} x + * @param {number} y + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttrib2f = function(index, x, y) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, 0, 1); + }; + + /** + * @param {number} index + * @param {number} x + * @param {number} y + * @param {number} z + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttrib3f = function(index, x, y, z) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, 1); + }; + + /** + * @param {number} index + * @param {number} x + * @param {number} y + * @param {number} z + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttrib4f = function(index, x, y, z, w) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w); + }; + + /** + * @param {number} index + * @param {number} x + * @param {number} y + * @param {number} z + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4i = function(index, x, y, z, w) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w); + }; + + /** + * @param {number} index + * @param {number} x + * @param {number} y + * @param {number} z + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4ui = function(index, x, y, z, w) { + if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE)) + return; + + this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w); + }; + + /** + * @param {sglrShaderProgram.ShaderProgram} program + * @param {string} name + * @return {number} + */ + sglrReferenceContext.ReferenceContext.prototype.getAttribLocation = function(program, name) { + if (this.conditionalSetError(!(program), gl.INVALID_OPERATION)) + return -1; + + for (var i = 0; i < program.m_attributeNames.length; i++) + if (program.m_attributeNames[i] === name) + return i; + + return -1; + }; + + /** + * @param {number} pname + */ + sglrReferenceContext.ReferenceContext.prototype.getParameter = function(pname) { + switch (pname) { + case (gl.VIEWPORT): return new Int32Array(this.m_viewport); + case (gl.SCISSOR_BOX): return new Int32Array(this.m_scissorBox); + default: + throw new Error('Unimplemented'); + } + }; + + /** + * @param {number} location + * @param {gluShaderUtil.DataType} type + * @param {Array<number>} value + */ + sglrReferenceContext.ReferenceContext.prototype.uniformValue = function(location, type, value) { + if (this.conditionalSetError(!this.m_currentProgram, gl.INVALID_OPERATION)) + return; + + if (location === null) + return; + + /** @type {sglrShaderProgram.Uniform} */ var uniform = this.m_currentProgram.m_uniforms[location]; + + if (this.conditionalSetError(!uniform, gl.INVALID_OPERATION)) + return; + + if (gluShaderUtil.isDataTypeSampler(uniform.type)) { + if (this.conditionalSetError(type != gluShaderUtil.DataType.INT, gl.INVALID_OPERATION)) + return; + } else if (this.conditionalSetError(uniform.type != type, gl.INVALID_OPERATION)) + return; + /* TODO: Do we need to copy objects? */ + uniform.value = value; + }; + + /** + * @param {number} location + * @param {number} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform1f = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, [x]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform1fv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, x); + }; + + /** + * @param {number} location + * @param {number} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform1i = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.INT, [x]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform1iv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.INT, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + */ + sglrReferenceContext.ReferenceContext.prototype.uniform2f = function(location, x, y) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, [x, y]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform2fv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + */ + sglrReferenceContext.ReferenceContext.prototype.uniform2i = function(location, x, y) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, [x, y]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform2iv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + * @param {number} z + */ + sglrReferenceContext.ReferenceContext.prototype.uniform3f = function(location, x, y, z) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, [x, y, z]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform3fv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + * @param {number} z + */ + sglrReferenceContext.ReferenceContext.prototype.uniform3i = function(location, x, y, z) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, [x, y, z]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform3iv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + * @param {number} z + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.uniform4f = function(location, x, y, z, w) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, [x, y, z, w]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform4fv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, x); + }; + + /** + * @param {number} location + * @param {number} x + * @param {number} y + * @param {number} z + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.uniform4i = function(location, x, y, z, w) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, [x, y, z, w]); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniform4iv = function(location, x) { + return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, x); + }; + + /** + * @return {Array<string>} + */ + sglrReferenceContext.ReferenceContext.prototype.getSupportedExtensions = function() { + var extensions = gl.getSupportedExtensions(); //TODO: Let's just return gl's supported extensions for now + return extensions; + }; + + /** + * @param {string} name + * @return {*} + */ + sglrReferenceContext.ReferenceContext.prototype.getExtension = function(name) { + return gl.getExtension(name); //TODO: Let's just return gl's supported extensions for now + }; + + /** transpose matrix 'x' of 'size' columns and rows + * @param {number} size + * @param {Array<number>} x + * @return {Array<number>} + */ + sglrReferenceContext.trans = function(size, x) { + /** @type {Array<number>} */ var result = []; + for (var row = 0; row < size; ++row) + for (var col = 0; col < size; ++col) + result[row * size + col] = x[col * size + row]; + + return result; + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniformMatrix2fv = function(location, transpose, x) { + /* change from column-major to internal row-major if transpose if FALSE */ + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT2, !transpose ? sglrReferenceContext.trans(2, x) : x); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniformMatrix3fv = function(location, transpose, x) { + /* change from column-major to internal row-major if transpose if FALSE */ + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT3, !transpose ? sglrReferenceContext.trans(3, x) : x); + }; + + /** + * @param {number} location + * @param {Array<number>} x + */ + sglrReferenceContext.ReferenceContext.prototype.uniformMatrix4fv = function(location, transpose, x) { + /* change from column-major to internal row-major if transpose if FALSE */ + return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT4, !transpose ? sglrReferenceContext.trans(4, x) : x); + }; + + /** + * @param {sglrShaderProgram.ShaderProgram} program + * @param {string} name + * @return {number} + */ + sglrReferenceContext.ReferenceContext.prototype.getUniformLocation = function(program, name) { + if (this.conditionalSetError(!program, gl.INVALID_OPERATION)) + return -1; + + for (var i = 0; i < program.m_uniforms.length; i++) + if (program.m_uniforms[i].name === name) + return i; + + return -1; + }; + + /** + * @param {number} w + */ + sglrReferenceContext.ReferenceContext.prototype.lineWidth = function(w) { + if (this.conditionalSetError(w < 0, gl.INVALID_VALUE)) + return; + this.m_lineWidth = w; + }; + + /** + * @param {number} target + * @return {boolean} + */ + sglrReferenceContext.isValidBufferTarget = function(target) { + switch (target) { + case gl.ARRAY_BUFFER: + case gl.COPY_READ_BUFFER: + case gl.COPY_WRITE_BUFFER: + case gl.ELEMENT_ARRAY_BUFFER: + case gl.PIXEL_PACK_BUFFER: + case gl.PIXEL_UNPACK_BUFFER: + case gl.TRANSFORM_FEEDBACK_BUFFER: + case gl.UNIFORM_BUFFER: + return true; + + default: + return false; + } + }; + + /** + * @param {number} target + * @param {sglrReferenceContext.DataBuffer} buffer + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.setBufferBinding = function(target, buffer) { + switch (target) { + case gl.ARRAY_BUFFER: this.m_arrayBufferBinding = buffer; break; + case gl.COPY_READ_BUFFER: this.m_copyReadBufferBinding = buffer; break; + case gl.COPY_WRITE_BUFFER: this.m_copyWriteBufferBinding = buffer; break; + case gl.ELEMENT_ARRAY_BUFFER: this.m_vertexArrayBinding.m_elementArrayBufferBinding = buffer; break; + case gl.PIXEL_PACK_BUFFER: this.m_pixelPackBufferBinding = buffer; break; + case gl.PIXEL_UNPACK_BUFFER: this.m_pixelUnpackBufferBinding = buffer; break; + case gl.TRANSFORM_FEEDBACK_BUFFER: this.m_transformFeedbackBufferBinding = buffer; break; + case gl.UNIFORM_BUFFER: this.m_uniformBufferBinding = buffer; break; + default: + throw new Error('Unrecognized target: ' + target); + } + }; + + /** + * @param {number} target + * @return {sglrReferenceContext.DataBuffer} + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.getBufferBinding = function(target) { + switch (target) { + case gl.ARRAY_BUFFER: return this.m_arrayBufferBinding; + case gl.COPY_READ_BUFFER: return this.m_copyReadBufferBinding; + case gl.COPY_WRITE_BUFFER: return this.m_copyWriteBufferBinding; + case gl.ELEMENT_ARRAY_BUFFER: return this.m_vertexArrayBinding.m_elementArrayBufferBinding; + case gl.PIXEL_PACK_BUFFER: return this.m_pixelPackBufferBinding; + case gl.PIXEL_UNPACK_BUFFER: return this.m_pixelUnpackBufferBinding; + case gl.TRANSFORM_FEEDBACK_BUFFER: return this.m_transformFeedbackBufferBinding; + case gl.UNIFORM_BUFFER: return this.m_uniformBufferBinding; + default: + throw new Error('Unrecognized target: ' + target); + } + }; + + /** + * @param {number} target + * @param {sglrReferenceContext.DataBuffer} buffer + */ + sglrReferenceContext.ReferenceContext.prototype.bindBuffer = function(target, buffer) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM)) + return; + + this.setBufferBinding(target, buffer); + }; + + /** + * @return {sglrReferenceContext.DataBuffer} + */ + sglrReferenceContext.ReferenceContext.prototype.createBuffer = function() { return new sglrReferenceContext.DataBuffer(); }; + + /** + * @param {number} buffer + */ + sglrReferenceContext.ReferenceContext.prototype.deleteBuffer = function(buffer) {}; + + /** + * @param {number} target + * @param {number|goog.NumberArray} input + * @param {number} usage + */ + sglrReferenceContext.ReferenceContext.prototype.bufferData = function(target, input, usage) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM)) + return; + /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target); + if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION)) + return; + + if (typeof input == 'number') { + if (this.conditionalSetError(input < 0, gl.INVALID_VALUE)) + return; + buffer.setStorage(input); + } else { + buffer.setData(input); + } + }; + + /** + * @param {number} target + * @param {number} offset + * @param {goog.NumberArray} data + */ + sglrReferenceContext.ReferenceContext.prototype.bufferSubData = function(target, offset, data) { + if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(offset < 0, gl.INVALID_VALUE)) + return; + /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target); + if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION)) + return; + + if (this.conditionalSetError(offset + data.byteLength > buffer.getSize(), gl.INVALID_VALUE)) + return; + buffer.setSubData(offset, data); + }; + + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + * @param {number} format + * @param {number} type + * @param {goog.NumberArray} pixels + */ + sglrReferenceContext.ReferenceContext.prototype.readPixels = function(x, y, width, height, format, type, pixels) { + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer(); + + // Map transfer format. + /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type); + + // Clamp input values + /** @type {number} */ var copyX = deMath.clamp(x, 0, src.raw().getHeight()); + /** @type {number} */ var copyY = deMath.clamp(y, 0, src.raw().getDepth()); + /** @type {number} */ var copyWidth = deMath.clamp(width, 0, src.raw().getHeight() - x); + /** @type {number} */ var copyHeight = deMath.clamp(height, 0, src.raw().getDepth() - y); + + /** @type {?ArrayBuffer} */ var data; + /** @type {number} */ var offset; + if (this.m_pixelPackBufferBinding) { + if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE)) + return; + data = this.m_pixelPackBufferBinding.getData(); + offset = pixels.byteOffset; + } else { + if (pixels instanceof ArrayBuffer) { + data = pixels; + offset = 0; + } else { + data = pixels.buffer; + offset = pixels.byteOffset; + } + } + + /** @type {tcuTexture.PixelBufferAccess} */ + var dst = new tcuTexture.PixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + depth: 1, + rowPitch: deMath.deAlign32(width * transferFmt.getPixelSize(), this.m_pixelPackAlignment), + slicePitch: 0, + data: data, + offset: offset}); + + src = src.getSubregion([copyX, copyY, copyWidth, copyHeight]); + src.resolveMultisampleColorBuffer(tcuTextureUtil.getSubregion(dst, 0, 0, 0, copyWidth, copyHeight, 1)); + }; + + /** + * @return {number} + */ + sglrReferenceContext.ReferenceContext.prototype.getType = function() { + return this.m_type; + }; + + /** + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.nullAccess = function() { + return new tcuTexture.PixelBufferAccess({ + width: 0, + height: 0}); + }; + + /** + * @param {sglrReferenceContext.Framebuffer} framebuffer + * @param {sglrReferenceContext.AttachmentPoint} point + * @return {tcuTexture.PixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getFboAttachment = function(framebuffer, point) { + /** @type {sglrReferenceContext.Attachment} */ var attachment = framebuffer.getAttachment(point); + + switch (attachment.type) { + case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE: { + var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object); + /** @type {?sglrReferenceContext.TextureType} */ var type = container.getType(); + var texture = container.texture; + + if (type == sglrReferenceContext.TextureType.TYPE_2D) + return texture.getLevel(attachment.level); + else if (type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP) + return texture.getFace(attachment.level, sglrReferenceContext.texTargetToFace(attachment.texTarget)); + else if (type == sglrReferenceContext.TextureType.TYPE_2D_ARRAY || + type == sglrReferenceContext.TextureType.TYPE_3D || + type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) { + /** @type {tcuTexture.PixelBufferAccess} */ var level = texture.getLevel(attachment.level); + + return new tcuTexture.PixelBufferAccess({ + format: level.getFormat(), + width: level.getWidth(), + height: level.getHeight(), + depth: 1, + rowPitch: level.getRowPitch(), + slicePitch: 0, + data: level.getBuffer(), + offset: level.getSlicePitch() * attachment.layer}); + } else + return sglrReferenceContext.nullAccess(); + } + + case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER: { + var rbo = /** @type {sglrReferenceContext.Renderbuffer} */ (attachment.object); + return rbo.getAccess(); + } + + default: + return sglrReferenceContext.nullAccess(); + } + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getReadColorbuffer = function() { + if (this.m_readFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0)); + else + return this.m_defaultColorbuffer; + }; + + // sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(mode, first, count) { + // this.drawArraysInstanced(mode, first, count, 1); + // }; + + /** + * @param {number} target + * @return {number} + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.checkFramebufferStatus = function(target) { + if (this.conditionalSetError(target != gl.FRAMEBUFFER && + target != gl.DRAW_FRAMEBUFFER && + target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM)) + return 0; + + // Select binding point. + /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding; + + // Default framebuffer is always complete. + if (!framebufferBinding) + return gl.FRAMEBUFFER_COMPLETE; + + /** @type {number} */ var width = -1; + /** @type {number} */ var height = -1; + /** @type {boolean} */ var hasAttachment = false; + /** @type {boolean} */ var attachmentComplete = true; + /** @type {boolean} */ var dimensionsOk = true; + + for (var key in sglrReferenceContext.AttachmentPoint) { + /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.AttachmentPoint[key]; + /** @type {sglrReferenceContext.Attachment} */ var attachment = framebufferBinding.getAttachment(point); + /** @type {number} */ var attachmentWidth = 0; + /** @type {number} */ var attachmentHeight = 0; + /** @type {tcuTexture.TextureFormat} */ var attachmentFormat; + + if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE) { + var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object); + /** @type {tcuTexture.ConstPixelBufferAccess} */ var level; + + if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D) { + DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D); + /** @type {sglrReferenceContext.Texture2D} */ var tex2D = /** @type {sglrReferenceContext.Texture2D} */ (container.texture); + + if (tex2D.hasLevel(attachment.level)) + level = tex2D.getLevel(attachment.level); + // TODO: implement CUBE_MAP, 2D_ARRAY, 3D, CUBE_MAP_ARRAY + } else if (deMath.deInRange32(attachment.texTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X, + sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z)) { + DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP); + + var texCube = /** @type {sglrReferenceContext.TextureCube} */ (container.texture); + var face = sglrReferenceContext.texTargetToFace(attachment.texTarget); + + if (texCube.hasFace(attachment.level, face)) + level = texCube.getFace(attachment.level, face); + } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY) { + DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D_ARRAY); + var tex2DArr = /** @type {sglrReferenceContext.Texture2DArray} */ (container.texture); + + if (tex2DArr.hasLevel(attachment.level)) + level = tex2DArr.getLevel(attachment.level); // \note Slice doesn't matter here. + } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_3D) { + DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_3D); + var tex3D = /** @type {sglrReferenceContext.Texture3D} */ (container.texture); + + if (tex3D.hasLevel(attachment.level)) + level = tex3D.getLevel(attachment.level); // \note Slice doesn't matter here. + // } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY) { + // DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY); + // var texCubeArr = container.texture; + // + // if (texCubeArr.hasLevel(attachment.level)) + // level = texCubeArr.getLevel(attachment.level); // \note Slice doesn't matter here. + } else + throw new Error('sglrReferenceContext.Framebuffer attached to a texture but no valid target specified.'); + + attachmentWidth = level.getWidth(); + attachmentHeight = level.getHeight(); + attachmentFormat = level.getFormat(); + } else if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER) { + var renderbuffer = attachment.object; + + attachmentWidth = renderbuffer.getWidth(); + attachmentHeight = renderbuffer.getHeight(); + attachmentFormat = renderbuffer.getFormat(); + } else + continue; // Skip rest of checks. + + if (!hasAttachment && attachmentWidth > 0 && attachmentHeight > 0) { + width = attachmentWidth; + height = attachmentHeight; + hasAttachment = true; + } else if (attachmentWidth != width || attachmentHeight != height) + dimensionsOk = false; + + // Validate attachment point compatibility. + switch (attachmentFormat.order) { + case tcuTexture.ChannelOrder.R: + case tcuTexture.ChannelOrder.RG: + case tcuTexture.ChannelOrder.RGB: + case tcuTexture.ChannelOrder.RGBA: + case tcuTexture.ChannelOrder.sRGB: + case tcuTexture.ChannelOrder.sRGBA: + if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0) + attachmentComplete = false; + break; + + case tcuTexture.ChannelOrder.D: + if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH) + attachmentComplete = false; + break; + + case tcuTexture.ChannelOrder.S: + if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL) + attachmentComplete = false; + break; + + case tcuTexture.ChannelOrder.DS: + if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH && + point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL) + attachmentComplete = false; + break; + + default: + throw new Error('Unsupported attachment channel order:' + attachmentFormat.order); + } + } + + if (!attachmentComplete) + return gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + else if (!hasAttachment) + return gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + else if (!dimensionsOk) + return gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + else + return gl.FRAMEBUFFER_COMPLETE; + }; + + /** + * @param {number} mode + * @return {boolean} + */ + sglrReferenceContext.ReferenceContext.prototype.predrawErrorChecks = function(mode) { + if (this.conditionalSetError(mode != gl.POINTS && + mode != gl.LINE_STRIP && mode != gl.LINE_LOOP && mode != gl.LINES && + mode != gl.TRIANGLE_STRIP && mode != gl.TRIANGLE_FAN && mode != gl.TRIANGLES, + gl.INVALID_ENUM)) + return false; + + // \todo [jarkko] Uncomment following code when the buffer mapping support is added + //for (size_t ndx = 0; ndx < vao.m_arrays.length; ++ndx) + // if (vao.m_arrays[ndx].enabled && vao.m_arrays[ndx].bufferBinding && vao.m_arrays[ndx].bufferBinding->isMapped) + // RC_ERROR_RET(gl.INVALID_OPERATION, RC_RET_VOID); + + if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_FRAMEBUFFER_OPERATION)) + return false; + + return true; + }; + + /** + * Draws quads from vertex arrays + * @param {number} mode GL primitive type to draw with. + * @param {number} first First vertex to begin drawing with + * @param {number} count How many vertices to draw (not counting vertices before first) + * @param {number} instanceCount + */ + sglrReferenceContext.ReferenceContext.prototype.drawArraysInstanced = function(mode, first, count, instanceCount) { + if (this.conditionalSetError(first < 0 || count < 0 || instanceCount < 0, gl.INVALID_VALUE)) + return; + + if (!this.predrawErrorChecks(mode)) + return; + + // All is ok + this.drawQuads(mode, first, count, instanceCount); + }; + + /** + * @param {number} mode GL primitive type to draw with. + * @param {number} start + * @param {number} end + * @param {number} count How many vertices to draw (not counting vertices before first) + * @param {number} type Data type + * @param {number} offset + */ + sglrReferenceContext.ReferenceContext.prototype.drawRangeElements = function(mode, start, end, count, type, offset) { + if (this.conditionalSetError(end < start, gl.INVALID_VALUE)) + return; + + this.drawElements(mode, count, type, offset); + }; + + /** + * @param {number} mode GL primitive type to draw with. + * @param {number} count How many vertices to draw (not counting vertices before first) + * @param {number} type Data type + * @param {number} offset + */ + sglrReferenceContext.ReferenceContext.prototype.drawElements = function(mode, count, type, offset) { + this.drawElementsInstanced(mode, count, type, offset, 1); + }; + + /** + * @param {number} mode GL primitive type to draw with. + * @param {number} count How many vertices to draw (not counting vertices before first) + * @param {number} type Data type + * @param {number} offset + * @param {number} instanceCount + */ + sglrReferenceContext.ReferenceContext.prototype.drawElementsInstanced = function(mode, count, type, offset, instanceCount) { + this.drawElementsInstancedBaseVertex(mode, count, type, offset, instanceCount, 0); + }; + + /** + * @param {number} mode GL primitive type to draw with. + * @param {number} count How many vertices to draw (not counting vertices before first) + * @param {number} type Data type + * @param {number} offset + * @param {number} instanceCount + * @param {number} baseVertex + */ + sglrReferenceContext.ReferenceContext.prototype.drawElementsInstancedBaseVertex = function(mode, count, type, offset, instanceCount, baseVertex) { + var vao = this.m_vertexArrayBinding; + + if (this.conditionalSetError(type != gl.UNSIGNED_BYTE && + type != gl.UNSIGNED_SHORT && + type != gl.UNSIGNED_INT, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(count < 0 || instanceCount < 0, gl.INVALID_VALUE)) + return; + + if (!this.predrawErrorChecks(mode)) + return; + + if (this.conditionalSetError(count > 0 && !vao.m_elementArrayBufferBinding, gl.INVALID_OPERATION)) + return; + // All is ok + var data = vao.m_elementArrayBufferBinding.getData(); + var indices = new rrRenderer.DrawIndices(data, sglrReferenceUtils.mapGLIndexType(type), offset, baseVertex); + + this.drawQuads(mode, indices, count, instanceCount); + }; + + /** + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access + * @return {Array<number>} + */ + sglrReferenceContext.getBufferRect = function(access) { return [0, 0, access.raw().getHeight(), access.raw().getDepth()]; }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getDrawColorbuffer = function() { + if (this.m_drawFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0)); + return this.m_defaultColorbuffer; + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getDrawDepthbuffer = function() { + if (this.m_drawFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH)); + return this.m_defaultDepthbuffer; + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getDrawStencilbuffer = function() { + if (this.m_drawFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)); + return this.m_defaultStencilbuffer; + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getReadDepthbuffer = function() { + if (this.m_readFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH)); + return this.m_defaultDepthbuffer; + }; + + /** + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ + sglrReferenceContext.ReferenceContext.prototype.getReadStencilbuffer = function() { + if (this.m_readFramebufferBinding) + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)); + return this.m_defaultStencilbuffer; + }; + + /** + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access + * @param {number} s + * @param {number} x + * @param {number} y + * @param {number} depth + */ + sglrReferenceContext.writeDepthOnly = function(access, s, x, y, depth) { access.raw().setPixDepth(depth, s, x, y); }; + + /** + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access + * @param {number} s + * @param {number} x + * @param {number} y + * @param {number} stencil + * @param {number} writeMask + */ + sglrReferenceContext.writeStencilOnly = function(access, s, x, y, stencil, writeMask) { + /** @type {number} */ var oldVal = access.raw().getPixelInt(s, x, y)[3]; + access.raw().setPixStencil((oldVal & ~writeMask) | (stencil & writeMask), s, x, y); + }; + + /** + * @param {number} bits + * @param {number} s + * @return {number} + */ + sglrReferenceContext.maskStencil = function(bits, s) { return s & ((1 << bits) - 1); }; + + /** + * @param {number} buffers + */ + sglrReferenceContext.ReferenceContext.prototype.clear = function(buffers) { + if (this.conditionalSetError((buffers & ~(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0, gl.INVALID_VALUE)) + return; + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer(); + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer(); + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer(); + /** @type {boolean} */ var hasColor0 = /** @type {!boolean} */ (colorBuf0 && !colorBuf0.isEmpty()); + /** @type {boolean} */ var hasDepth = /** @type {!boolean} */ (depthBuf && !depthBuf.isEmpty()); + /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty()); + /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff]; + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access; + /** @type {boolean} */ var isSharedDepthStencil; + + if (hasColor0 && (buffers & gl.COLOR_BUFFER_BIT) != 0) { + /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf0)); + access = colorBuf0.getSubregion(colorArea); + /** @type {boolean} */ var isSRGB = colorBuf0.raw().getFormat().isSRGB(); + /** @type {Array<number>} */ var c = (isSRGB && this.m_sRGBUpdateEnabled) ? tcuTextureUtil.linearToSRGB(this.m_clearColor) : this.m_clearColor; + /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3]; + /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3]; + + if (!maskUsed) + access.clear(c); + else if (!maskZero) { + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + access.raw().setPixel(tcuTextureUtil.select(c, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y); + } + // else all channels masked out + } + + if (hasDepth && (buffers & gl.DEPTH_BUFFER_BIT) != 0 && this.m_depthMask) { + /** @type {Array<number>} */ var depthArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf)); + access = depthBuf.getSubregion(depthArea); + isSharedDepthStencil = depthBuf.raw().getFormat().order != tcuTexture.ChannelOrder.D; + + if (isSharedDepthStencil) { + // Slow path where stencil is masked out in write. + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + sglrReferenceContext.writeDepthOnly(access, s, x, y, this.m_clearDepth); + } else + access.clear([this.m_clearDepth, 0, 0, 0]); + } + + if (hasStencil && (buffers & gl.STENCIL_BUFFER_BIT) != 0) { + /** @type {Array<number>} */ var stencilArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf)); + access = stencilBuf.getSubregion(stencilArea); + /** @type {number} */ var stencilBits = stencilBuf.raw().getFormat().getNumStencilBits(); + /** @type {number} */ var stencil = sglrReferenceContext.maskStencil(stencilBits, this.m_clearStencil); + isSharedDepthStencil = stencilBuf.raw().getFormat().order != tcuTexture.ChannelOrder.S; + + if (isSharedDepthStencil || ((this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask & ((1 << stencilBits) - 1)) != ((1 << stencilBits) - 1))) { + // Slow path where depth or stencil is masked out in write. + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask); + } else + access.clear([0, 0, 0, stencil]); + } + }; + + /** + * @param {number} buffer + * @param {number} drawbuffer + * @param {Array<number>} value + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.clearBufferiv = function(buffer, drawbuffer, value) { + if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.STENCIL, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE)) + return; + + /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff]; + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access; + + if (buffer == gl.COLOR) { + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer(); + /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3]; + /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3]; + + if (!colorBuf.isEmpty() && !maskZero) { + /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf)); + access = colorBuf.getSubregion(colorArea); + + if (!maskUsed) + access.clear(value); + else { + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y); + } + } + } else { + if (buffer !== gl.STENCIL) + throw new Error('Unexpected buffer type: ' + buffer); + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer(); + + if (!stencilBuf.isEmpty() && this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask != 0) { + /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf)); + access = stencilBuf.getSubregion(area); + /** @type {number} */ var stencil = value[0]; + + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask); + } + } + }; + + /** + * @param {number} buffer + * @param {number} drawbuffer + * @param {Array<number>} value + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.clearBufferfv = function(buffer, drawbuffer, value) { + if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.DEPTH, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE)) + return; + + /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff]; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access; + if (buffer == gl.COLOR) { + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer(); + /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3]; + /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3]; + + if (!colorBuf.isEmpty() && !maskZero) { + /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf)); + access = colorBuf.getSubregion(colorArea); + var color = value; + + if (this.m_sRGBUpdateEnabled && access.raw().getFormat().isSRGB()) + color = tcuTextureUtil.linearToSRGB(color); + + if (!maskUsed) + access.clear(color); + else { + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + access.raw().setPixel(tcuTextureUtil.select(color, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y); + } + } + } else { + if (buffer !== gl.DEPTH) + throw new Error('Unexpected buffer type: ' + buffer); + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer(); + + if (!depthBuf.isEmpty() && this.m_depthMask) { + /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf)); + access = depthBuf.getSubregion(area); + /** @type {number} */ var depth = value[0]; + + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + sglrReferenceContext.writeDepthOnly(access, s, x, y, depth); + } + } + }; + + /** + * @param {number} buffer + * @param {number} drawbuffer + * @param {Array<number>} value + */ + sglrReferenceContext.ReferenceContext.prototype.clearBufferuiv = function(buffer, drawbuffer, value) { + if (this.conditionalSetError(buffer != gl.COLOR, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE)) + return; + + /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff]; + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer(); + /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3]; + /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3]; + + if (!colorBuf.isEmpty() && !maskZero) { + /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf)); + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access = colorBuf.getSubregion(colorArea); + + if (!maskUsed) + access.clear(value); + else { + for (var y = 0; y < access.raw().getDepth(); y++) + for (var x = 0; x < access.raw().getHeight(); x++) + for (var s = 0; s < access.getNumSamples(); s++) + access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y); + } + } + }; + + /** + * @param {number} buffer + * @param {number} drawbuffer + * @param {number} depth + * @param {number} stencil + */ + sglrReferenceContext.ReferenceContext.prototype.clearBufferfi = function(buffer, drawbuffer, depth, stencil) { + if (this.conditionalSetError(buffer != gl.DEPTH_STENCIL, gl.INVALID_ENUM)) + return; + this.clearBufferfv(gl.DEPTH, drawbuffer, [depth]); + this.clearBufferiv(gl.STENCIL, drawbuffer, [stencil]); + }; + + /** + * @param {number} target + * @param {number} attachment + * @param {sglrReferenceContext.TexTarget} textarget + * @param {sglrReferenceContext.TextureContainer} texture + * @param {number} level + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.framebufferTexture2D = function(target, attachment, textarget, texture, level) { + if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) { + // Attach to both depth and stencil. + this.framebufferTexture2D(target, gl.DEPTH_ATTACHMENT, textarget, texture, level); + this.framebufferTexture2D(target, gl.STENCIL_ATTACHMENT, textarget, texture, level); + } else { + /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment); + /** @type {sglrReferenceContext.TexTarget} */ var fboTexTarget = sglrReferenceContext.mapGLFboTexTarget(textarget); + + if (this.conditionalSetError(target != gl.FRAMEBUFFER && + target != gl.DRAW_FRAMEBUFFER && + target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM)) + return; + + // Select binding point. + /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding; + if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION)) + return; + + if (texture) { + if (this.conditionalSetError(level != 0, gl.INVALID_VALUE)) + return; + + if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D) { + if (this.conditionalSetError(fboTexTarget != sglrReferenceContext.TexTarget.TEXTARGET_2D, gl.INVALID_OPERATION)) + return; + } else { + if (!texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP) + throw new Error('Unsupported texture type'); + if (this.conditionalSetError(!deMath.deInRange32(fboTexTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z), gl.INVALID_OPERATION)) + return; + } + } + + /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment(); + + if (texture) { + fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE; + fboAttachment.object = texture; + fboAttachment.texTarget = fboTexTarget; + fboAttachment.level = level; + } + framebufferBinding.setAttachment(point, fboAttachment); + } + }; + + /** + * @param {number} target + * @param {number} attachment + * @param {sglrReferenceContext.TextureContainer} texture + * @param {number} level + * @param {number} layer + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.framebufferTextureLayer = function(target, attachment, texture, level, layer) { + if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) { + // Attach to both depth and stencil. + this.framebufferTextureLayer(target, gl.DEPTH_ATTACHMENT, texture, level, layer); + this.framebufferTextureLayer(target, gl.STENCIL_ATTACHMENT, texture, level, layer); + } else { + /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment); + + if (this.conditionalSetError(target != gl.FRAMEBUFFER && + target != gl.DRAW_FRAMEBUFFER && + target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(point === undefined, gl.INVALID_ENUM)) + return; + + // Select binding point. + /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding; + if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION)) + return; + + if (texture) { + if (this.conditionalSetError(level != 0, gl.INVALID_VALUE)) + return; + + if (this.conditionalSetError(texture.getType() != sglrReferenceContext.TextureType.TYPE_2D_ARRAY && + texture.getType() != sglrReferenceContext.TextureType.TYPE_3D && + texture.getType() != sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY, gl.INVALID_OPERATION)) + return; + + if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D_ARRAY || texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) { + if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_ARRAY_TEXTURE_LAYERS), gl.INVALID_VALUE)) + return; + if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_TEXTURE_SIZE))), gl.INVALID_VALUE)) + return; + } else if (texture.getType() == sglrReferenceContext.TextureType.TYPE_3D) { + if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_3D_TEXTURE_SIZE), gl.INVALID_VALUE)) + return; + if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_3D_TEXTURE_SIZE))), gl.INVALID_VALUE)) + return; + } + } + + /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment(); + + if (texture) { + fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE; + fboAttachment.object = texture; + fboAttachment.texTarget = sglrReferenceContext.texLayeredTypeToTarget(texture.getType()); + fboAttachment.level = level; + fboAttachment.layer = layer; + } + framebufferBinding.setAttachment(point, fboAttachment); + + } + }; + + /** + * @param {number} target + * @param {number} attachment + * @param {number} renderbuffertarget + * @param {sglrReferenceContext.Renderbuffer} renderbuffer + */ + sglrReferenceContext.ReferenceContext.prototype.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) { + if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) { + // Attach both to depth and stencil. + this.framebufferRenderbuffer(target, gl.DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer); + this.framebufferRenderbuffer(target, gl.STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer); + } else { + /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment); + + if (this.conditionalSetError(target != gl.FRAMEBUFFER && + target != gl.DRAW_FRAMEBUFFER && + target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM)) + return; + + // Select binding point. + /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding; + if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION)) + return; + + if (renderbuffer) { + if (this.conditionalSetError(renderbuffertarget != gl.RENDERBUFFER, gl.INVALID_ENUM)) + return; + } + + /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment(); + + if (renderbuffer) { + fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER; + fboAttachment.object = renderbuffer; + } + framebufferBinding.setAttachment(point, fboAttachment); + } + }; + + /** + * @param {number} target + * @param {number} internalformat + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.renderbufferStorage = function(target, internalformat, width, height) { + /** @type {tcuTexture.TextureFormat} */ var format = gluTextureUtil.mapGLInternalFormat(internalformat); + + if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError(!this.m_renderbufferBinding, gl.INVALID_OPERATION)) + return; + if (this.conditionalSetError(!deMath.deInRange32(width, 0, this.m_limits.maxRenderbufferSize) || + !deMath.deInRange32(height, 0, this.m_limits.maxRenderbufferSize), + gl.INVALID_OPERATION)) + return; + if (this.conditionalSetError(!format, gl.INVALID_ENUM)) + return; + + this.m_renderbufferBinding.setStorage(format, width, height); + }; + + /** + * @param {number} target + * @param {number} samples + * @param {number} internalformat + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.renderbufferStorageMultisample = function(target, samples, internalformat, width, height) { + this.renderbufferStorage(target, internalformat, width, height); + }; + + /** + * @param {rrRenderer.PrimitiveType} derivedType + * @return {rrRenderer.PrimitiveType} + * @throws {Error} + */ + sglrReferenceContext.getPrimitiveBaseType = function(derivedType) { + switch (derivedType) { + case rrRenderer.PrimitiveType.TRIANGLES: + case rrRenderer.PrimitiveType.TRIANGLE_STRIP: + case rrRenderer.PrimitiveType.TRIANGLE_FAN: + return rrRenderer.PrimitiveType.TRIANGLES; + + case rrRenderer.PrimitiveType.LINES: + case rrRenderer.PrimitiveType.LINE_STRIP: + case rrRenderer.PrimitiveType.LINE_LOOP: + return rrRenderer.PrimitiveType.LINES; + + case rrRenderer.PrimitiveType.POINTS: + return rrRenderer.PrimitiveType.POINTS; + + default: + throw new Error('Unrecognized primitive type:' + derivedType); + } + }; + + /** + * createProgram + * @param {sglrShaderProgram.ShaderProgram} program + * @return {sglrShaderProgram.ShaderProgram} + */ + sglrReferenceContext.ReferenceContext.prototype.createProgram = function(program) { + return program; + }; + + /** + * deleteProgram + * @param {sglrShaderProgram.ShaderProgram} program + */ + sglrReferenceContext.ReferenceContext.prototype.deleteProgram = function(program) {}; + + /** + * @param {sglrShaderProgram.ShaderProgram} program + */ + sglrReferenceContext.ReferenceContext.prototype.useProgram = function(program) { + this.m_currentProgram = program; + }; + + /** + * Draws quads from vertex arrays + * @param {number} primitive GL primitive type to draw with. + * @param {number} first First vertex to begin drawing with + * @param {number} count How many vertices to draw (not counting vertices before first) + */ + sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(primitive, first, count) { + this.drawQuads(primitive, first, count, 1); + }; + + /** + * Draws quads from vertex arrays + * @param {number} primitive GL primitive type to draw with. + * @param {(number|rrRenderer.DrawIndices)} first First vertex to begin drawing with + * @param {number} count Number of vertices + * @param {number=} instances Number of instances + */ + sglrReferenceContext.ReferenceContext.prototype.drawQuads = function(primitive, first, count, instances) { + // undefined results + if (!this.m_currentProgram) + return; + + if (typeof instances === 'undefined') + instances = 1; + + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer(); + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer(); + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer(); + /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty()); + /** @type {number} */ var stencilBits = (hasStencil) ? stencilBuf.raw().getFormat().getNumStencilBits() : 0; + + /** @type {rrRenderer.RenderTarget} */ var renderTarget = new rrRenderer.RenderTarget(colorBuf0, + depthBuf, + stencilBuf); + /** @type {sglrShaderProgram.ShaderProgram} */ var program = this.m_currentProgram; + + /*new rrRenderer.Program( + * this.m_currentProgram.getVertexShader(), + * this.m_currentProgram.getFragmentShader());*/ + + /** @type {rrRenderState.ViewportState} */ var viewportState = new rrRenderState.ViewportState(colorBuf0); + /** @type {rrRenderState.RenderState} */ var state = new rrRenderState.RenderState(viewportState); + + /** @type {Array<rrVertexAttrib.VertexAttrib>} */ var vertexAttribs = []; + + // Gen state + /** @type {rrRenderer.PrimitiveType} */ var baseType = rrRenderer.PrimitiveType.TRIANGLES; + /** @type {boolean} */ var polygonOffsetEnabled = + (baseType == rrRenderer.PrimitiveType.TRIANGLES) ? + (this.m_polygonOffsetFillEnabled) : + (false); + + //state.cullMode = m_cullMode + + state.fragOps.scissorTestEnabled = this.m_scissorEnabled; + state.fragOps.scissorRectangle = new rrRenderState.WindowRectangle(this.m_scissorBox); + + state.fragOps.numStencilBits = stencilBits; + state.fragOps.stencilTestEnabled = this.m_stencilTestEnabled; + + for (var key in rrDefs.FaceType) { + /** @type {number} */ var faceType = rrDefs.FaceType[key]; + state.fragOps.stencilStates[faceType].compMask = this.m_stencil[faceType].opMask; + state.fragOps.stencilStates[faceType].writeMask = this.m_stencil[faceType].writeMask; + state.fragOps.stencilStates[faceType].ref = this.m_stencil[faceType].ref; + state.fragOps.stencilStates[faceType].func = sglrReferenceUtils.mapGLTestFunc(this.m_stencil[faceType].func); + state.fragOps.stencilStates[faceType].sFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opStencilFail); + state.fragOps.stencilStates[faceType].dpFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthFail); + state.fragOps.stencilStates[faceType].dpPass = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthPass); + } + + state.fragOps.depthTestEnabled = this.m_depthTestEnabled; + state.fragOps.depthFunc = sglrReferenceUtils.mapGLTestFunc(this.m_depthFunc); + state.fragOps.depthMask = this.m_depthMask; + + state.fragOps.blendMode = this.m_blendEnabled ? rrRenderState.BlendMode.STANDARD : rrRenderState.BlendMode.NONE; + state.fragOps.blendRGBState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeRGB); + state.fragOps.blendRGBState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcRGB); + state.fragOps.blendRGBState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstRGB); + state.fragOps.blendAState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeAlpha); + state.fragOps.blendAState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcAlpha); + state.fragOps.blendAState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstAlpha); + state.fragOps.blendColor = this.m_blendColor; + + state.fragOps.colorMask = this.m_colorMask; + + state.viewport.rect = new rrRenderState.WindowRectangle(this.m_viewport); + state.viewport.zn = this.m_depthRangeNear; + state.viewport.zf = this.m_depthRangeFar; + + //state.point.pointSize = this.m_pointSize; + state.line.lineWidth = this.m_lineWidth; + + state.fragOps.polygonOffsetEnabled = polygonOffsetEnabled; + state.fragOps.polygonOffsetFactor = this.m_polygonOffsetFactor; + state.fragOps.polygonOffsetUnits = this.m_polygonOffsetUnits; + + state.provokingVertexConvention = (this.m_provokingFirstVertexConvention) ? (rrDefs.ProvokingVertex.PROVOKINGVERTEX_FIRST) : (rrDefs.ProvokingVertex.PROVOKINGVERTEX_LAST); + + // gen attributes + /** @type {sglrReferenceContext.VertexArray} */ var vao = this.m_vertexArrayBinding; + for (var ndx = 0; ndx < vao.m_arrays.length; ++ndx) { + vertexAttribs[ndx] = new rrVertexAttrib.VertexAttrib(); + if (!vao.m_arrays[ndx].enabled) { + vertexAttribs[ndx].type = rrVertexAttrib.VertexAttribType.DONT_CARE; // reading with wrong type is allowed, but results are undefined + vertexAttribs[ndx].generic = this.m_currentAttribs[ndx]; + } else { + vertexAttribs[ndx].type = (vao.m_arrays[ndx].integer) ? + (sglrReferenceUtils.mapGLPureIntegerVertexAttributeType(vao.m_arrays[ndx].type)) : + (sglrReferenceUtils.mapGLFloatVertexAttributeType(vao.m_arrays[ndx].type, vao.m_arrays[ndx].normalized, vao.m_arrays[ndx].size)); + vertexAttribs[ndx].size = sglrReferenceUtils.mapGLSize(vao.m_arrays[ndx].size); + vertexAttribs[ndx].stride = vao.m_arrays[ndx].stride; + vertexAttribs[ndx].instanceDivisor = vao.m_arrays[ndx].divisor; + vertexAttribs[ndx].pointer = vao.m_arrays[ndx].bufferBinding.getData(); + vertexAttribs[ndx].offset = vao.m_arrays[ndx].offset; + vertexAttribs[ndx].componentCount = vao.m_arrays[ndx].size; + } + } + + // Set shader samplers + for (var uniformNdx = 0; uniformNdx < this.m_currentProgram.m_uniforms.length; ++uniformNdx) { + /** @type {number} */ var texNdx = this.m_currentProgram.m_uniforms[uniformNdx].value[0]; + + switch (this.m_currentProgram.m_uniforms[uniformNdx].type) { + case gluShaderUtil.DataType.SAMPLER_2D: + case gluShaderUtil.DataType.UINT_SAMPLER_2D: + case gluShaderUtil.DataType.INT_SAMPLER_2D: { + /** @type {sglrReferenceContext.Texture2D} */ var tex; + + if (texNdx >= 0 && texNdx < this.m_textureUnits.length) + tex = /** @type {sglrReferenceContext.Texture2D} */ (this.m_textureUnits[texNdx].tex2DBinding.texture); + + if (tex && tex.isComplete()) { + tex.updateView(); + this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex; + } else + this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2D.texture; + + break; + } + case gluShaderUtil.DataType.SAMPLER_CUBE: + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: + case gluShaderUtil.DataType.INT_SAMPLER_CUBE: { + /** @type {sglrReferenceContext.TextureCube} */ var texCube; + + if (texNdx >= 0 && texNdx < this.m_textureUnits.length) + texCube = /** @type {sglrReferenceContext.TextureCube} */ (this.m_textureUnits[texNdx].texCubeBinding.texture); + + if (texCube && texCube.isComplete()) { + texCube.updateView(); + this.m_currentProgram.m_uniforms[uniformNdx].sampler = texCube; + } else + this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTexCube.texture; + + break; + } + case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: + case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: + case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: { + /** @type {sglrReferenceContext.Texture2DArray} */ var tex2DArray; + + if (texNdx >= 0 && texNdx < this.m_textureUnits.length) + tex2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (this.m_textureUnits[texNdx].tex2DArrayBinding.texture); + + if (tex2DArray && tex2DArray.isComplete()) { + tex2DArray.updateView(); + this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex2DArray; + } else + this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2DArray.texture; + + break; + } + case gluShaderUtil.DataType.SAMPLER_3D: + case gluShaderUtil.DataType.UINT_SAMPLER_3D: + case gluShaderUtil.DataType.INT_SAMPLER_3D: { + /** @type {sglrReferenceContext.Texture3D} */ var tex3D; + + if (texNdx >= 0 && texNdx < this.m_textureUnits.length) + tex3D = /** @type {sglrReferenceContext.Texture3D} */ (this.m_textureUnits[texNdx].tex3DBinding.texture); + + if (tex3D && tex3D.isComplete()) { + tex3D.updateView(); + this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex3D; + } else + this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex3D.texture; + + break; + } + /* TODO: Port + case gluShaderUtil.DataType.SAMPLER_CUBE_ARRAY: + case gluShaderUtil.DataType.UINT_SAMPLER_CUBE_ARRAY: + case gluShaderUtil.DataType.INT_SAMPLER_CUBE_ARRAY:{ + rc::TextureCubeArray* tex = DE_NULL; + + if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.length) + tex = (this.m_textureUnits[texNdx].texCubeArrayBinding) ? (this.m_textureUnits[texNdx].texCubeArrayBinding) : (&this.m_textureUnits[texNdx].defaultCubeArrayTex); + + if (tex && tex.isComplete()) { + tex.updateView(); + this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = tex; + } else + this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = &this.m_emptyTexCubeArray; + + break; + } + */ + default: + // nothing + break; + } + } + + var primitiveType = sglrReferenceUtils.mapGLPrimitiveType(primitive); + + var renderFunction = rrRenderer.drawTriangles; + if (primitiveType == rrRenderer.PrimitiveType.LINES || + primitiveType == rrRenderer.PrimitiveType.LINE_STRIP || + primitiveType == rrRenderer.PrimitiveType.LINE_LOOP) + renderFunction = rrRenderer.drawLines; + else if (primitiveType == rrRenderer.PrimitiveType.POINTS) + renderFunction = rrRenderer.drawPoints; + + for (var instanceID = 0; instanceID < instances; instanceID++) + renderFunction(state, renderTarget, program, vertexAttribs, primitiveType, first, count, instanceID); + }; + + /** + * @param {Array<number>} rect + * @return {boolean} + */ + sglrReferenceContext.isEmpty = function(rect) { return rect[2] == 0 || rect[3] == 0; }; + + /** + * @param {number} mask + * @param {Array<number>} srcRect + * @param {Array<number>} dstRect + * @param {boolean} flipX + * @param {boolean} flipY + * @throws {Error} + */ + sglrReferenceContext.ReferenceContext.prototype.blitResolveMultisampleFramebuffer = function(mask, srcRect, dstRect, flipX, flipY) { + throw new Error('Unimplemented'); + }; + + /** + * @param {number} srcX0 + * @param {number} srcY0 + * @param {number} srcX1 + * @param {number} srcY1 + * @param {number} dstX0 + * @param {number} dstY0 + * @param {number} dstX1 + * @param {number} dstY1 + * @param {number} mask + * @param {number} filter + */ + sglrReferenceContext.ReferenceContext.prototype.blitFramebuffer = function(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) { + // p0 in inclusive, p1 exclusive. + // Negative width/height means swap. + /** @type {boolean} */ var swapSrcX = srcX1 < srcX0; + /** @type {boolean} */ var swapSrcY = srcY1 < srcY0; + /** @type {boolean} */ var swapDstX = dstX1 < dstX0; + /** @type {boolean} */ var swapDstY = dstY1 < dstY0; + /** @type {number} */ var srcW = Math.abs(srcX1 - srcX0); + /** @type {number} */ var srcH = Math.abs(srcY1 - srcY0); + /** @type {number} */ var dstW = Math.abs(dstX1 - dstX0); + /** @type {number} */ var dstH = Math.abs(dstY1 - dstY0); + /** @type {boolean} */ var scale = srcW != dstW || srcH != dstH; + /** @type {number} */ var srcOriginX = swapSrcX ? srcX1 : srcX0; + /** @type {number} */ var srcOriginY = swapSrcY ? srcY1 : srcY0; + /** @type {number} */ var dstOriginX = swapDstX ? dstX1 : dstX0; + /** @type {number} */ var dstOriginY = swapDstY ? dstY1 : dstY0; + /** @type {Array<number>} */ var srcRect = [srcOriginX, srcOriginY, srcW, srcH]; + /** @type {Array<number>} */ var dstRect = [dstOriginX, dstOriginY, dstW, dstH]; + + if (this.conditionalSetError(filter != gl.NEAREST && filter != gl.LINEAR, gl.INVALID_ENUM)) + return; + if (this.conditionalSetError((mask & (gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0 && filter != gl.NEAREST, gl.INVALID_OPERATION)) + return; + + // Validate that both targets are complete. + if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE || + this.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_OPERATION)) + return; + + // Check samples count is valid + if (this.conditionalSetError(this.getDrawColorbuffer().getNumSamples() != 1, gl.INVALID_OPERATION)) + return; + + // Check size restrictions of multisampled case + if (this.getReadColorbuffer().getNumSamples() != 1) { + // Src and Dst rect dimensions must be the same + if (this.conditionalSetError(srcW != dstW || srcH != dstH, gl.INVALID_OPERATION)) + return; + + // sglrReferenceContext.Framebuffer formats must match + if (mask & gl.COLOR_BUFFER_BIT) + if (this.conditionalSetError(this.getReadColorbuffer().raw().getFormat() != this.getDrawColorbuffer().raw().getFormat(), gl.INVALID_OPERATION)) + return; + if (mask & gl.DEPTH_BUFFER_BIT) + if (this.conditionalSetError(this.getReadDepthbuffer().raw().getFormat() != this.getDrawDepthbuffer().raw().getFormat(), gl.INVALID_OPERATION)) + return; + if (mask & gl.STENCIL_BUFFER_BIT) + if (this.conditionalSetError(this.getReadStencilbuffer().raw().getFormat() != this.getDrawStencilbuffer().raw().getFormat(), gl.INVALID_OPERATION)) + return; + } + + // Compute actual source rect. + srcRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadColorbuffer())) : srcRect; + srcRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadDepthbuffer())) : srcRect; + srcRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadStencilbuffer())) : srcRect; + + // Compute destination rect. + dstRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawColorbuffer())) : dstRect; + dstRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawDepthbuffer())) : dstRect; + dstRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawStencilbuffer())) : dstRect; + dstRect = this.m_scissorEnabled ? deMath.intersect(dstRect, this.m_scissorBox) : dstRect; + + if (sglrReferenceContext.isEmpty(srcRect) || sglrReferenceContext.isEmpty(dstRect)) + return; // Don't attempt copy. + + // Multisampled read buffer is a special case + if (this.getReadColorbuffer().getNumSamples() != 1) { + /** @type {boolean} */ var swapX = swapSrcX ^ swapDstX ? true : false; + /** @type {boolean} */ var swapY = swapSrcY ^ swapDstY ? true : false; + var error = this.blitResolveMultisampleFramebuffer(mask, srcRect, dstRect, swapX, swapY); + + if (error != gl.NO_ERROR) + this.setError(error); + + return; + } + + // \note Multisample pixel buffers can now be accessed like non-multisampled because multisample read buffer case is already handled. => sample count must be 1 + + // Coordinate transformation: + // Dst offset space -> dst rectangle space -> src rectangle space -> src offset space. + /** @type {tcuMatrix.Matrix} */ var matrix = tcuMatrixUtil.translationMatrix([srcX0 - srcRect[0], srcY0 - srcRect[1]]); + matrix = tcuMatrix.multiply(matrix, tcuMatrix.matrixFromVector(3, 3, [(srcX1 - srcX0) / (dstX1 - dstX0), (srcY1 - srcY0) / (dstY1 - dstY0), 1])); + matrix = tcuMatrix.multiply(matrix, tcuMatrixUtil.translationMatrix([dstRect[0] - dstX0, dstRect[1] - dstY0])); + + /** + * @param {number} x + * @param {number} y + * @return {number} + */ + var transform = function(x, y) { return matrix.get(x, y); }; + + /** @type {number} */ var dX; + /** @type {number} */ var dY; + /** @type {number} */ var sX; + /** @type {number} */ var sY; + /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src; + /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var dst; + + if (mask & gl.COLOR_BUFFER_BIT) { + src = tcuTextureUtil.getSubregion(this.getReadColorbuffer().toSinglesampleAccess(), srcRect[0], srcRect[1], 0, srcRect[2], srcRect[3], 1); + dst = tcuTextureUtil.getSubregion(this.getDrawColorbuffer().toSinglesampleAccess(), dstRect[0], dstRect[1], 0, dstRect[2], dstRect[3], 1); + /** @type {tcuTexture.TextureChannelClass} */ var dstClass = tcuTexture.getTextureChannelClass(dst.getFormat().type); + /** @type {boolean} */ var dstIsFloat = dstClass == tcuTexture.TextureChannelClass.FLOATING_POINT || + dstClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT || + dstClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT; + /** @type {tcuTexture.FilterMode} */ var sFilter = (scale && filter == gl.LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; + /** @type {tcuTexture.Sampler} */ var sampler = new tcuTexture.Sampler(tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE, + sFilter, sFilter, 0.0 /* lod threshold */, false /* non-normalized coords */); + /** @type {boolean} */ var srcIsSRGB = src.getFormat().order == tcuTexture.ChannelOrder.sRGB || src.getFormat().order == tcuTexture.ChannelOrder.sRGBA; + /** @type {boolean} */ var dstIsSRGB = dst.getFormat().order == tcuTexture.ChannelOrder.sRGB || dst.getFormat().order == tcuTexture.ChannelOrder.sRGBA; + /** @type {boolean} */ var convertSRGB = this.m_sRGBUpdateEnabled; + + // \note We don't check for unsupported conversions, unlike spec requires. + + for (var yo = 0; yo < dstRect[3]; yo++) { + for (var xo = 0; xo < dstRect[2]; xo++) { + dX = xo + 0.5; + dY = yo + 0.5; + + // \note Only affine part is used. + sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2); + sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2); + + // do not copy pixels outside the modified source region (modified by buffer intersection) + if (sX < 0.0 || sX >= srcRect[2] || + sY < 0.0 || sY >= srcRect[3]) + continue; + + if (dstIsFloat || srcIsSRGB || filter == tcuTexture.FilterMode.LINEAR) { + /** @type {Array<number>} */ var p = src.sample2D(sampler, sampler.minFilter, sX, sY, 0); + dst.setPixel((dstIsSRGB && convertSRGB) ? tcuTextureUtil.linearToSRGB(p) : p, xo, yo); + } else + dst.setPixelInt(src.getPixelInt(Math.floor(sX), Math.floor(sY)), xo, yo); + } + } + } + + if ((mask & gl.DEPTH_BUFFER_BIT) && this.m_depthMask) { + src = this.getReadDepthbuffer().getSubregion(srcRect); + dst = this.getDrawDepthbuffer().getSubregion(dstRect); + + for (var yo = 0; yo < dstRect[3]; yo++) { + for (var xo = 0; xo < dstRect[2]; xo++) { + var sampleNdx = 0; // multisample read buffer case is already handled + + dX = xo + 0.5; + dY = yo + 0.5; + sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2); + sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2); + + sglrReferenceContext.writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixel(sampleNdx, Math.floor(sX), Math.floor(sY))[0]); + } + } + } + + if (mask & gl.STENCIL_BUFFER_BIT) { + src = this.getReadStencilbuffer().getSubregion(srcRect); + dst = this.getDrawStencilbuffer().getSubregion(dstRect); + + for (var yo = 0; yo < dstRect[3]; yo++) { + for (var xo = 0; xo < dstRect[2]; xo++) { + var sampleNdx = 0; // multisample read buffer case is already handled + + dX = xo + 0.5; + dY = yo + 0.5; + sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2); + sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2); + + sglrReferenceContext.writeStencilOnly(dst, sampleNdx, xo, yo, src.raw().getPixelInt(sampleNdx, Math.floor(sX), Math.floor(sY))[3], this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask); + } + } + } + }; + + /** + * @param {number} internalFormat + * @return {tcuTexture.TextureFormat} + */ + sglrReferenceContext.mapInternalFormat = function(internalFormat) { + switch (internalFormat) { + case gl.ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.A, tcuTexture.ChannelType.UNORM_INT8); + case gl.LUMINANCE: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.L, tcuTexture.ChannelType.UNORM_INT8); + case gl.LUMINANCE_ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.LA, tcuTexture.ChannelType.UNORM_INT8); + case gl.RGB: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8); + case gl.RGBA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8); + + default: + return gluTextureUtil.mapGLInternalFormat(internalFormat); + } + }; + + /** + * @param {tcuTexture.PixelBufferAccess} dst + * @param {tcuTexture.ConstPixelBufferAccess} src + */ + sglrReferenceContext.depthValueFloatClampCopy = function(dst, src) { + /** @type {number} */ var width = dst.getWidth(); + /** @type {number} */ var height = dst.getHeight(); + /** @type {number} */ var depth = dst.getDepth(); + + DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth); + + // clamping copy + for (var z = 0; z < depth; z++) + for (var y = 0; y < height; y++) + for (var x = 0; x < width; x++) { + /** @type {Array<number>} */ var data = src.getPixel(x, y, z); + dst.setPixel([deMath.clamp(data[0], 0.0, 1.0), data[1], data[2], data[3]], x, y, z); + } + }; + + /** + * @param {number} target + * @param {number} level + * @param {number} internalFormat + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.texImage2DDelegate = function (target, level, internalFormat, width, height) { + var format; + var dataType; + + switch (internalFormat) + { + case gl.ALPHA: + case gl.LUMINANCE: + case gl.LUMINANCE_ALPHA: + case gl.RGB: + case gl.RGBA: + format = internalFormat; + dataType = GL.UNSIGNED_BYTE; + break; + default: + { + var transferFmt = gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(internalFormat)); + format = transferFmt.format; + dataType = transferFmt.dataType; + break; + } + } + this.texImage2D(target, level, internalFormat, width, height, 0, format, dataType, null); + }; + + /** + * @param {number} target + * @param {number} level + * @param {number} internalFormat + * @param {number} width + * @param {number} height + * @param {number} border + * @param {number} format + * @param {number} type + * @param {number} pixels + */ + sglrReferenceContext.ReferenceContext.prototype.texImage2D = function(target, level, internalFormat, width, height, border, format, type, pixels) { + this.texImage3D(target, level, internalFormat, width, height, 1, border, format, type, pixels); + }; + + sglrReferenceContext.ReferenceContext.prototype.texImage3D = function(target, level, internalFormat, width, height, depth, border, format, type, pixels) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + /** @type {ArrayBuffer} */ var data = null; + /** @type {number} */ var offset = 0; + /** @type {tcuTexture.PixelBufferAccess} */ var dst; + /** @type {tcuTexture.ConstPixelBufferAccess} */ var src; + if (this.m_pixelUnpackBufferBinding) { + if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE)) + return; + data = this.m_pixelUnpackBufferBinding.getData(); + offset = pixels; + } else if (pixels) { + if (pixels instanceof ArrayBuffer) { + data = pixels; + offset = 0; + } else { + data = pixels.buffer; + offset = pixels.byteOffset; + } + } + /** @type {boolean} */ var isDstFloatDepthFormat = (internalFormat == gl.DEPTH_COMPONENT32F || internalFormat == gl.DEPTH32F_STENCIL8); // depth components are limited to [0,1] range + + if (this.conditionalSetError(border != 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE)) + return; + + // Map storage format. + /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat); + if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM)) + return; + + // Map transfer format. + /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type); + if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM)) + return; + + if (target == gl.TEXTURE_2D) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2D} */ + var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture); + + if (texture.isImmutable()) { + if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION)) + return; + + //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level)); + dst = texture.getLevel(level); + + if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) || + width != dst.getWidth() || + height != dst.getHeight(), gl.INVALID_OPERATION)) + return; + } else + texture.allocLevel(level, storageFmt, width, height); + + if (data) { + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + rowPitch: rowPitch, + data: data, + offset: offset + skip}); + + //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level)); + dst = texture.getLevel(level); + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(dst, src); + else + tcuTextureUtil.copy(dst, src); + } else { + // No data supplied, clear to black. + + //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level)); + dst = texture.getLevel(level); + dst.clear([0.0, 0.0, 0.0, 1.0]); + } + } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_X || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) { + // Validate size and level. + if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize || depth != 1, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE)) + return; + + var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture); + + var face = sglrReferenceContext.mapGLCubeFace(target); + + if (textureCube.isImmutable()) { + if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION)) + return; + + dst = textureCube.getFace(level, face); + + if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) || + width != dst.getWidth() || + height != dst.getHeight(), gl.INVALID_OPERATION)) + return; + } else + textureCube.allocLevel(level, face, storageFmt, width, height); + + if (data) { + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + rowPitch: rowPitch, + data: data, + offset: offset + skip}); + + dst = textureCube.getFace(level, face); + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(dst, src); + else + tcuTextureUtil.copy(dst, src); + } else { + // No data supplied, clear to black. + dst = textureCube.getFace(level, face); + dst.clear([0.0, 0.0, 0.0, 1.0]); + } + } else if (target == gl.TEXTURE_2D_ARRAY) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || + height > this.m_limits.maxTexture2DSize || + depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2DArray} */ + var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture); + + if (texture2DArray.isImmutable()) { + if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION)) + return; + + dst = texture2DArray.getLevel(level); + if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) || + width != dst.getWidth() || + height != dst.getHeight() || + depth != dst.getDepth(), gl.INVALID_OPERATION)) + return; + } else + texture2DArray.allocLevel(level, storageFmt, width, height, depth); + + if (data) { + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var slicePitch = imageHeight * rowPitch; + var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch + + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + depth: depth, + rowPitch: rowPitch, + slicePitch: slicePitch, + data: data, + offset: offset + skip}); + + dst = texture2DArray.getLevel(level); + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(dst, src); + else + tcuTextureUtil.copy(dst, src); + } else { + // No data supplied, clear to black. + dst = texture2DArray.getLevel(level); + dst.clear([0.0, 0.0, 0.0, 1.0]); + } + } else if (target == gl.TEXTURE_3D) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize || + height > this.m_limits.maxTexture3DSize || + depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE)) + return; + + var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture); + + if (texture3D.isImmutable()) { + if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION)) + return; + + dst = texture3D.getLevel(level); + if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) || + width != dst.getWidth() || + height != dst.getHeight() || + depth != dst.getDepth(), gl.INVALID_OPERATION)) + return; + } else + texture3D.allocLevel(level, storageFmt, width, height, depth); + + if (data) { + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var slicePitch = imageHeight * rowPitch; + var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch + + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + depth: depth, + rowPitch: rowPitch, + slicePitch: slicePitch, + data: data, + offset: offset + skip}); + + dst = texture3D.getLevel(level); + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(dst, src); + else + tcuTextureUtil.copy(dst, src); + + } else { + // No data supplied, clear to black. + dst = texture3D.getLevel(level); + dst.clear([0.0, 0.0, 0.0, 1.0]); + } + } + // else if (target == gl.TEXTURE_CUBE_MAP_ARRAY) + // { + // // Validate size and level. + // RC_IF_ERROR(width != height || + // width > m_limits.maxTexture2DSize || + // depth % 6 != 0 || + // depth > m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE, RC_RET_VOID); + // RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), gl.INVALID_VALUE, RC_RET_VOID); + + // TextureCubeArray* texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex; + + // if (texture->isImmutable()) + // { + // RC_IF_ERROR(!texture->hasLevel(level), gl.INVALID_OPERATION, RC_RET_VOID); + + // ConstPixelBufferAccess dst(texture->getLevel(level)); + // RC_IF_ERROR(storageFmt != dst.getFormat() || + // width != dst.getWidth() || + // height != dst.getHeight() || + // depth != dst.getDepth(), gl.INVALID_OPERATION, RC_RET_VOID); + // } + // else + // texture->allocLevel(level, storageFmt, width, height, depth); + + // if (unpackPtr) + // { + // ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr); + // PixelBufferAccess dst (texture->getLevel(level)); + + // if (isDstFloatDepthFormat) + // sglrReferenceContext.depthValueFloatClampCopy(dst, src); + // else + // tcu::copy(dst, src); + // } + // else + // { + // // No data supplied, clear to black. + // PixelBufferAccess dst = texture->getLevel(level); + // tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f)); + // } + // } /**/ + else + this.setError(gl.INVALID_ENUM); + }; + + sglrReferenceContext.ReferenceContext.prototype.texSubImage2D = function(target, level, xoffset, yoffset, width, height, format, type, pixels) { + this.texSubImage3D(target, level, xoffset, yoffset, 0, width, height, 1, format, type, pixels); + }; + + sglrReferenceContext.ReferenceContext.prototype.texSubImage3D = function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + /** @type {ArrayBuffer} */ var data = null; + /** @type {number} */ var offset = 0; + /** @type {tcuTexture.PixelBufferAccess} */ var dst; + /** @type {tcuTexture.PixelBufferAccess} */ var sub; + /** @type {tcuTexture.ConstPixelBufferAccess} */ var src; + /** @type {boolean} */ var isDstFloatDepthFormat; + if (this.m_pixelUnpackBufferBinding) { + if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE)) + return; + data = this.m_pixelUnpackBufferBinding.getData(); + offset = pixels; + } else if (pixels) { + if (pixels instanceof ArrayBuffer) { + data = pixels; + offset = 0; + } else { + data = pixels.buffer; + offset = pixels.byteOffset; + } + } + + if (this.conditionalSetError(xoffset < 0 || yoffset < 0 || zoffset < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE)) + return; + + // Map transfer format. + /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type); + if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM)) + return; + + if (target == gl.TEXTURE_2D) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2D} */ + var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture); + + if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION)) + return; + + //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level)); + dst = texture.getLevel(level); + + if (this.conditionalSetError(xoffset + width > dst.getWidth() || + yoffset + height > dst.getHeight() || + zoffset + depth > dst.getDepth(), + gl.INVALID_VALUE)) + return; + + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + rowPitch: rowPitch, + data: data, + offset: offset + skip}); + + sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth); + isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(sub, src); + else + tcuTextureUtil.copy(sub, src); + } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_X || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) { + var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture); + + var face = sglrReferenceContext.mapGLCubeFace(target); + + if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION)) + return; + + dst = textureCube.getFace(level, face); + + if (this.conditionalSetError(xoffset + width > dst.getWidth() || + yoffset + height > dst.getHeight() || + zoffset + depth > dst.getDepth(), + gl.INVALID_VALUE)) + return; + + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + rowPitch: rowPitch, + slicePitach: slicePitch, + data: data, + offset: offset + skip}); + + sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth); + isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(sub, src); + else + tcuTextureUtil.copy(sub, src); + } else if (target == gl.TEXTURE_2D_ARRAY) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || + height > this.m_limits.maxTexture2DSize || + depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2DArray} */ + var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture); + + if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION)) + return; + + dst = texture2DArray.getLevel(level); + if (this.conditionalSetError(xoffset + width > dst.getWidth() || + yoffset + height > dst.getHeight() || + zoffset + depth > dst.getDepth(), + gl.INVALID_VALUE)) + return; + + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var slicePitch = imageHeight * rowPitch; + var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch + + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + depth: depth, + rowPitch: rowPitch, + slicePitch: slicePitch, + data: data, + offset: offset + skip}); + + sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth); + isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range + + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(sub, src); + else + tcuTextureUtil.copy(sub, src); + } else if (target == gl.TEXTURE_3D) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize || + height > this.m_limits.maxTexture3DSize || + depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE)) + return; + + var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture); + + if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION)) + return; + + dst = texture3D.getLevel(level); + if (this.conditionalSetError(xoffset + width > dst.getWidth() || + yoffset + height > dst.getHeight() || + zoffset + depth > dst.getDepth(), + gl.INVALID_VALUE)) + return; + + var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width; + var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height; + var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment); + var slicePitch = imageHeight * rowPitch; + var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch + + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize(); + src = new tcuTexture.ConstPixelBufferAccess({ + format: transferFmt, + width: width, + height: height, + depth: depth, + rowPitch: rowPitch, + slicePitch: slicePitch, + data: data, + offset: offset + skip}); + + sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth); + + isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range + if (isDstFloatDepthFormat) + sglrReferenceContext.depthValueFloatClampCopy(sub, src); + else + tcuTextureUtil.copy(sub, src); + } else + this.setError(gl.INVALID_ENUM); + }; + + /** + * @param {number} target + * @param {number} level + * @param {number} internalFormat + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + * @param {number} border + */ + sglrReferenceContext.ReferenceContext.prototype.copyTexImage2D = function(target, level, internalFormat, x, y, width, height, border) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer(); + + if (this.conditionalSetError(border != 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION)) + return; + + // Map storage format. + /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat); + if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM)) + return; + + if (target == gl.TEXTURE_2D) { + // Validate size and level. + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2D} */ + var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture); + + if (texture.isImmutable()) { + if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION)) + return; + + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level); + if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION)) + return; + } else { + texture.allocLevel(level, storageFmt, width, height); + } + + // Copy from current framebuffer. + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level); + for (var yo = 0; yo < height; yo++) { + for (var xo = 0; xo < width; xo++) { + if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth())) + continue; // Undefined pixel. + + dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo); + } + } + } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_X || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) { + // Validate size and level. + if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.TextureCube} */ + var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture); + var face = sglrReferenceContext.mapGLCubeFace(target); + + if (texture.isImmutable()) { + if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_OPERATION)) + return; + + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face); + if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION)) + return; + } else { + texture.allocLevel(level, face, storageFmt, width, height); + } + + // Copy from current framebuffer. + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face); + for (var yo = 0; yo < height; yo++) { + for (var xo = 0; xo < width; xo++) { + if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth())) + continue; // Undefined pixel. + + dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo); + } + } + } else { + this.setError(gl.INVALID_ENUM); + } + } + + /** + * @param {number} target + * @param {number} level + * @param {number} xoffset + * @param {number} yoffset + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ + sglrReferenceContext.ReferenceContext.prototype.copyTexSubImage2D = function(target, level, xoffset, yoffset, x, y, width, height) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer(); + + if (this.conditionalSetError(xoffset < 0 || yoffset < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION)) + return; + + if (target == gl.TEXTURE_2D) { + /** @type {sglrReferenceContext.Texture2D} */ + var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture); + + if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_VALUE)) + return; + + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level); + + if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE)) + return; + + for (var yo = 0; yo < height; yo++) { + for (var xo = 0; xo < width; xo++) { + if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth())) + continue; + + dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset); + } + } + } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_X || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y || + target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z || + target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) { + /** @type {sglrReferenceContext.TextureCube} */ + var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture); + var face = sglrReferenceContext.mapGLCubeFace(target); + + if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_VALUE)) + return; + + /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face); + + if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE)) + return; + + for (var yo = 0; yo < height; yo++) { + for (var xo = 0; xo < width; xo++) { + if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth())) + continue; + + dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset); + } + } + } else { + this.setError(gl.INVALID_ENUM); + } + } + + sglrReferenceContext.ReferenceContext.prototype.texStorage3D = function(target, levels, internalFormat, width, height, depth) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + + if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE)) + return; + + // Map storage format. + /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat); + if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM)) + return; + + if (target == gl.TEXTURE_2D_ARRAY) { + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || + height > this.m_limits.maxTexture2DSize || + depth >= this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2DArray} */ + var textureArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture); + if (this.conditionalSetError(textureArray.isImmutable(), gl.INVALID_OPERATION)) + return; + + textureArray.clearLevels(); + textureArray.setImmutable(); + + for (var level = 0; level < levels; level++) { + var levelW = Math.max(1, width >> level); + var levelH = Math.max(1, height >> level); + + textureArray.allocLevel(level, storageFmt, levelW, levelH, depth); + } + } else if (target == gl.TEXTURE_3D) { + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || + height > this.m_limits.maxTexture2DSize || + depth >= this.m_limits.maxTexture3DSize, gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture3D} */ + var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture); + if (this.conditionalSetError(texture3D.isImmutable(), gl.INVALID_OPERATION)) + return; + + texture3D.clearLevels(); + texture3D.setImmutable(); + + for (var level = 0; level < levels; level++) { + var levelW = Math.max(1, width >> level); + var levelH = Math.max(1, height >> level); + var levelD = Math.max(1, depth >> level); + + texture3D.allocLevel(level, storageFmt, levelW, levelH, levelD); + } + } else + this.setError(gl.INVALID_ENUM); + }; + + sglrReferenceContext.ReferenceContext.prototype.texStorage2D = function(target, levels, internalFormat, width, height) { + /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture]; + + if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE)) + return; + if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE)) + return; + + // Map storage format. + /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat); + if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM)) + return; + + if (target == gl.TEXTURE_2D) { + if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE)) + return; + + /** @type {sglrReferenceContext.Texture2D} */ + var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture); + if (this.conditionalSetError(texture.isImmutable(), gl.INVALID_OPERATION)) + return; + + texture.clearLevels(); + texture.setImmutable(); + + for (var level = 0; level < levels; level++) { + var levelW = Math.max(1, width >> level); + var levelH = Math.max(1, height >> level); + + texture.allocLevel(level, storageFmt, levelW, levelH); + } + } else if (target == gl.TEXTURE_CUBE_MAP) { + if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE)) + return; + var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture); + if (this.conditionalSetError(textureCube.isImmutable(), gl.INVALID_OPERATION)) + return; + + textureCube.clearLevels(); + textureCube.setImmutable(); + + for (var level = 0; level < levels; level++) { + var levelW = Math.max(1, width >> level); + var levelH = Math.max(1, height >> level); + + for (var face in tcuTexture.CubeFace) + textureCube.allocLevel(level, tcuTexture.CubeFace[face], storageFmt, levelW, levelH); + } + } else + this.setError(gl.INVALID_ENUM); + }; + + /** + * @param {number} value + * @return {?tcuTexture.WrapMode} + */ + sglrReferenceContext.mapGLWrapMode = function(value) { + switch (value) { + case gl.CLAMP_TO_EDGE: return tcuTexture.WrapMode.CLAMP_TO_EDGE; + case gl.REPEAT: return tcuTexture.WrapMode.REPEAT_GL; + case gl.MIRRORED_REPEAT: return tcuTexture.WrapMode.MIRRORED_REPEAT_GL; + } + return null; + }; + + /** + * @param {number} value + * @return {?tcuTexture.FilterMode} + */ + sglrReferenceContext.mapGLFilterMode = function(value) { + switch (value) { + case gl.NEAREST: return tcuTexture.FilterMode.NEAREST; + case gl.LINEAR: return tcuTexture.FilterMode.LINEAR; + case gl.NEAREST_MIPMAP_NEAREST: return tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST; + case gl.NEAREST_MIPMAP_LINEAR: return tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR; + case gl.LINEAR_MIPMAP_NEAREST: return tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST; + case gl.LINEAR_MIPMAP_LINEAR: return tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR; + } + return null; + }; + + /** + * @param {number} target + * @param {number} pname + * @param {number} value + */ + sglrReferenceContext.ReferenceContext.prototype.texParameteri = function(target, pname, value) { + /** @type {sglrReferenceContext.TextureUnit} */ var unit = this.m_textureUnits[this.m_activeTexture]; + /** @type {sglrReferenceContext.TextureContainer} */ var container = null; + + switch (target) { + case gl.TEXTURE_2D: container = unit.tex2DBinding; break; + case gl.TEXTURE_CUBE_MAP: container = unit.texCubeBinding; break; + case gl.TEXTURE_2D_ARRAY: container = unit.tex2DArrayBinding; break; + case gl.TEXTURE_3D: container = unit.tex3DBinding; break; + + default: this.setError(gl.INVALID_ENUM); + } + + if (!container) + return; + + /** @type {sglrReferenceContext.Texture} */ + var texture = container.texture; + + switch (pname) { + case gl.TEXTURE_WRAP_S: { + /** @type {?tcuTexture.WrapMode} */ var wrapS = sglrReferenceContext.mapGLWrapMode(value); + if (this.conditionalSetError(null == wrapS, gl.INVALID_VALUE)) + return; + texture.getSampler().wrapS = /** @type {tcuTexture.WrapMode} */ (wrapS); + break; + } + + case gl.TEXTURE_WRAP_T: { + /** @type {?tcuTexture.WrapMode} */ var wrapT = sglrReferenceContext.mapGLWrapMode(value); + if (this.conditionalSetError(null == wrapT, gl.INVALID_VALUE)) + return; + texture.getSampler().wrapT = /** @type {tcuTexture.WrapMode} */ (wrapT); + break; + } + + case gl.TEXTURE_WRAP_R: { + /** @type {?tcuTexture.WrapMode} */ var wrapR = sglrReferenceContext.mapGLWrapMode(value); + if (this.conditionalSetError(null == wrapR, gl.INVALID_VALUE)) + return; + texture.getSampler().wrapR = /** @type {tcuTexture.WrapMode} */ (wrapR); + break; + } + + case gl.TEXTURE_MIN_FILTER: { + /** @type {?tcuTexture.FilterMode} */ var minMode = sglrReferenceContext.mapGLFilterMode(value); + if (this.conditionalSetError(null == minMode, gl.INVALID_VALUE)) + return; + texture.getSampler().minFilter = /** @type {tcuTexture.FilterMode} */ (minMode); + break; + } + + case gl.TEXTURE_MAG_FILTER: { + /** @type {?tcuTexture.FilterMode} */ var magMode = sglrReferenceContext.mapGLFilterMode(value); + if (this.conditionalSetError(null == magMode, gl.INVALID_VALUE)) + return; + texture.getSampler().magFilter = /** @type {tcuTexture.FilterMode} */ (magMode); + break; + } + + case gl.TEXTURE_MAX_LEVEL: { + if (this.conditionalSetError(value < 0, gl.INVALID_VALUE)) + return; + texture.setMaxLevel(value); + break; + } + + default: + this.setError(gl.INVALID_ENUM); + return; + } + }; + + sglrReferenceContext.ReferenceContext.prototype.invalidateFramebuffer = function(target, attachments) {}; + sglrReferenceContext.ReferenceContext.prototype.invalidateSubFramebuffer = function(target, attachments, x, y, width, height) {}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js new file mode 100644 index 0000000000..cc8abf5969 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js @@ -0,0 +1,834 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.simplereference.sglrReferenceContextTest'); +goog.require('framework.common.tcuLogImage'); +goog.require('framework.common.tcuPixelFormat'); +goog.require('framework.common.tcuRGBA'); +goog.require('framework.common.tcuSurface'); +goog.require('framework.common.tcuTestCase'); +goog.require('framework.opengl.gluDrawUtil'); +goog.require('framework.opengl.simplereference.sglrReferenceContext'); +goog.require('framework.opengl.simplereference.sglrShaderProgram'); +goog.require('framework.referencerenderer.rrFragmentOperations'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrShadingContext'); +goog.require('framework.referencerenderer.rrVertexAttrib'); +goog.require('framework.referencerenderer.rrVertexPacket'); + +goog.scope(function() { + var sglrReferenceContextTest = framework.opengl.simplereference.sglrReferenceContextTest; + var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext; + var tcuTestCase = framework.common.tcuTestCase; + var tcuPixelFormat = framework.common.tcuPixelFormat; + var gluDrawUtil = framework.opengl.gluDrawUtil; + var tcuSurface = framework.common.tcuSurface; + var tcuLogImage = framework.common.tcuLogImage; + var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram; + var rrGenericVector = framework.referencerenderer.rrGenericVector; + var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; + var rrShadingContext = framework.referencerenderer.rrShadingContext; + var rrVertexPacket = framework.referencerenderer.rrVertexPacket; + var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations; + var tcuRGBA = framework.common.tcuRGBA; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.ClearContext = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.ClearContext.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.ClearContext.prototype.constructor = sglrReferenceContextTest.ClearContext; + + sglrReferenceContextTest.ClearContext.prototype.init = function() {}; + + sglrReferenceContextTest.ClearContext.prototype.iterate = function() { + + var width = 200; + var height = 188; + var samples = 1; + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(1, 0, 0, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var numFailedPixels = 0; + var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]); + for (var x = 0; x < width; x++) + for (var y = 0; y < height; y++) { + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y)); + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + } + + var access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + ctx.scissor(width / 4, height / 4, width / 2, height / 2); + ctx.enable(gl.SCISSOR_TEST); + ctx.clearColor(0, 1, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + numFailedPixels = 0; + var greenBluePixel = new gluDrawUtil.Pixel([0, 255, 255, 255]); + for (var x = 0; x < width; x++) + for (var y = 0; y < height; y++) { + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y)); + if ((x >= width / 4 && x < width - width / 4) && (y >= height / 4 && y < height - height / 4)) { + if (!pixel.equals(greenBluePixel)) + numFailedPixels += 1; + } else + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + } + + access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.Framebuffer = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.Framebuffer.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.Framebuffer.prototype.constructor = sglrReferenceContextTest.Framebuffer; + + sglrReferenceContextTest.Framebuffer.prototype.init = function() {}; + + sglrReferenceContextTest.Framebuffer.prototype.iterate = function() { + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var width = 200; + var height = 188; + var samples = 1; + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(0, 0, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + var fbo = ctx.createFramebuffer(); + var rbo = ctx.createRenderbuffer(); + ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo); + ctx.bindRenderbuffer(gl.RENDERBUFFER, rbo); + ctx.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height); + ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + bufferedLogToConsole('Framebuffer status: ' + (ctx.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE)); + ctx.clearColor(1, 0, 0, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + var numFailedPixels = 0; + var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]); + for (var x = 0; x < width; x++) + for (var y = 0; y < height; y++) { + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y)); + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + } + var access = pixels.getAccess(); + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + ctx.scissor(width / 4, height / 4, width / 2, height / 2); + ctx.enable(gl.SCISSOR_TEST); + ctx.clearColor(0, 1, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + numFailedPixels = 0; + var greenBluePixel = new gluDrawUtil.Pixel([0, 255, 255, 255]); + for (var x = 0; x < width; x++) + for (var y = 0; y < height; y++) { + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y)); + if ((x >= width / 4 && x < width - width / 4) && (y >= height / 4 && y < height - height / 4)) { + if (!pixel.equals(greenBluePixel)) + numFailedPixels += 1; + } else + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + } + + access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + ctx.bindFramebuffer(gl.FRAMEBUFFER, null); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]); + for (var x = 0; x < width; x++) + for (var y = 0; y < height; y++) { + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y)); + if (!pixel.equals(bluePixel)) + numFailedPixels += 1; + } + access = pixels.getAccess(); + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.Shader = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.Shader.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.Shader.prototype.constructor = sglrReferenceContextTest.Shader; + + sglrReferenceContextTest.Shader.prototype.init = function() {}; + + sglrReferenceContextTest.Shader.prototype.iterate = function() { + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var width = 200; + var height = 188; + var samples = 1; + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(0, 0, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + + var vertices = [ + -0.5, 0.5, + 0.5, 0.5, + -0.5, -0.5, + 0.5, 0.5, + 0.5, -0.5, + -0.5, -0.5 + ]; + + var vertices32 = new Float32Array(vertices); + + var squareVerticesBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW); + + var colors = [ + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1 + ]; + + var colors32 = new Float32Array(colors); + + var squareColorsBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW); + + /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration(); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexSource(new sglrShaderProgram.VertexSource('')); + + progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource('')); + + /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl); + + //Create program + ctx.createProgram(program); + + //Use program + ctx.useProgram(program); + + var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition'); + var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor'); + ctx.enableVertexAttribArray(vertexPositionAttribute); + ctx.enableVertexAttribArray(vertexColorAttribute); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); + + ctx.drawQuads(gl.TRIANGLES, 0, 6); + + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var numFailedPixels = 0; + + var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]); + var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]); + + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0)); + if (!pixel.equals(bluePixel)) + numFailedPixels += 1; + + pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94)); + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + + var access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.TriangleStrip = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.TriangleStrip.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.TriangleStrip.prototype.constructor = sglrReferenceContextTest.TriangleStrip; + + sglrReferenceContextTest.TriangleStrip.prototype.init = function() {}; + + sglrReferenceContextTest.TriangleStrip.prototype.iterate = function() { + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var width = 200; + var height = 188; + var samples = 1; + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(0, 0, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + + var vertices = [ + -0.5, 0.5, + 0.5, 0.5, + -0.5, 0, + 0.5, 0, + -0.5, -0.5, + 0.5, -0.5 + ]; + + var vertices32 = new Float32Array(vertices); + + var squareVerticesBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW); + + var colors = [ + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1 + ]; + + var colors32 = new Float32Array(colors); + + var squareColorsBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW); + + /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration(); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexSource(new sglrShaderProgram.VertexSource('')); + + progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource('')); + + /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl); + + //Create program + ctx.createProgram(program); + + //Use program + ctx.useProgram(program); + + var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition'); + var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor'); + ctx.enableVertexAttribArray(vertexPositionAttribute); + ctx.enableVertexAttribArray(vertexColorAttribute); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); + + ctx.drawQuads(gl.TRIANGLE_STRIP, 0, 6); + + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var numFailedPixels = 0; + + var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]); + var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]); + + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0)); + if (!pixel.equals(bluePixel)) + numFailedPixels += 1; + + pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94)); + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + + var access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.TriangleFan = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.TriangleFan.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.TriangleFan.prototype.constructor = sglrReferenceContextTest.TriangleFan; + + sglrReferenceContextTest.TriangleFan.prototype.init = function() {}; + + sglrReferenceContextTest.TriangleFan.prototype.iterate = function() { + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var width = 200; + var height = 188; + var samples = 1; + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(0, 0, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + + var vertices = [ + -0.5, 0, + -0.5, 0.5, + 0.5, 0.5, + 0.5, 0, + 0.5, -0.5, + -0.5, -0.5 + ]; + + var vertices32 = new Float32Array(vertices); + + var squareVerticesBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW); + + var colors = [ + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1, + 1, 0, 0, 1 + ]; + + var colors32 = new Float32Array(colors); + + var squareColorsBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW); + + /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration(); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexSource(new sglrShaderProgram.VertexSource('')); + + progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource('')); + + /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl); + + //Create program + ctx.createProgram(program); + + //Use program + ctx.useProgram(program); + + var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition'); + var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor'); + ctx.enableVertexAttribArray(vertexPositionAttribute); + ctx.enableVertexAttribArray(vertexColorAttribute); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); + + ctx.drawQuads(gl.TRIANGLE_FAN, 0, 6); + + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var numFailedPixels = 0; + + var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]); + var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]); + + var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0)); + if (!pixel.equals(bluePixel)) + numFailedPixels += 1; + + pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94)); + if (!pixel.equals(redPixel)) + numFailedPixels += 1; + + var access = pixels.getAccess(); + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {tcuTestCase.DeqpTest} + * @param {string} name + * @param {string} description + */ + sglrReferenceContextTest.DrawElements = function(name, description) { + tcuTestCase.DeqpTest.call(this, name, description); + }; + + sglrReferenceContextTest.DrawElements.prototype = Object.create(tcuTestCase.DeqpTest.prototype); + sglrReferenceContextTest.DrawElements.prototype.constructor = sglrReferenceContextTest.DrawElements; + + sglrReferenceContextTest.DrawElements.prototype.init = function() {}; + + sglrReferenceContextTest.DrawElements.prototype.iterate = function() { + var limits = new sglrReferenceContext.ReferenceContextLimits(gl); + var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8); + var width = 200; + var height = 188; + var samples = 1; + var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples); + var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); + ctx.clearColor(0, 0, 1, 1); + ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + + var vertices = [ + -0.5, 0.5, + 0, 0.5, + 0.4, 0.5, + + -0.5, 0.1, + 0, 0.1, + 0.4, 0.1, + + -0.5, -0.7, + 0, -0.7, + 0.4, -0.7 + ]; + + var vertices32 = new Float32Array(vertices); + + var squareVerticesBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW); + + var indices = [ + 0, 1, 3, 1, 3, 4, + 1, 2, 4, 2, 4, 5, + 3, 4, 6, 4, 6, 7, + 4, 5, 7, 5, 7, 8 + ]; + var indicesBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer); + ctx.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); + + var colors = [ + 1, 0, 0, 1, + 0, 1, 0, 1, + 0, 0, 1, 1, + 1, 1, 1, 1, + 1, 1, 0, 1, + 0, 1, 1, 1, + 1, 0, 1, 1, + 0.5, 0.5, 0.5, 1, + 0, 0, 0, 0 + ]; + + var colors32 = new Float32Array(colors); + + var squareColorsBuffer = ctx.createBuffer(); + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW); + + /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration(); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushVertexSource(new sglrShaderProgram.VertexSource('')); + + progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT)); + + progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource('')); + + /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl); + + //Create program + ctx.createProgram(program); + + //Use program + ctx.useProgram(program); + + var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition'); + var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor'); + ctx.enableVertexAttribArray(vertexPositionAttribute); + ctx.enableVertexAttribArray(vertexColorAttribute); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); + ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer); + ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); + + ctx.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0); + + var pixels = new tcuSurface.Surface(width, height); + ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr()); + + var numFailedPixels = 0; + + var access = pixels.getAccess(); + + var pixelsTotest = [ + // location, color + [2, 1], [0, 0, 255, 255], + // The red vertex is between 140 and 141 so account for some blending with the white vertex + [50, 140], [255, 5, 5, 255], + [50, 28], [255, 0, 255, 255], + [139, 28], [0, 0, 0, 255], + [50, 102], [255, 255, 255, 255], + [139, 102], [0, 255, 255, 255] + ]; + + var threshold = new tcuRGBA.RGBA([5, 5, 5, 5]); + + for (var i = 0; i < pixelsTotest.length; i += 2) { + var location = pixelsTotest[i]; + var reference = new tcuRGBA.RGBA(pixelsTotest[i + 1]); + var color = access.getPixelInt(location[0], location[1]); + var pixel = new tcuRGBA.RGBA(color); + if (!tcuRGBA.compareThreshold(pixel, reference, threshold)) + numFailedPixels++; + } + + tcuLogImage.logImage('Result', '', access); + + if (numFailedPixels > 0) + testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false); + else + testPassedOptions('Image comparison succeed', true); + + return tcuTestCase.IterateResult.STOP; + }; + + /** + * @constructor + * @extends {sglrShaderProgram.ShaderProgram} + * @param {sglrShaderProgram.ShaderProgramDeclaration} progDecl + */ + sglrReferenceContextTest.ContextShaderProgram = function(progDecl) { + sglrShaderProgram.ShaderProgram.call(this, progDecl); + }; + + sglrReferenceContextTest.ContextShaderProgram.prototype = Object.create(sglrShaderProgram.ShaderProgram.prototype); + sglrReferenceContextTest.ContextShaderProgram.prototype.constructor = sglrReferenceContextTest.ContextShaderProgram; + + /** + * @param {Array<rrVertexAttrib.VertexAttrib>} inputs + * @param {Array<rrVertexPacket.VertexPacket>} packets + * @param {number} numPackets + */ + sglrReferenceContextTest.ContextShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) { + for (var packetNdx = 0; packetNdx < numPackets; ++packetNdx) { + /** @type {number} */ var varyingLocColor = 0; + + /** @type {rrVertexPacket.VertexPacket} */ var packet = packets[packetNdx]; + + // Calc output color + /** @type {Array<number>} */ var coord = [1.0, 1.0]; + /** @type {Array<number>} */ var color = [1.0, 1.0, 1.0]; + + for (var attribNdx = 0; attribNdx < this.getVertexShader().getInputs().length; attribNdx++) { + /** @type {number} */ var numComponents = inputs[attribNdx].componentCount; + + var attribValue = rrVertexAttrib.readVertexAttrib(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx, this.getVertexShader().getInputs()[attribNdx].type); + + if (attribNdx == 0) { + coord[0] = attribValue[0]; + coord[1] = attribValue[1]; + } else { + color[0] = attribValue[0] * attribValue[3]; + color[1] = attribValue[1] * attribValue[3]; + color[2] = attribValue[2] * attribValue[3]; + } + } + + // Transform position + packet.position = [coord[0], coord[1], 1.0, 1.0]; + + // Pass color to FS + packet.outputs[varyingLocColor] = [color[0], color[1], color[2], 1.0]; + } + }; + + /** + * @param {Array<rrFragmentOperations.Fragment>} packets + * @param {rrShadingContext.FragmentShadingContext} context + */ + sglrReferenceContextTest.ContextShaderProgram.prototype.shadeFragments = function(packets, context) { + var varyingLocColor = 0; + + // Normal shading + for (var packetNdx = 0; packetNdx < packets.length; ++packetNdx) + packets[packetNdx].value = rrShadingContext.readTriangleVarying(packets[packetNdx], context, varyingLocColor); + }; + + sglrReferenceContextTest.init = function() { + var state = tcuTestCase.runner; + /** @type {tcuTestCase.DeqpTest} */ var testGroup = state.testCases; + + /** @type {tcuTestCase.DeqpTest} */ var referenceContextGroup = tcuTestCase.newTest('reference_context', 'Test reference context'); + + referenceContextGroup.addChild(new sglrReferenceContextTest.ClearContext('clear_context', 'Clear Context Test')); + referenceContextGroup.addChild(new sglrReferenceContextTest.Framebuffer('Framebuffer', 'Framebuffer Test')); + referenceContextGroup.addChild(new sglrReferenceContextTest.Shader('Shaders', 'Drawing using TRIANGLES')); + referenceContextGroup.addChild(new sglrReferenceContextTest.TriangleStrip('TriangleStrip', 'Drawing using TRIANGLE_STRIP')); + referenceContextGroup.addChild(new sglrReferenceContextTest.TriangleFan('TriangleFan', 'Drawing using TRIANGLE_FAN')); + referenceContextGroup.addChild(new sglrReferenceContextTest.DrawElements('DrawElements', 'Drawing using DrawElements and TRIANGLES')); + + testGroup.addChild(referenceContextGroup); + + }; + + sglrReferenceContextTest.run = function(context) { + gl = context; + //Set up Test Root parameters + var testName = 'single_reference_context'; + var testDescription = 'Single Reference Context Tests'; + var state = tcuTestCase.runner; + + state.testName = testName; + state.testCases = tcuTestCase.newTest(testName, testDescription, null); + + //Set up name and description of this test series. + setCurrentTestName(testName); + description(testDescription); + + try { + //Create test cases + sglrReferenceContextTest.init(); + //Run test cases + tcuTestCase.runTestCases(); + } + catch (err) { + bufferedLogToConsole(err); + tcuTestCase.runner.terminate(); + } + + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js new file mode 100644 index 0000000000..3b93dd8f9f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js @@ -0,0 +1,317 @@ +/*------------------------------------------------------------------------- + * 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. + * + *//*! + * \file + * \brief Reference context utils + *//*--------------------------------------------------------------------*/ + +'use strict'; +goog.provide('framework.opengl.simplereference.sglrReferenceUtils'); +goog.require('framework.common.tcuFloat'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrRenderState'); +goog.require('framework.referencerenderer.rrRenderer'); +goog.require('framework.referencerenderer.rrShaders'); +goog.require('framework.referencerenderer.rrVertexAttrib'); + +goog.scope(function() { + + var sglrReferenceUtils = framework.opengl.simplereference.sglrReferenceUtils; + var deMath = framework.delibs.debase.deMath; + var tcuFloat = framework.common.tcuFloat; + var rrGenericVector = framework.referencerenderer.rrGenericVector; + var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; + var rrRenderer = framework.referencerenderer.rrRenderer; + var rrDefs = framework.referencerenderer.rrDefs; + var rrShaders = framework.referencerenderer.rrShaders; + var rrRenderState = framework.referencerenderer.rrRenderState; + + /** + * @param {number} type (32-bit, unsigend) + * @return {rrVertexAttrib.VertexAttribType} + * @throws {Error} + */ + sglrReferenceUtils.mapGLPureIntegerVertexAttributeType = function(type) { + switch (type) { + case gl.UNSIGNED_BYTE: return rrVertexAttrib.VertexAttribType.PURE_UINT8; + case gl.UNSIGNED_SHORT: return rrVertexAttrib.VertexAttribType.PURE_UINT16; + case gl.UNSIGNED_INT: return rrVertexAttrib.VertexAttribType.PURE_UINT32; + case gl.BYTE: return rrVertexAttrib.VertexAttribType.PURE_INT8; + case gl.SHORT: return rrVertexAttrib.VertexAttribType.PURE_INT16; + case gl.INT: return rrVertexAttrib.VertexAttribType.PURE_INT32; + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} type (32-bit, unsigend) + * @param {boolean} normalizedInteger + * @param {number} size + * @return {rrVertexAttrib.VertexAttribType} converted value from type to VertexAttribType + * @throws {Error} + */ + sglrReferenceUtils.mapGLFloatVertexAttributeType = function(type, normalizedInteger, size) { + + /** @type {boolean} */ var useClampingNormalization = true; + + switch (type) { + case gl.FLOAT: + return rrVertexAttrib.VertexAttribType.FLOAT; + case gl.HALF_FLOAT: + return rrVertexAttrib.VertexAttribType.HALF; + /* Not supported in WebGL 1/2 case gl.FIXED: + return rrVertexAttrib.VertexAttribType.FIXED; + case gl.DOUBLE: + return rrVertexAttrib.VertexAttribType.DOUBLE; */ + case gl.UNSIGNED_BYTE: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_UINT8; + else + return rrVertexAttrib.VertexAttribType.NONPURE_UNORM8; + + case gl.UNSIGNED_SHORT: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_UINT16; + else + return rrVertexAttrib.VertexAttribType.NONPURE_UNORM16; + + case gl.UNSIGNED_INT: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_UINT32; + else + return rrVertexAttrib.VertexAttribType.NONPURE_UNORM32; + + case gl.UNSIGNED_INT_2_10_10_10_REV: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_UINT_2_10_10_10_REV; + else + return rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV; + + case gl.BYTE: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_INT8; + else if (useClampingNormalization) + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_CLAMP; + else + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_SCALE; + + case gl.SHORT: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_INT16; + else if (useClampingNormalization) + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_CLAMP; + else + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_SCALE; + + case gl.INT: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_INT32; + else if (useClampingNormalization) + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_CLAMP; + else + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_SCALE; + + case gl.INT_2_10_10_10_REV: + if (!normalizedInteger) + return rrVertexAttrib.VertexAttribType.NONPURE_INT_2_10_10_10_REV; + else if (useClampingNormalization) + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP; + else + return rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE; + + default: + throw new Error('Value to do mapping not compatible'); + + } + + }; + + /** + * @param {number} size + * @return {number} + * @throws {Error} + */ + sglrReferenceUtils.mapGLSize = function(size) { + switch (size) { + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return 4; + /* NOT in GL + case gl.BGRA: return 4; + */ + + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} type (32-bit, unsigned) + * @return {rrRenderer.PrimitiveType} + * @throws {Error} + */ + sglrReferenceUtils.mapGLPrimitiveType = function(type) { + switch (type) { + case gl.TRIANGLES: return rrRenderer.PrimitiveType.TRIANGLES; + case gl.TRIANGLE_STRIP: return rrRenderer.PrimitiveType.TRIANGLE_STRIP; + case gl.TRIANGLE_FAN: return rrRenderer.PrimitiveType.TRIANGLE_FAN; + case gl.LINES: return rrRenderer.PrimitiveType.LINES; + case gl.LINE_STRIP: return rrRenderer.PrimitiveType.LINE_STRIP; + case gl.LINE_LOOP: return rrRenderer.PrimitiveType.LINE_LOOP; + case gl.POINTS: return rrRenderer.PrimitiveType.POINTS; + + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} type (32-bit, unsigned) + * @return {rrDefs.IndexType} + * @throws {Error} + */ + sglrReferenceUtils.mapGLIndexType = function(type) { + switch (type) { + case gl.UNSIGNED_BYTE: return rrDefs.IndexType.INDEXTYPE_UINT8; + case gl.UNSIGNED_SHORT: return rrDefs.IndexType.INDEXTYPE_UINT16; + case gl.UNSIGNED_INT: return rrDefs.IndexType.INDEXTYPE_UINT32; + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} func (deUint32) + * @return {rrRenderState.TestFunc} + * @throws {Error} + */ + sglrReferenceUtils.mapGLTestFunc = function(func) { + switch (func) { + case gl.ALWAYS: return rrRenderState.TestFunc.ALWAYS; + case gl.EQUAL: return rrRenderState.TestFunc.EQUAL; + case gl.GEQUAL: return rrRenderState.TestFunc.GEQUAL; + case gl.GREATER: return rrRenderState.TestFunc.GREATER; + case gl.LEQUAL: return rrRenderState.TestFunc.LEQUAL; + case gl.LESS: return rrRenderState.TestFunc.LESS; + case gl.NEVER: return rrRenderState.TestFunc.NEVER; + case gl.NOTEQUAL: return rrRenderState.TestFunc.NOTEQUAL; + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} op (deUint32) + * @return {rrRenderState.StencilOp} + * @throws {Error} + */ + sglrReferenceUtils.mapGLStencilOp = function(op) { + switch (op) { + case gl.KEEP: return rrRenderState.StencilOp.KEEP; + case gl.ZERO: return rrRenderState.StencilOp.ZERO; + case gl.REPLACE: return rrRenderState.StencilOp.REPLACE; + case gl.INCR: return rrRenderState.StencilOp.INCR; + case gl.DECR: return rrRenderState.StencilOp.DECR; + case gl.INCR_WRAP: return rrRenderState.StencilOp.INCR_WRAP; + case gl.DECR_WRAP: return rrRenderState.StencilOp.DECR_WRAP; + case gl.INVERT: return rrRenderState.StencilOp.INVERT; + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} equation (deUint32) + * @return {rrRenderState.BlendEquation} + * @throws {Error} + */ + sglrReferenceUtils.mapGLBlendEquation = function(equation) { + switch (equation) { + case gl.FUNC_ADD: return rrRenderState.BlendEquation.ADD; + case gl.FUNC_SUBTRACT: return rrRenderState.BlendEquation.SUBTRACT; + case gl.FUNC_REVERSE_SUBTRACT: return rrRenderState.BlendEquation.REVERSE_SUBTRACT; + case gl.MIN: return rrRenderState.BlendEquation.MIN; + case gl.MAX: return rrRenderState.BlendEquation.MAX; + default: + throw new Error('Value to do mapping not compatible'); + } + }; + + /** + * @param {number} equation (deUint32) + * @return {rrRenderState.BlendEquationAdvanced} + * @throws {Error} + */ + /*sglrReferenceUtils.mapGLBlendEquationAdvanced = function(equation) { + switch (equation) { + case gl.MULTIPLY_KHR: return rrRenderState.BlendEquationAdvanced.MULTIPLY; + case gl.SCREEN_KHR: return rrRenderState.BlendEquationAdvanced.SCREEN; + case gl.OVERLAY_KHR: return rrRenderState.BlendEquationAdvanced.OVERLAY; + case gl.DARKEN_KHR: return rrRenderState.BlendEquationAdvanced.DARKEN; + case gl.LIGHTEN_KHR: return rrRenderState.BlendEquationAdvanced.LIGHTEN; + case gl.COLORDODGE_KHR: return rrRenderState.BlendEquationAdvanced.COLORDODGE; + case gl.COLORBURN_KHR: return rrRenderState.BlendEquationAdvanced.COLORBURN; + case gl.HARDLIGHT_KHR: return rrRenderState.BlendEquationAdvanced.HARDLIGHT; + case gl.SOFTLIGHT_KHR: return rrRenderState.BlendEquationAdvanced.SOFTLIGHT; + case gl.DIFFERENCE_KHR: return rrRenderState.BlendEquationAdvanced.DIFFERENCE; + case gl.EXCLUSION_KHR: return rrRenderState.BlendEquationAdvanced.EXCLUSION; + case gl.HSL_HUE_KHR: return rrRenderState.BlendEquationAdvanced.HSL_HUE; + case gl.HSL_SATURATION_KHR: return rrRenderState.BlendEquationAdvanced.HSL_SATURATION; + case gl.HSL_COLOR_KHR: return rrRenderState.BlendEquationAdvanced.HSL_COLOR; + case gl.HSL_LUMINOSITY_KHR: return rrRenderState.BlendEquationAdvanced.HSL_LUMINOSITY; + default: + throw new Error("Value to do mapping not compatible"); + } + };*/ + + /** + * @param {number} func (deUint32) + * @return {rrRenderState.BlendFunc} + * @throws {Error} + */ + sglrReferenceUtils.mapGLBlendFunc = function(func) { + switch (func) { + case gl.ZERO: return rrRenderState.BlendFunc.ZERO; + case gl.ONE: return rrRenderState.BlendFunc.ONE; + case gl.SRC_COLOR: return rrRenderState.BlendFunc.SRC_COLOR; + case gl.ONE_MINUS_SRC_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR; + case gl.DST_COLOR: return rrRenderState.BlendFunc.DST_COLOR; + case gl.ONE_MINUS_DST_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR; + case gl.SRC_ALPHA: return rrRenderState.BlendFunc.SRC_ALPHA; + case gl.ONE_MINUS_SRC_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA; + case gl.DST_ALPHA: return rrRenderState.BlendFunc.DST_ALPHA; + case gl.ONE_MINUS_DST_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA; + case gl.CONSTANT_COLOR: return rrRenderState.BlendFunc.CONSTANT_COLOR; + case gl.ONE_MINUS_CONSTANT_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR; + case gl.CONSTANT_ALPHA: return rrRenderState.BlendFunc.CONSTANT_ALPHA; + case gl.ONE_MINUS_CONSTANT_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA; + case gl.SRC_ALPHA_SATURATE: return rrRenderState.BlendFunc.SRC_ALPHA_SATURATE; + // case gl.SRC1_COLOR: return rrRenderState.BlendFunc.SRC1_COLOR; + // case gl.ONE_MINUS_SRC1_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR; + // case gl.SRC1_ALPHA: return rrRenderState.BlendFunc.SRC1_ALPHA; + // case gl.ONE_MINUS_SRC1_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA; + default: + throw new Error('Value to do mapping not compatible'); + } + }; +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js new file mode 100644 index 0000000000..f5201a5315 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js @@ -0,0 +1,336 @@ +/*------------------------------------------------------------------------- + * 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('framework.opengl.simplereference.sglrShaderProgram'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.opengl.gluShaderUtil'); +goog.require('framework.opengl.gluTextureUtil'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrFragmentOperations'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrShaders'); +goog.require('framework.referencerenderer.rrShadingContext'); +goog.require('framework.referencerenderer.rrVertexAttrib'); +goog.require('framework.referencerenderer.rrVertexPacket'); + +goog.scope(function() { + + var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram; + var rrShaders = framework.referencerenderer.rrShaders; + var rrGenericVector = framework.referencerenderer.rrGenericVector; + var tcuTexture = framework.common.tcuTexture; + var deMath = framework.delibs.debase.deMath; + var gluTextureUtil = framework.opengl.gluTextureUtil; + var gluShaderUtil = framework.opengl.gluShaderUtil; + var tcuTextureUtil = framework.common.tcuTextureUtil; + var rrDefs = framework.referencerenderer.rrDefs; + var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations; + var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; + var rrVertexPacket = framework.referencerenderer.rrVertexPacket; + var rrShadingContext = framework.referencerenderer.rrShadingContext; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + /** + * sglrShaderProgram.VaryingFlags + * @constructor + * @struct + */ + sglrShaderProgram.VaryingFlags = function() { + this.NONE = true; //TODO: is NONE necessary? + this.FLATSHADE = false; + }; + + /** + * sglrShaderProgram.VertexAttribute + * @constructor + * @param {string} name_ + * @param {rrGenericVector.GenericVecType} type_ + */ + sglrShaderProgram.VertexAttribute = function(name_, type_) { + this.name = name_; + this.type = type_; + }; + + /** + * sglrShaderProgram.VertexToFragmentVarying + * @constructor + * @param {rrGenericVector.GenericVecType} type_ + * @param {sglrShaderProgram.VaryingFlags=} flags + */ + sglrShaderProgram.VertexToFragmentVarying = function(type_, flags) { + this.type = type_; + this.flatshade = flags === undefined ? new sglrShaderProgram.VaryingFlags().FLATSHADE : flags.FLATSHADE; + }; + + /** + * sglrShaderProgram.FragmentOutput + * @constructor + * @param {rrGenericVector.GenericVecType} type_ + */ + sglrShaderProgram.FragmentOutput = function(type_) { + /** @type {rrGenericVector.GenericVecType} */ this.type = type_; + }; + + /** + * sglrShaderProgram.Uniform + * @constructor + * @param {string} name_ + * @param {gluShaderUtil.DataType} type_ + */ + sglrShaderProgram.Uniform = function(name_, type_) { + /** @type {string} */ this.name = name_; + /** @type {gluShaderUtil.DataType} */ this.type = type_; + /** @type {Array<number>} */ this.value; + /** @type {?rrDefs.Sampler} */ this.sampler = null; + }; + + /** + * sglrShaderProgram.VertexSource + * @constructor + * @param {string} str + */ + sglrShaderProgram.VertexSource = function(str) { + /** @type {string} */ this.source = str; + }; + + /** + * sglrShaderProgram.FragmentSource + * @constructor + * @param {string} str + */ + sglrShaderProgram.FragmentSource = function(str) { + /** @type {string} */ this.source = str; + }; + + /** + * sglrShaderProgram.ShaderProgramDeclaration + * @constructor + */ + sglrShaderProgram.ShaderProgramDeclaration = function() { + /** @type {Array<sglrShaderProgram.VertexAttribute>} */ this.m_vertexAttributes = []; + /** @type {Array<sglrShaderProgram.VertexToFragmentVarying>} */ this.m_vertexToFragmentVaryings = []; + /** @type {Array<sglrShaderProgram.FragmentOutput>} */ this.m_fragmentOutputs = []; + /** @type {Array<sglrShaderProgram.Uniform>} */ this.m_uniforms = []; + /** @type {string} */ this.m_vertexSource; + /** @type {string} */ this.m_fragmentSource; + + /** @type {boolean} */ this.m_vertexShaderSet = false; + /** @type {boolean} */ this.m_fragmentShaderSet = false; + }; + + /** + * Add a vertex attribute to the shader program declaration. + * @param {sglrShaderProgram.VertexAttribute} v + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexAttribute = function(v) { + this.m_vertexAttributes.push(v); + return this; + }; + + /** + * Add a vertex to fragment varying to the shader program declaration. + * @param {sglrShaderProgram.VertexToFragmentVarying} v + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexToFragmentVarying = function(v) { + this.m_vertexToFragmentVaryings.push(v); + return this; + }; + + /** + * Add a fragment output to the shader program declaration. + * @param {sglrShaderProgram.FragmentOutput} v + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushFragmentOutput = function(v) { + this.m_fragmentOutputs.push(v); + return this; + }; + + /** + * Add a uniform to the shader program declaration. + * @param {sglrShaderProgram.Uniform} v + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushUniform = function(v) { + this.m_uniforms.push(v); + return this; + }; + + /** + * @param {sglrShaderProgram.VertexSource} c + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexSource = function(c) { + DE_ASSERT(!this.m_vertexShaderSet); + this.m_vertexSource = c.source; + this.m_vertexShaderSet = true; + return this; + }; + + /** + * @param {sglrShaderProgram.FragmentSource} c + * @return {sglrShaderProgram.ShaderProgramDeclaration} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.pushFragmentSource = function(c) { + DE_ASSERT(!this.m_fragmentSource); + /** @type {sglrShaderProgram.FragmentSource} */ this.m_fragmentSource = c.source; + /** @type {boolean} */ this.m_fragmentShaderSet = true; + return this; + }; + + /** + * @return {boolean} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.valid = function() { + if (!this.m_vertexShaderSet || !this.m_fragmentShaderSet) + return false; + + if (this.m_fragmentOutputs.length == 0) + return false; + + return true; + }; + + /** + * @return {number} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.getVertexInputCount = function() { + return this.m_vertexAttributes.length; + }; + + /** + * @return {number} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.getVertexOutputCount = function() { + return this.m_vertexToFragmentVaryings.length; + }; + + /** + * @return {number} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.getFragmentInputCount = function() { + return this.m_vertexToFragmentVaryings.length; + }; + + /** + * @return {number} + */ + sglrShaderProgram.ShaderProgramDeclaration.prototype.getFragmentOutputCount = function() { + return this.m_fragmentOutputs.length; + }; + + /** + * @constructor + * @param {sglrShaderProgram.ShaderProgramDeclaration} decl + */ + sglrShaderProgram.ShaderProgram = function(decl) { + /** @type {rrShaders.VertexShader} */ this.vertexShader = new rrShaders.VertexShader(decl.getVertexInputCount(), decl.getVertexOutputCount()); + /** @type {rrShaders.FragmentShader} */ this.fragmentShader = new rrShaders.FragmentShader(decl.getFragmentInputCount(), decl.getFragmentOutputCount()); + + /** @type {Array<string>} */ this.m_attributeNames = []; + /** @type {Array<sglrShaderProgram.Uniform>} */ this.m_uniforms = []; + /** @type {string} */ this.m_vertSrc = decl.m_vertexSource; + /** @type {string} */ this.m_fragSrc = decl.m_fragmentSource; + + DE_ASSERT(decl.valid()); + + // Set up shader IO + + for (var ndx = 0; ndx < decl.m_vertexAttributes.length; ++ndx) { + this.vertexShader.m_inputs[ndx].type = decl.m_vertexAttributes[ndx].type; + this.m_attributeNames[ndx] = decl.m_vertexAttributes[ndx].name; + } + + for (var ndx = 0; ndx < decl.m_vertexToFragmentVaryings.length; ++ndx) { + this.vertexShader.m_outputs[ndx].type = decl.m_vertexToFragmentVaryings[ndx].type; + this.vertexShader.m_outputs[ndx].flatshade = decl.m_vertexToFragmentVaryings[ndx].flatshade; + + this.fragmentShader.m_inputs[ndx] = this.vertexShader.m_outputs[ndx]; + } + + for (var ndx = 0; ndx < decl.m_fragmentOutputs.length; ++ndx) + this.fragmentShader.m_outputs[ndx].type = decl.m_fragmentOutputs[ndx].type; + + // Set up uniforms + + for (var ndx = 0; ndx < decl.m_uniforms.length; ++ndx) + this.m_uniforms[ndx] = new sglrShaderProgram.Uniform(decl.m_uniforms[ndx].name, decl.m_uniforms[ndx].type); + }; + + /** + * @return {rrShaders.VertexShader} + */ + sglrShaderProgram.ShaderProgram.prototype.getVertexShader = function() { + return this.vertexShader; + }; + + /** + * @return {rrShaders.FragmentShader} + */ + sglrShaderProgram.ShaderProgram.prototype.getFragmentShader = function() { + return this.fragmentShader; + }; + + /** + * @param {string} name + * @return {sglrShaderProgram.Uniform} + * @throws {Error} + */ + sglrShaderProgram.ShaderProgram.prototype.getUniformByName = function(name) { + DE_ASSERT(name); + + for (var ndx = 0; ndx < this.m_uniforms.length; ++ndx) + if (this.m_uniforms[ndx].name == name) + return this.m_uniforms[ndx]; + + throw new Error('Invalid uniform name, uniform not found.'); + }; + + /** + * shadeFragments - abstract function, to be implemented by children classes + * @param {Array<rrFragmentOperations.Fragment>} packets + * @param {rrShadingContext.FragmentShadingContext} context + * @throws {Error} + */ + sglrShaderProgram.ShaderProgram.prototype.shadeFragments = function(packets, context) { + throw new Error('This function needs to be overwritten in a child class.'); + }; + + /** + * shadeVertices - abstract function, to be implemented by children classes + * @param {Array<rrVertexAttrib.VertexAttrib>} inputs + * @param {Array<rrVertexPacket.VertexPacket>} packets + * @param {number} numPackets + * @throws {Error} + */ + sglrShaderProgram.ShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) { + throw new Error('This function needs to be overwritten in a child class.'); + }; + +}); |