diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer')
11 files changed, 3589 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrDefs.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrDefs.js new file mode 100644 index 0000000000..c0400465e4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrDefs.js @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrDefs'); + +goog.scope(function() { + +var rrDefs = framework.referencerenderer.rrDefs; + +/** + * @enum + */ +rrDefs.FaceType = { + FACETYPE_FRONT: 0, + FACETYPE_BACK: 1 +}; + +/** + * @enum + */ +rrDefs.IndexType = { + INDEXTYPE_UINT8: 0, + INDEXTYPE_UINT16: 1, + INDEXTYPE_UINT32: 2 +}; + +/** + * @enum + */ +rrDefs.ProvokingVertex = { + PROVOKINGVERTEX_FIRST: 1, + PROVOKINGVERTEX_LAST: 2 // \note valid value, "last vertex", not last of enum +}; + +/** + * @interface + */ +rrDefs.Sampler = function() {}; + +/** + * @param {Array<number>} pos + * @param {number=} lod + * @return {Array<number>} + */ +rrDefs.Sampler.prototype.sample = function(pos, lod) {}; + +/** + * @param {Array<Array<number>>} packetTexcoords 4 coordinates + * @param {number} lodBias + * @return {Array<Array<number>>} 4 vec4 samples + */ +rrDefs.Sampler.prototype.sample4 = function(packetTexcoords, lodBias) {}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrFragmentOperations.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrFragmentOperations.js new file mode 100644 index 0000000000..a9c2a1f464 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrFragmentOperations.js @@ -0,0 +1,583 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrFragmentOperations'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrRenderState'); + +goog.scope(function() { + +var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations; +var deMath = framework.delibs.debase.deMath; +var rrRenderState = framework.referencerenderer.rrRenderState; +var tcuTexture = framework.common.tcuTexture; +var tcuTextureUtil = framework.common.tcuTextureUtil; + +/** Return oldValue with the bits indicated by mask replaced by corresponding bits of newValue. + * @param {number} oldValue + * @param {number} newValue + * @param {number} mask + * @return {number} + */ +rrFragmentOperations.maskedBitReplace = function(oldValue, newValue, mask) { + return (oldValue & ~mask) | (newValue & mask); +}; + +/** + * @param {Array<number>} point + * @param {?} rect + * @return {boolean} + */ +rrFragmentOperations.isInsideRect = function(point, rect) { + return deMath.deInBounds32(point[0], rect.left, rect.left + rect.width) && + deMath.deInBounds32(point[1], rect.bottom, rect.bottom + rect.height); +}; + +/** + * @constructor + * @param {Array<number>} coefficents + * @param {Array<number>} coords + * @param {number} depth + */ +rrFragmentOperations.Fragment = function(coefficents, coords, depth) { + /** @type {Array<number>} */ this.barycentric = coefficents; + /** @type {Array<number>} */ this.pixelCoord = coords; + /** @type {boolean} */ this.isAlive = true; + /** @type {boolean} */ this.stencilPassed = true; + /** @type {boolean} */ this.depthPassed = true; + /** @type {Array<number>} */ this.sampleDepths = [depth]; + /** @type {Array<number>} */ this.clampedBlendSrcColor = []; + /** @type {Array<number>} */ this.clampedBlendSrc1Color = []; + /** @type {Array<number>} */ this.clampedBlendDstColor = []; + /** @type {Array<number>} */ this.blendSrcFactorRGB = []; + /** @type {number} */ this.blendSrcFactorA = NaN; + /** @type {Array<number>} */ this.blendDstFactorRGB = []; + /** @type {number} */ this.blendDstFactorA = NaN; + /** @type {Array<number>} */ this.blendedRGB = []; + /** @type {number} */ this.blendedA = NaN; + /** @type {Array<number>} */ this.signedValue = []; //!< integer targets + /** @type {Array<number>} */ this.unsignedValue = []; //!< unsigned integer targets + /** @type {Array<number>} */ this.value = []; /*TODO: what type should it be? */ + /** @type {Array<number>} */ this.value1 = []; /*TODO: what type should it be? */ +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.WindowRectangle} scissorRect + */ +rrFragmentOperations.executeScissorTest = function(inputFragments, scissorRect) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + if (!rrFragmentOperations.isInsideRect(frag.pixelCoord, scissorRect)) + frag.isAlive = false; + } + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.StencilState} stencilState + * @param {number} numStencilBits + * @param {tcuTexture.PixelBufferAccess} stencilBuffer + */ +rrFragmentOperations.executeStencilCompare = function(inputFragments, stencilState, numStencilBits, stencilBuffer) { + var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1); + + /** + * @param {function(number=,number=):boolean} expression + */ + var sample_register_stencil_compare = function(expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var fragSampleNdx = 0; + var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + var maskedRef = stencilState.compMask & clampedStencilRef; + var maskedBuf = stencilState.compMask & stencilBufferValue; + frag.stencilPassed = expression(maskedRef, maskedBuf); + } + } + }; + + switch (stencilState.func) { + case rrRenderState.TestFunc.NEVER: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return false;}); break; + case rrRenderState.TestFunc.ALWAYS: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return true;}); break; + case rrRenderState.TestFunc.LESS: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef < maskedBuf;}); break; + case rrRenderState.TestFunc.LEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef <= maskedBuf;}); break; + case rrRenderState.TestFunc.GREATER: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef > maskedBuf;}); break; + case rrRenderState.TestFunc.GEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef >= maskedBuf;}); break; + case rrRenderState.TestFunc.EQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef == maskedBuf;}); break; + case rrRenderState.TestFunc.NOTEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef != maskedBuf;}); break; + default: + throw new Error('Unrecognized stencil test function:' + stencilState.func); + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.StencilState} stencilState + * @param {number} numStencilBits + * @param {tcuTexture.PixelBufferAccess} stencilBuffer + */ +rrFragmentOperations.executeStencilSFail = function(inputFragments, stencilState, numStencilBits, stencilBuffer) { + var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1); + /** + * @param {function(number,number):number} expression + */ + var sample_register_sfail = function(expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive && !frag.stencilPassed) { + var fragSampleNdx = 0; + var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + stencilBuffer.setPixStencil(rrFragmentOperations.maskedBitReplace(stencilBufferValue, expression(stencilBufferValue, numStencilBits), stencilState.writeMask), fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + frag.isAlive = false; + } + } + }; + + switch (stencilState.sFail) { + case rrRenderState.StencilOp.KEEP: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return stencilBufferValue;}); break; + case rrRenderState.StencilOp.ZERO: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return 0;}); break; + case rrRenderState.StencilOp.REPLACE: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return clampedStencilRef;}); break; + case rrRenderState.StencilOp.INCR: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue + 1, 0, (1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.DECR: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue - 1, 0, (1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.INCR_WRAP: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (stencilBufferValue + 1) & ((1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.DECR_WRAP: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (stencilBufferValue - 1) & ((1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.INVERT: + sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (~stencilBufferValue) & ((1 << numStencilBits) - 1);}); break; + default: + throw new Error('Unrecognized stencil op:' + stencilState.sFail); + } + +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.TestFunc} depthFunc + * @param {tcuTexture.PixelBufferAccess} depthBuffer + */ +rrFragmentOperations.executeDepthCompare = function(inputFragments, depthFunc, depthBuffer) { + /** + * @param {function(number=,number=):boolean} expression + */ + var convertToDepthBuffer = false; + + var access; + if (depthBuffer.getFormat().type != tcuTexture.ChannelType.FLOAT && + depthBuffer.getFormat().type != tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV) { + access = new tcuTexture.PixelBufferAccess({ + format: depthBuffer.getFormat(), + width: 1, + height: 1, + depth: 1, + data: new ArrayBuffer(8) + }); + convertToDepthBuffer = true; + } + + var sample_register_depth_compare = function(expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var fragSampleNdx = 0; + var depthBufferValue = depthBuffer.getPixDepth(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + var sampleDepthFloat = frag.sampleDepths[fragSampleNdx]; + + var sampleDepth; + if (convertToDepthBuffer) { + /* convert input float to target buffer format for comparison */ + access.setPixDepth(sampleDepthFloat, 0, 0, 0); + sampleDepth = access.getPixDepth(0, 0, 0); + } else { + sampleDepth = deMath.clamp(sampleDepthFloat, 0.0, 1.0); + } + + frag.depthPassed = expression(sampleDepth, depthBufferValue); + } + } + }; + + switch (depthFunc) { + case rrRenderState.TestFunc.NEVER: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return false;}); break; + case rrRenderState.TestFunc.ALWAYS: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return true;}); break; + case rrRenderState.TestFunc.LESS: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth < depthBufferValue;}); break; + case rrRenderState.TestFunc.LEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth <= depthBufferValue;}); break; + case rrRenderState.TestFunc.GREATER: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth > depthBufferValue;}); break; + case rrRenderState.TestFunc.GEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth >= depthBufferValue;}); break; + case rrRenderState.TestFunc.EQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth == depthBufferValue;}); break; + case rrRenderState.TestFunc.NOTEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth != depthBufferValue;}); break; + default: + throw new Error('Unrecognized depth function:' + depthFunc); + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {tcuTexture.PixelBufferAccess} depthBuffer + */ +rrFragmentOperations.executeDepthWrite = function(inputFragments, depthBuffer) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive && frag.depthPassed) { + var fragSampleNdx = 0; + var clampedDepth = deMath.clamp(frag.sampleDepths[fragSampleNdx], 0.0, 1.0); + depthBuffer.setPixDepth(clampedDepth, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.StencilState} stencilState + * @param {number} numStencilBits + * @param {tcuTexture.PixelBufferAccess} stencilBuffer + */ +rrFragmentOperations.executeStencilDpFailAndPass = function(inputFragments, stencilState, numStencilBits, stencilBuffer) { + var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1); + + /** + * @param {function(boolean):boolean} condition + * @param {function(number,number):number} expression + */ + var sample_register_dpfail_or_dppass = function(condition, expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive && condition(frag.depthPassed)) { + var fragSampleNdx = 0; + var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + stencilBuffer.setPixStencil(rrFragmentOperations.maskedBitReplace(stencilBufferValue, expression(stencilBufferValue, numStencilBits), stencilState.writeMask), fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } + }; + + var switch_dpfail_or_dppass = function(op_name, condition) { + switch (stencilState[op_name]) { + case rrRenderState.StencilOp.KEEP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return stencilBufferValue;}); break; + case rrRenderState.StencilOp.ZERO: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return 0;}); break; + case rrRenderState.StencilOp.REPLACE: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return clampedStencilRef;}); break; + case rrRenderState.StencilOp.INCR: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue + 1, 0, (1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.DECR: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue - 1, 0, (1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.INCR_WRAP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (stencilBufferValue + 1) & ((1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.DECR_WRAP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (stencilBufferValue - 1) & ((1 << numStencilBits) - 1);}); break; + case rrRenderState.StencilOp.INVERT: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (~stencilBufferValue) & ((1 << numStencilBits) - 1);}); break; + default: + throw new Error('Unrecognized stencil operation:' + op_name); + } + }; + + var passed = function(depthPassed) { return depthPassed;}; + var failed = function(depthPassed) { return !depthPassed;}; + + switch_dpfail_or_dppass('dpFail', failed); + switch_dpfail_or_dppass('dpPass', passed); +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {Array<number>} blendColor + * @param {rrRenderState.BlendState} blendRGBState + */ +rrFragmentOperations.executeBlendFactorComputeRGB = function(inputFragments, blendColor, blendRGBState) { + /** + * @param {string} factor_name + * @param {function(Array<number>, Array<number>, Array<number>):Array<number>} expression + */ + var sample_register_blend_factor = function(factor_name, expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var src = frag.clampedBlendSrcColor; + var src1 = frag.clampedBlendSrc1Color; + var dst = frag.clampedBlendDstColor; + frag[factor_name] = deMath.clampVector(expression(src, src1, dst), 0, 1); + } + } + }; + + var switch_src_or_dst_factor_rgb = function(func_name, factor_name) { + switch (blendRGBState[func_name]) { + case rrRenderState.BlendFunc.ZERO: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [0, 0, 0];}); break; + case rrRenderState.BlendFunc.ONE: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1, 1, 1];}); break; + case rrRenderState.BlendFunc.SRC_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(src, [0, 1, 2]);}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(src, [0, 1, 2]));}); break; + case rrRenderState.BlendFunc.DST_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(dst, [0, 1, 2]);}); break; + case rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(dst, [0, 1, 2]));}); break; + case rrRenderState.BlendFunc.SRC_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [src[3], src[3], src[3]];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - src[3], 1.0 - src[3], 1.0 - src[3]];}); break; + case rrRenderState.BlendFunc.DST_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [dst[3], dst[3], dst[3]];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - dst[3], 1.0 - dst[3], 1.0 - dst[3]];}); break; + case rrRenderState.BlendFunc.CONSTANT_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(blendColor, [0, 1, 2]);}); break; + case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(blendColor, [0, 1, 2]));}); break; + case rrRenderState.BlendFunc.CONSTANT_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [blendColor[3], blendColor[3], blendColor[3]];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - blendColor[3], 1.0 - blendColor[3], 1.0 - blendColor[3]];}); break; + case rrRenderState.BlendFunc.SRC_ALPHA_SATURATE: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [Math.min(src[3], 1.0 - dst[3]), Math.min(src[3], 1.0 - dst[3]), Math.min(src[3], 1.0 - dst[3])];}); break; + case rrRenderState.BlendFunc.SRC1_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(src1, [0, 1, 2]);}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(src1, [0, 1, 2]));}); break; + case rrRenderState.BlendFunc.SRC1_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [src1[3], src1[3], src1[3]];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - src1[3], 1.0 - src1[3], 1.0 - src1[3]];}); break; + default: + throw new Error('Unrecognized blend function:' + func_name); + } + }; + + switch_src_or_dst_factor_rgb('srcFunc', 'blendSrcFactorRGB'); + switch_src_or_dst_factor_rgb('dstFunc', 'blendDstFactorRGB'); + +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {Array<number>} blendColor + * @param {rrRenderState.BlendState} blendAState + */ +rrFragmentOperations.executeBlendFactorComputeA = function(inputFragments, blendColor, blendAState) { + /** + * @param {string} factor_name + * @param {function(Array<number>, Array<number>, Array<number>):number} expression + */ + var sample_register_blend_factor = function(factor_name, expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var src = frag.clampedBlendSrcColor; + var src1 = frag.clampedBlendSrc1Color; + var dst = frag.clampedBlendDstColor; + frag[factor_name] = deMath.clamp(expression(src, src1, dst), 0, 1); + } + } + }; + + var swictch_src_or_dst_factor_a = function(func_name, factor_name) { + switch (blendAState[func_name]) { + case rrRenderState.BlendFunc.ZERO: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 0.0;}); break; + case rrRenderState.BlendFunc.ONE: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0;}); break; + case rrRenderState.BlendFunc.SRC_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return src[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src[3];}); break; + case rrRenderState.BlendFunc.DST_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return dst[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - dst[3];}); break; + case rrRenderState.BlendFunc.SRC_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return src[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src[3];}); break; + case rrRenderState.BlendFunc.DST_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return dst[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - dst[3];}); break; + case rrRenderState.BlendFunc.CONSTANT_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return blendColor[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - blendColor[3];}); break; + case rrRenderState.BlendFunc.CONSTANT_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return blendColor[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - blendColor[3];}); break; + case rrRenderState.BlendFunc.SRC_ALPHA_SATURATE: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0;}); break; + case rrRenderState.BlendFunc.SRC1_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return src1[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src1[3];}); break; + case rrRenderState.BlendFunc.SRC1_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return src1[3];}); break; + case rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA: + sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src1[3];}); break; + default: + throw new Error('Unrecognized blend function:' + func_name); + } + }; + + swictch_src_or_dst_factor_a('srcFunc', 'blendSrcFactorA'); + swictch_src_or_dst_factor_a('dstFunc', 'blendDstFactorA'); +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write + * @param {rrRenderState.BlendState} blendRGBState + * @param {rrRenderState.BlendState} blendAState + */ +rrFragmentOperations.executeBlend = function(inputFragments, blendRGBState, blendAState) { + var sample_register_blended_color = function(color_name, expression) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var src = frag.clampedBlendSrcColor; + var dst = frag.clampedBlendDstColor; + frag[color_name] = expression(src, dst, frag); + } + } + }; + + switch (blendRGBState.equation) { + case rrRenderState.BlendEquation.ADD: + sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.add(deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB), deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB));}); break; + case rrRenderState.BlendEquation.SUBTRACT: + sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.subtract(deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB), deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB));}); break; + case rrRenderState.BlendEquation.REVERSE_SUBTRACT: + sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.subtract(deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB), deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB));}); break; + case rrRenderState.BlendEquation.MIN: + sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.min(deMath.swizzle(src, [0, 1, 2]), deMath.swizzle(dst, [0, 1, 2]));}); break; + case rrRenderState.BlendEquation.MAX: + sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.max(deMath.swizzle(src, [0, 1, 2]), deMath.swizzle(dst, [0, 1, 2]));}); break; + default: + throw new Error('Unrecognized blend equation:' + blendRGBState.equation); + } + + switch (blendAState.equation) { + case rrRenderState.BlendEquation.ADD: + sample_register_blended_color('blendedA', function(src, dst, frag) { return src[3] * frag.blendSrcFactorA + dst[3] * frag.blendDstFactorA;}); break; + case rrRenderState.BlendEquation.SUBTRACT: + sample_register_blended_color('blendedA', function(src, dst, frag) { return src[3] * frag.blendSrcFactorA - dst[3] * frag.blendDstFactorA;}); break; + case rrRenderState.BlendEquation.REVERSE_SUBTRACT: + sample_register_blended_color('blendedA', function(src, dst, frag) { return dst[3] * frag.blendDstFactorA - src[3] * frag.blendSrcFactorA;}); break; + case rrRenderState.BlendEquation.MIN: + sample_register_blended_color('blendedA', function(src, dst, frag) { return Math.min(src[3], dst[3]);}); break; + case rrRenderState.BlendEquation.MAX: + sample_register_blended_color('blendedA', function(src, dst, frag) { return Math.max(src[3], dst[3]);}); break; + default: + throw new Error('Unrecognized blend equation:' + blendAState.equation); + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments + * @param {boolean} isSRGB + * @param {tcuTexture.PixelBufferAccess} colorBuffer + */ +rrFragmentOperations.executeColorWrite = function(inputFragments, isSRGB, colorBuffer) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var combinedColor = frag.blendedRGB.slice(); + combinedColor[3] = frag.blendedA; + if (isSRGB) + combinedColor = tcuTextureUtil.linearToSRGB(combinedColor); + + colorBuffer.setPixel(combinedColor, 0, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments + * @param {Array<boolean>} colorMaskFactor + * @param {Array<boolean>} colorMaskNegationFactor + * @param {boolean} isSRGB + * @param {tcuTexture.PixelBufferAccess} colorBuffer + */ +rrFragmentOperations.executeMaskedColorWrite = function(inputFragments, colorMaskFactor, colorMaskNegationFactor, isSRGB, colorBuffer) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var fragSampleNdx = 0; + var originalColor = colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + var newColor = frag.blendedRGB.slice(); + newColor[3] = frag.blendedA; + + if (isSRGB) + newColor = tcuTextureUtil.linearToSRGB(newColor); + + newColor = deMath.add(deMath.multiply(colorMaskFactor, newColor), deMath.multiply(colorMaskNegationFactor, originalColor)); + + colorBuffer.setPixel(newColor, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments + * @param {Array<boolean>} colorMask + * @param {tcuTexture.PixelBufferAccess} colorBuffer + */ +rrFragmentOperations.executeSignedValueWrite = function(inputFragments, colorMask, colorBuffer) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var fragSampleNdx = 0; + var originalValue = colorBuffer.getPixelInt(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + var newValue = tcuTextureUtil.select(frag.signedValue, originalValue, colorMask); + + colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } +}; + +/** + * @param {Array<rrFragmentOperations.Fragment>} inputFragments + * @param {Array<boolean>} colorMask + * @param {tcuTexture.PixelBufferAccess} colorBuffer + */ +rrFragmentOperations.executeUnsignedValueWrite = function(inputFragments, colorMask, colorBuffer) { + for (var i = 0; i < inputFragments.length; i++) { + var frag = inputFragments[i]; + if (frag.isAlive) { + var fragSampleNdx = 0; + var originalValue = colorBuffer.getPixelInt(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + var newValue = tcuTextureUtil.select(frag.unsignedValue, originalValue, colorMask); + + colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]); + } + } +}; + +/** + * @constructor + */ +rrFragmentOperations.FragmentProcessor = function() { + /* TODO: implement */ +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrGenericVector.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrGenericVector.js new file mode 100644 index 0000000000..62a92a4227 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrGenericVector.js @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrGenericVector'); + +goog.scope(function() { + +var rrGenericVector = framework.referencerenderer.rrGenericVector; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + /** + * rrGenericVector.GenericVecType + * @enum + */ + rrGenericVector.GenericVecType = { + FLOAT: 0, + UINT32: 1, + INT32: 2 + }; + + /** + * @constructor + * @param {number=} a + * @param {number=} b + * @param {number=} c + * @param {number=} d + */ + rrGenericVector.GenericVec4 = function(a, b, c, d) { + this.data = [a || 0, b || 0, c || 0, d || 0]; + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrMultisamplePixelBufferAccess.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrMultisamplePixelBufferAccess.js new file mode 100644 index 0000000000..6de1ca2701 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrMultisamplePixelBufferAccess.js @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrMultisamplePixelBufferAccess'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); + +goog.scope(function() { + +var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess; +var tcuTexture = framework.common.tcuTexture; +var deMath = framework.delibs.debase.deMath; +var tcuTextureUtil = framework.common.tcuTextureUtil; + +var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); +}; + +/** + * \brief Read-write pixel data access to multisampled buffers. + * + * Multisampled data access follows the multisampled indexing convention. + * + * Prevents accidental usage of non-multisampled buffer as multisampled + * with PixelBufferAccess. + * @constructor + * @param {tcuTexture.PixelBufferAccess=} rawAccess + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess = function(rawAccess) { + this.m_access = rawAccess || new tcuTexture.PixelBufferAccess({ + width: 0, + height: 0}); +}; + +/** + * @return {tcuTexture.PixelBufferAccess} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.raw = function() { return this.m_access; }; + +/** + * @return {boolean} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.isEmpty = function() { return this.m_access.isEmpty(); }; + +/** + * @return {number} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.getNumSamples = function() { return this.raw().getWidth(); }; + +/** + * @return {tcuTexture.PixelBufferAccess} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.toSinglesampleAccess = function() { + DE_ASSERT(this.getNumSamples() == 1); + + return new tcuTexture.PixelBufferAccess({ + format: this.m_access.getFormat(), + width: this.m_access.getHeight(), + height: this.m_access.getDepth(), + depth: 1, + rowPitch: this.m_access.getSlicePitch(), + slicePitch: this.m_access.getSlicePitch() * this.m_access.getDepth(), + data: this.m_access.m_data, + offset: this.m_access.m_offset}); +}; + +/** + * @param {tcuTexture.PixelBufferAccess} original + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess = function(original) { + return new rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess( + new tcuTexture.PixelBufferAccess({ + format: original.getFormat(), + width: 1, + height: original.getWidth(), + depth: original.getHeight(), + rowPitch: original.getFormat().getPixelSize(), + slicePitch: original.getRowPitch(), + data: original.m_data, + offset: original.m_offset})); +}; + +/** + * @param {tcuTexture.PixelBufferAccess} multisampledAccess + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess = function(multisampledAccess) { + return new rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess(multisampledAccess); +}; + +/** + * @param {Array<number>} region + * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.getSubregion = function(region) { + var x = region[0]; + var y = region[1]; + var width = region[2]; + var height = region[3]; + + return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(tcuTextureUtil.getSubregion(this.raw(), 0, x, y, this.getNumSamples(), width, height)); +}; + +/** + * @return {Array<number>} [x, y, width, height] + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.getBufferSize = function() { + return [0, 0, this.raw().getHeight(), this.raw().getDepth()]; +}; + +/** + * @param {tcuTexture.PixelBufferAccess} dst + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.resolveMultisampleColorBuffer = function(dst) { + var src = this; + DE_ASSERT(dst.getWidth() == src.raw().getHeight()); + DE_ASSERT(dst.getHeight() == src.raw().getDepth()); + + var numSamples = src.getNumSamples(); + var sum = [0, 0, 0, 0]; + for (var y = 0; y < dst.getHeight(); y++) { + for (var x = 0; x < dst.getWidth(); x++) { + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + + for (var s = 0; s < src.raw().getWidth(); s++) { + var pixel = src.raw().getPixel(s, x, y); + sum[0] += pixel[0]; + sum[1] += pixel[1]; + sum[2] += pixel[2]; + sum[3] += pixel[3]; + } + + sum[0] /= numSamples; + sum[1] /= numSamples; + sum[2] /= numSamples; + sum[3] /= numSamples; + + dst.setPixel(sum, x, y); + } + } +}; + +/** + * @param {number} x + * @param {number} y + * @return {Array<number>} + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.resolveMultisamplePixel = function(x, y) { + var sum = [0, 0, 0, 0]; + for (var s = 0; s < this.getNumSamples(); s++) + sum = deMath.add(sum, this.raw().getPixel(s, x, y)); + + for (var i = 0; i < sum.length; i++) + sum[i] = sum[i] / this.getNumSamples(); + + return sum; +}; + +/** + * @param {Array<number>} color + */ +rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.prototype.clear = function(color) { + this.raw().clear(color); +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderState.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderState.js new file mode 100644 index 0000000000..cac4dc56a3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderState.js @@ -0,0 +1,323 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program Reference Renderer + * ----------------------------------------------- + * + * 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 renderer render state. + *//*--------------------------------------------------------------------*/ +'use strict'; +goog.provide('framework.referencerenderer.rrRenderState'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess'); + +goog.scope(function() { + +var rrRenderState = framework.referencerenderer.rrRenderState; +var tcuTexture = framework.common.tcuTexture; +var deMath = framework.delibs.debase.deMath; +var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess; +var rrDefs = framework.referencerenderer.rrDefs; + +/** + * Enum for rrRenderState.HorizontalFill values. + * @enum {number} + */ +rrRenderState.HorizontalFill = { + LEFT: 0, + RIGHT: 1 +}; + +/** + * Enum for rrRenderState.VerticalFill values. + * @enum {number} + */ +rrRenderState.VerticalFill = { + TOP: 0, + BOTTOM: 1 +}; + +/** + * Enum for rrRenderState.Winding values. + * @enum {number} + */ +rrRenderState.Winding = { + CCW: 0, + CC: 1 +}; + +/** + * Enum for rrRenderState.CullMode values. + * @enum {number} + */ +rrRenderState.CullMode = { + NONE: 0, + BACK: 1, + FRONT: 2 +}; + +/**rrRenderState.Winding : rrRenderState.Winding, + + * @constructor + */ +rrRenderState.RasterizationState = function() { + /** @type {number} */ this.winding = rrRenderState.Winding.CCW; + /** @type {number} */ this.horizontalFill = rrRenderState.HorizontalFill.LEFT; + /** @type {number} */ this.verticalFill = rrRenderState.VerticalFill.BOTTOM; +}; + +/** + * Enum for rrRenderState.TestFunc values. + * @enum {number} + */ +rrRenderState.TestFunc = { + NEVER: 0, + ALWAYS: 1, + LESS: 2, + LEQUAL: 3, + GREATER: 4, + GEQUAL: 5, + EQUAL: 6, + NOTEQUAL: 7 +}; + +/** + * Enum for rrRenderState.StencilOp values. + * @enum {number} + */ +rrRenderState.StencilOp = { + KEEP: 0, + ZERO: 1, + REPLACE: 2, + INCR: 3, //!< Increment with saturation. + DECR: 4, //!< Decrement with saturation. + INCR_WRAP: 5, + DECR_WRAP: 6, + INVERT: 7 +}; + +/** + * Enum for rrRenderState.BlendMode values. + * @enum {number} + */ +rrRenderState.BlendMode = { + NONE: 0, //!< No blending. + STANDARD: 1 //!< Standard blending. +// Advanced blending is not supported +// ADVANCED : 2 //!< Advanced blending mode, as defined in gl.KHR_blend_equation_advanced. +}; + +/** + * Enum for rrRenderState.BlendEquation values. + * @enum {number} + */ +rrRenderState.BlendEquation = { + ADD: 0, + SUBTRACT: 1, + REVERSE_SUBTRACT: 2, + MIN: 3, + MAX: 4 +}; + +// /** +// * Enum for rrRenderState.BlendEquationAdvanced values. +// * @enum {number} +// */ +// rrRenderState.BlendEquationAdvanced = { +// MULTIPLY : 0, +// SCREEN : 1, +// OVERLAY : 2, +// DARKEN : 3, +// LIGHTEN : 4, +// COLORDODGE : 5, +// COLORBURN : 6, +// HARDLIGHT : 7, +// SOFTLIGHT : 8, +// DIFFERENCE : 9, +// EXCLUSION : 10, +// HSL_HUE : 11, +// HSL_SATURATION : 12, +// HSL_COLOR : 13, +// HSL_LUMINOSITY : 14 +// }; + +/** + * Enum for rrRenderState.BlendFunc values. + * @enum {number} + */ +rrRenderState.BlendFunc = { + ZERO: 0, + ONE: 1, + SRC_COLOR: 2, + ONE_MINUS_SRC_COLOR: 3, + DST_COLOR: 4, + ONE_MINUS_DST_COLOR: 5, + SRC_ALPHA: 6, + ONE_MINUS_SRC_ALPHA: 7, + DST_ALPHA: 8, + ONE_MINUS_DST_ALPHA: 9, + CONSTANT_COLOR: 10, + ONE_MINUS_CONSTANT_COLOR: 11, + CONSTANT_ALPHA: 12, + ONE_MINUS_CONSTANT_ALPHA: 13, + SRC_ALPHA_SATURATE: 14, + SRC1_COLOR: 15, + ONE_MINUS_SRC1_COLOR: 16, + SRC1_ALPHA: 17, + ONE_MINUS_SRC1_ALPHA: 18 +}; + +/** + * @constructor + */ +rrRenderState.StencilState = function() { + /** @type {number} */ this.func = rrRenderState.TestFunc.ALWAYS; + /** @type {number} */ this.ref = 0; + /** @type {number} */ this.compMask = ~0; + /** @type {number} */ this.sFail = rrRenderState.StencilOp.KEEP; + /** @type {number} */ this.dpFail = rrRenderState.StencilOp.KEEP; + /** @type {number} */ this.dpPass = rrRenderState.StencilOp.KEEP; + /** @type {number} */ this.writeMask = ~0; +}; + +/** + * @constructor + */ +rrRenderState.BlendState = function() { + /** @type {number} */ this.equation = rrRenderState.BlendEquation.ADD; + /** @type {number} */ this.srcFunc = rrRenderState.BlendFunc.ONE; + /** @type {number} */ this.dstFunc = rrRenderState.BlendFunc.ZERO; +}; + +/** + * @param {(Array<number>|number)} left_ + * @param {number=} bottom_ + * @param {number=} width_ + * @param {number=} height_ + * @constructor + */ +rrRenderState.WindowRectangle = function(left_, bottom_, width_, height_) { + // Is first parameter an array? Use it + if (left_.length && left_.length == 4) { + this.left = left_[0]; + this.bottom = left_[1]; + this.width = left_[2]; + this.height = left_[3]; + } else { + this.left = left_; + this.bottom = bottom_; + this.width = width_; + this.height = height_; + } +}; + +/** + * @constructor + */ +rrRenderState.FragmentOperationState = function() { + /** @type {boolean} */ this.scissorTestEnabled = false; + /** @type {rrRenderState.WindowRectangle} */ this.scissorRectangle = new rrRenderState.WindowRectangle(0, 0, 1, 1); + + /** @type {boolean} */ this.stencilTestEnabled = false; + + /** @type {Array<rrRenderState.StencilState>} */ this.stencilStates = []; + for (var type in rrDefs.FaceType) + this.stencilStates[rrDefs.FaceType[type]] = new rrRenderState.StencilState(); + + /** @type {boolean} */ this.depthTestEnabled = false; + /** @type {rrRenderState.TestFunc} */ this.depthFunc = rrRenderState.TestFunc.LESS; + /** @type {boolean} */ this.depthMask = true; + + /** @type {rrRenderState.BlendMode} */ this.blendMode = rrRenderState.BlendMode.NONE; + /** @type {rrRenderState.BlendState} */ this.blendRGBState = new rrRenderState.BlendState(); + /** @type {rrRenderState.BlendState} */ this.blendAState = new rrRenderState.BlendState(); + /** @type {Array<number>} */ this.blendColor = [0.0, 0.0, 0.0, 0.0]; +// /** @type {rrRenderState.BlendEquationAdvanced} */ this.blendEquationAdvanced = null; + + /** @type {boolean} */ this.sRGBEnabled = true; + + /** @type {boolean} */ this.depthClampEnabled = false; + + /** @type {boolean} */ this.polygonOffsetEnabled = false; + /** @type {number} */ this.polygonOffsetFactor = 0.0; + /** @type {number} */ this.polygonOffsetUnits = 0.0; + + /** @type {Array<boolean>} */ this.colorMask = [true, true, true, true]; + + /** @type {number} */ this.numStencilBits = 8; +}; + +/** + * @constructor + */ +rrRenderState.PointState = function() { + /** @type {number} */ this.pointSize = 1.0; +}; + +/** + * @constructor + */ +rrRenderState.LineState = function() { + /** @type {number} */ this.lineWidth = 1.0; +}; + +/** + * Constructor checks if the parameter has a "raw" member to detect if the instance is + * of type rrRenderState.WindowRectangle or MultisamplePixelBufferAccess. + * @param {rrRenderState.WindowRectangle|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} rect_ + * @constructor + */ +rrRenderState.ViewportState = function(rect_) { + /** @type {number} */ this.zn = 0.0; + /** @type {number} */ this.zf = 1.0; + /** @type {rrRenderState.WindowRectangle} */ this.rect; + + if (rect_.raw) { + this.rect = new rrRenderState.WindowRectangle(0, 0, rect_.raw().getHeight(), + rect_.raw().getDepth()); + } else { + this.rect = /** @type {rrRenderState.WindowRectangle} */ (rect_); + } +}; + +/** + * @constructor + */ +rrRenderState.RestartState = function() { + /** @type {boolean} */ this.enabled = false; + /** @type {number} */ this.restartIndex = 0xFFFFFFFF; +}; + +/** + * @constructor + * @param {rrRenderState.ViewportState} viewport_ + */ +rrRenderState.RenderState = function(viewport_) { + /** @type {rrRenderState.CullMode} */ this.cullMode = rrRenderState.CullMode.NONE; + /** @type {number} */ this.provokingVertexConvention; + /** @type {rrRenderState.ViewportState} */ this.viewport = viewport_; + + /** @type {rrRenderState.RasterizationState} */ this.rasterization = new rrRenderState.RasterizationState(); + /** @type {rrRenderState.FragmentOperationState} */ this.fragOps = new rrRenderState.FragmentOperationState(); + /** @type {rrRenderState.PointState} */ this.point = new rrRenderState.PointState(); + /** @type {rrRenderState.LineState} */ this.line = new rrRenderState.LineState(); + /** @type {rrRenderState.RestartState} */ this.restart = new rrRenderState.RestartState(); +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderer.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderer.js new file mode 100644 index 0000000000..4d5752b2c4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderer.js @@ -0,0 +1,1274 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrRenderer'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.common.tcuTextureUtil'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.delibs.debase.deString'); +goog.require('framework.delibs.debase.deUtil'); +goog.require('framework.opengl.simplereference.sglrShaderProgram'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrFragmentOperations'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess'); +goog.require('framework.referencerenderer.rrRenderState'); +goog.require('framework.referencerenderer.rrShadingContext'); +goog.require('framework.referencerenderer.rrVertexAttrib'); +goog.require('framework.referencerenderer.rrVertexPacket'); + +goog.scope(function() { + +var rrRenderer = framework.referencerenderer.rrRenderer; +var rrVertexPacket = framework.referencerenderer.rrVertexPacket; +var rrDefs = framework.referencerenderer.rrDefs; +var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations; +var deMath = framework.delibs.debase.deMath; +var tcuTextureUtil = framework.common.tcuTextureUtil; +var tcuTexture = framework.common.tcuTexture; +var rrRenderState = framework.referencerenderer.rrRenderState; +var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess; +var rrShadingContext = framework.referencerenderer.rrShadingContext; +var rrGenericVector = framework.referencerenderer.rrGenericVector; +var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram; +var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; +var deString = framework.delibs.debase.deString; +var deUtil = framework.delibs.debase.deUtil; + +/** + * @enum + */ +rrRenderer.PrimitiveType = { + TRIANGLES: 0, //!< Separate rrRenderer.triangles + TRIANGLE_STRIP: 1, //!< rrRenderer.Triangle strip + TRIANGLE_FAN: 2, //!< rrRenderer.Triangle fan + + LINES: 3, //!< Separate lines + LINE_STRIP: 4, //!< Line strip + LINE_LOOP: 5, //!< Line loop + + POINTS: 6 //!< Points +}; + +// /** +// * @constructor +// * @param {boolean} depthEnabled Is depth buffer enabled +// */ +// rrRenderer.RasterizationInternalBuffers = function(depthEnabled) { +// /*std::vector<rrFragmentOperations.Fragment>*/ this.fragmentPackets = []; +// /*std::vector<GenericVec4>*/ this.shaderOutputs = []; +// /*std::vector<Fragment>*/ this.shadedFragments = []; +// /*float**/ this.fragmentDepthBuffer = depthEnabled ? [] : null; +// }; + +/** + * @constructor + * @param {number=} id + */ +rrRenderer.DrawContext = function(id) { + this.primitiveID = id || 0; + +}; + +/** + * Transform [x, y] to window (pixel) coordinates. + * z and w are unchanged + * @param {rrRenderState.RenderState} state + * @param {rrVertexPacket.VertexPacket} packet + * Wreturn {Array<number>} + */ +rrRenderer.transformGLToWindowCoords = function(state, packet) { + var transformed = [packet.position[0] / packet.position[3], + packet.position[1] / packet.position[3], + packet.position[2], + packet.position[3]]; + var viewport = state.viewport.rect; + var halfW = viewport.width / 2; + var halfH = viewport.height / 2; + var oX = viewport.left + halfW; + var oY = viewport.bottom + halfH; + + return [ + transformed[0] * halfW + oX, + transformed[1] * halfH + oY, + transformed[2], + transformed[3] + ]; +}; + +/** + * @constructor + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} colorMultisampleBuffer + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess=} depthMultisampleBuffer + * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess=} stencilMultisampleBuffer + */ +rrRenderer.RenderTarget = function(colorMultisampleBuffer, depthMultisampleBuffer, stencilMultisampleBuffer) { + this.MAX_COLOR_BUFFERS = 4; + this.colorBuffers = []; + this.colorBuffers[0] = colorMultisampleBuffer; + this.depthBuffer = depthMultisampleBuffer || new rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess(); + this.stencilBuffer = stencilMultisampleBuffer || new rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess(); + this.numColorBuffers = 1; +}; + +// NOTE: Program object is useless. Let's just use the sglrShaderProgram +// /** +// * @constructor +// * @param {rrShaders.VertexShader} vertexShader_ +// * @param {rrShaders.FragmentShader} fragmentShader_ +// */ +// var Program = function(vertexShader_, fragmentShader_) { +// this.vertexShader = vertexShader_; +// this.fragmentShader = fragmentShader_; +// }; + +/** + * @constructor + * @param {ArrayBuffer} data + * @param {rrDefs.IndexType} type + * @param {number} offset + * @param {number=} baseVertex_ + */ +rrRenderer.DrawIndices = function(data, type, offset, baseVertex_) { + /** @type {ArrayBuffer} */ this.data = data; + /** @type {number} */ this.baseVertex = baseVertex_ || 0; + /** @type {rrDefs.IndexType} */ this.indexType = type; + /** @type {goog.NumberArray} */ this.access = null; + switch (type) { + case rrDefs.IndexType.INDEXTYPE_UINT8: this.access = new Uint8Array(data).subarray(offset); break; + case rrDefs.IndexType.INDEXTYPE_UINT16: this.access = new Uint16Array(data).subarray(offset / 2); break; + case rrDefs.IndexType.INDEXTYPE_UINT32: this.access = new Uint32Array(data).subarray(offset / 4); break; + default: throw new Error('Invalid type: ' + type); + } +}; + +/** + * @return {number} + */ +rrRenderer.DrawIndices.prototype.readIndexArray = function(index) { return this.access[index]; }; + +/** + * @constructor + * @param {rrRenderer.PrimitiveType} primitiveType + * @param {number} numElements + * @param {(number|rrRenderer.DrawIndices)} indices + */ +rrRenderer.PrimitiveList = function(primitiveType, numElements, indices) { + /** @type {rrRenderer.PrimitiveType} */ this.m_primitiveType = primitiveType; + /** @type {number} */ this.m_numElements = numElements; + if (typeof indices == 'number') { + // !< primitive list for drawArrays-like call + this.m_indices = null; + this.m_indexType = null; + this.m_baseVertex = indices; + } else { + // !< primitive list for drawElements-like call + this.m_indices = indices; + this.m_indexType = indices.indexType; + this.m_baseVertex = indices.baseVertex; + } + this.m_iterator = 0; +}; + +/** + * @param {number} elementNdx + * @return {number} + */ +rrRenderer.PrimitiveList.prototype.getIndex = function(elementNdx) { + if (this.m_indices) { + var index = this.m_baseVertex + this.m_indices.readIndexArray(elementNdx); + if (index < 0) + throw new Error('Index must not be negative'); + + return index; + } else + return this.m_baseVertex + elementNdx; +}; + +/** + * @param {number} elementNdx + * @param {number} restartIndex + * @return {boolean} + */ +rrRenderer.PrimitiveList.prototype.isRestartIndex = function(elementNdx, restartIndex) { + // implicit index or explicit index (without base vertex) equals restart + if (this.m_indices) + return this.m_indices.readIndexArray(elementNdx) == restartIndex; + else + return elementNdx == restartIndex; +}; + +/** + * @return {number} + */ +rrRenderer.PrimitiveList.prototype.getNumElements = function() {return this.m_numElements;}; + +/** + * @return {rrRenderer.PrimitiveType} + */ +rrRenderer.PrimitiveList.prototype.getPrimitiveType = function() {return this.m_primitiveType;}; + +/** + * @return {?rrDefs.IndexType} + */ +rrRenderer.PrimitiveList.prototype.getIndexType = function() {return this.m_indexType;}; + +/** + * Generate a primitive from indices + * @param {boolean=} reset Restart generating primitives. Default false + * @return {Array<number>} + */ +rrRenderer.PrimitiveList.prototype.getNextPrimitive = function(reset) { + if (reset) + this.m_iterator = 0; + var result = []; + var i = this.m_iterator; + switch (this.m_primitiveType) { + case rrRenderer.PrimitiveType.TRIANGLES: + if (this.m_iterator + 3 <= this.m_numElements) { + result = [i, i + 1, i + 2]; + this.m_iterator += 3; + } + break; + case rrRenderer.PrimitiveType.TRIANGLE_STRIP: + if (this.m_iterator + 3 <= this.m_numElements) { + result = [i, i + 1, i + 2]; + this.m_iterator += 1; + } + break; + case rrRenderer.PrimitiveType.TRIANGLE_FAN: + if (this.m_iterator + 3 <= this.m_numElements) { + result = [0, i + 1, i + 2]; + this.m_iterator += 1; + } + break; + case rrRenderer.PrimitiveType.LINES: + if (this.m_iterator + 2 <= this.m_numElements) { + result = [i, i + 1]; + this.m_iterator += 2; + } + break; + case rrRenderer.PrimitiveType.LINE_STRIP: + if (this.m_iterator + 2 <= this.m_numElements) { + result = [i, i + 1]; + this.m_iterator += 1; + } + break; + case rrRenderer.PrimitiveType.LINE_LOOP: + if (this.m_iterator == this.m_numElements) + break; + if (this.m_iterator + 2 <= this.m_numElements) + result = [i, i + 1]; + else + result = [i, 0]; + this.m_iterator += 1; + break; + case rrRenderer.PrimitiveType.POINTS: + if (this.m_iterator == this.m_numElements) + break; + else + result = [i]; + this.m_iterator += 1; + break; + default: + throw new Error('Unsupported primitive type: ' + deString.enumToString(rrRenderer.PrimitiveType, this.m_primitiveType)); + } + + return result; +}; + +/** + * @param {rrRenderState.RenderState} state + * @param {rrRenderer.RenderTarget} renderTarget + * @param {Array<rrFragmentOperations.Fragment>} fragments Fragments to write +*/ +rrRenderer.writeFragments = function(state, renderTarget, fragments) { + /* TODO: Add blending, depth, stencil ... */ + var colorbuffer = renderTarget.colorBuffers[0].raw(); + for (var i = 0; i < fragments.length; i++) { + var fragment = fragments[i]; + colorbuffer.setPixel(fragment.value, 0, fragment.pixelCoord[0], fragment.pixelCoord[1]); + } + +}; + +/** + * @param {rrRenderState.RenderState} renderState + * @param {rrRenderer.RenderTarget} renderTarget + * @param {Array<rrFragmentOperations.Fragment>} fragments Fragments to write +*/ +rrRenderer.writeFragments2 = function(renderState, renderTarget, fragments) { + /* +void FragmentProcessor::render (const rr::MultisamplePixelBufferAccess& msColorBuffer, + const rr::MultisamplePixelBufferAccess& msDepthBuffer, + const rr::MultisamplePixelBufferAccess& msStencilBuffer, + const Fragment* fragments, + int numFragments, + FaceType fragmentFacing, + const FragmentOperationState& state) +*/ + + /** @const */ var fragmentFacing = rrDefs.FaceType.FACETYPE_FRONT; + var colorBuffer = renderTarget.colorBuffers[0].raw(); + var depthBuffer = renderTarget.depthBuffer.raw(); + var stencilBuffer = renderTarget.stencilBuffer.raw(); + var state = renderState.fragOps; + + var hasDepth = depthBuffer.getWidth() > 0 && depthBuffer.getHeight() > 0 && depthBuffer.getDepth() > 0; + var hasStencil = stencilBuffer.getWidth() > 0 && stencilBuffer.getHeight() > 0 && stencilBuffer.getDepth() > 0; + var doDepthTest = hasDepth && state.depthTestEnabled; + var doStencilTest = hasStencil && state.stencilTestEnabled; + + var colorbufferClass = tcuTexture.getTextureChannelClass(colorBuffer.getFormat().type); + var fragmentDataType = rrGenericVector.GenericVecType.FLOAT; + switch (colorbufferClass) { + case tcuTexture.TextureChannelClass.SIGNED_INTEGER: + fragmentDataType = rrGenericVector.GenericVecType.INT32; + break; + case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER: + fragmentDataType = rrGenericVector.GenericVecType.UINT32; + break; + } + + if (!((!hasDepth || colorBuffer.getWidth() == depthBuffer.getWidth()) && (!hasStencil || colorBuffer.getWidth() == stencilBuffer.getWidth()))) + throw new Error('Attachment must have the same width'); + if (!((!hasDepth || colorBuffer.getHeight() == depthBuffer.getHeight()) && (!hasStencil || colorBuffer.getHeight() == stencilBuffer.getHeight()))) + throw new Error('Attachment must have the same height'); + if (!((!hasDepth || colorBuffer.getDepth() == depthBuffer.getDepth()) && (!hasStencil || colorBuffer.getDepth() == stencilBuffer.getDepth()))) + throw new Error('Attachment must have the same depth'); + + var stencilState = state.stencilStates[fragmentFacing]; + var colorMaskFactor = [state.colorMask[0] ? 1 : 0, state.colorMask[1] ? 1 : 0, state.colorMask[2] ? 1 : 0, state.colorMask[3] ? 1 : 0]; + var colorMaskNegationFactor = [state.colorMask[0] ? false : true, state.colorMask[1] ? false : true, state.colorMask[2] ? false : true, state.colorMask[3] ? false : true]; + var sRGBTarget = state.sRGBEnabled && colorBuffer.getFormat().isSRGB(); + + // Scissor test. + + if (state.scissorTestEnabled) + rrFragmentOperations.executeScissorTest(fragments, state.scissorRectangle); + + // Stencil test. + + if (doStencilTest) { + rrFragmentOperations.executeStencilCompare(fragments, stencilState, state.numStencilBits, stencilBuffer); + rrFragmentOperations.executeStencilSFail(fragments, stencilState, state.numStencilBits, stencilBuffer); + } + + // Depth test. + // \note Current value of isAlive is needed for dpPass and dpFail, so it's only updated after them and not right after depth test. + + if (doDepthTest) { + rrFragmentOperations.executeDepthCompare(fragments, state.depthFunc, depthBuffer); + + if (state.depthMask) + rrFragmentOperations.executeDepthWrite(fragments, depthBuffer); + } + + // Do dpFail and dpPass stencil writes. + + if (doStencilTest) + rrFragmentOperations.executeStencilDpFailAndPass(fragments, stencilState, state.numStencilBits, stencilBuffer); + + // Kill the samples that failed depth test. + + if (doDepthTest) { + for (var i = 0; i < fragments.length; i++) + fragments[i].isAlive = fragments[i].isAlive && fragments[i].depthPassed; + } + + // Paint fragments to target + + switch (fragmentDataType) { + case rrGenericVector.GenericVecType.FLOAT: + // Blend calculation - only if using blend. + if (state.blendMode == rrRenderState.BlendMode.STANDARD) { + // Put dst color to register, doing srgb-to-linear conversion if needed. + for (var i = 0; i < fragments.length; i++) { + var frag = fragments[i]; + if (frag.isAlive) { + var dstColor = colorBuffer.getPixel(0, frag.pixelCoord[0], frag.pixelCoord[1]); + + /* TODO: Check frag.value and frag.value1 types */ + frag.clampedBlendSrcColor = deMath.clampVector(frag.value, 0, 1); + frag.clampedBlendSrc1Color = deMath.clampVector(frag.value1, 0, 1); + frag.clampedBlendDstColor = deMath.clampVector(sRGBTarget ? tcuTexture.sRGBToLinear(dstColor) : dstColor, 0, 1); + } + } + + // Calculate blend factors to register. + rrFragmentOperations.executeBlendFactorComputeRGB(fragments, state.blendColor, state.blendRGBState); + rrFragmentOperations.executeBlendFactorComputeA(fragments, state.blendColor, state.blendAState); + + // Compute blended color. + rrFragmentOperations.executeBlend(fragments, state.blendRGBState, state.blendAState); + } else { + // Not using blend - just put values to register as-is. + + for (var i = 0; i < fragments.length; i++) { + var frag = fragments[i]; + if (frag.isAlive) { + frag.blendedRGB = deMath.swizzle(frag.value, [0, 1, 2]); + frag.blendedA = frag.value[3]; + } + } + } + + // Finally, write the colors to the color buffer. + + if (state.colorMask[0] && state.colorMask[1] && state.colorMask[2] && state.colorMask[3]) { + /* TODO: Add quick path */ + // if (colorBuffer.getFormat().isEqual(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8))) + // executeRGBA8ColorWrite(fragments, colorBuffer); + // else + rrFragmentOperations.executeColorWrite(fragments, sRGBTarget, colorBuffer); + } else if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3]) + rrFragmentOperations.executeMaskedColorWrite(fragments, colorMaskFactor, colorMaskNegationFactor, sRGBTarget, colorBuffer); + break; + + case rrGenericVector.GenericVecType.INT32: + // Write fragments + for (var i = 0; i < fragments.length; i++) { + var frag = fragments[i]; + if (frag.isAlive) { + frag.signedValue = frag.value; + } + } + + if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3]) + rrFragmentOperations.executeSignedValueWrite(fragments, state.colorMask, colorBuffer); + break; + + case rrGenericVector.GenericVecType.UINT32: + // Write fragments + for (var i = 0; i < fragments.length; i++) { + var frag = fragments[i]; + if (frag.isAlive) { + frag.unsignedValue = frag.value; + } + } + + if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3]) + rrFragmentOperations.executeUnsignedValueWrite(fragments, state.colorMask, colorBuffer); + break; + + default: + throw new Error('Unrecognized fragment data type:' + fragmentDataType); + } +}; + +/** + * Determines the index of the corresponding vertex according to top/right conditions. + * @param {boolean} isTop + * @param {boolean} isRight + * @return {number} + */ +rrRenderer.getIndexOfCorner = function(isTop, isRight, vertexPackets) { + var x = null; + var y = null; + + var xcriteria = isRight ? Math.max : Math.min; + var ycriteria = isTop ? Math.max : Math.min; + + // Determine corner values + for (var i = 0; i < vertexPackets.length; i++) { + x = x != null ? xcriteria(vertexPackets[i].position[0], x) : vertexPackets[i].position[0]; + y = y != null ? ycriteria(vertexPackets[i].position[1], y) : vertexPackets[i].position[1]; + } + + // Search for matching vertex + for (var v = 0; v < vertexPackets.length; v++) + if (vertexPackets[v].position[0] == x && + vertexPackets[v].position[1] == y) + return v; + + throw new Error('Corner not found'); +}; + +/** + * Check that point is in the clipping volume + * @param {number} x + * @param {number} y + * @param {number} z + * @param {rrRenderState.WindowRectangle} rect + * @return {boolean} + */ +rrRenderer.clipTest = function(x, y, z, rect) { + x = Math.round(x); + y = Math.round(y); + if (!deMath.deInBounds32(x, rect.left, rect.left + rect.width)) + return false; + if (!deMath.deInBounds32(y, rect.bottom, rect.bottom + rect.height)) + return false; + if (z < 0 || z > 1) + return false; + return true; +}; + +// Rasterizer configuration +rrRenderer.RASTERIZER_SUBPIXEL_BITS = 8; +rrRenderer.RASTERIZER_MAX_SAMPLES_PER_FRAGMENT = 16; + +// Referenced from rrRasterizer.hpp + +/** + * Get coverage bit value + * @param {number} numSamples + * @param {number} x + * @param {number} y + * @param {number} sampleNdx + * @return {number} + */ +rrRenderer.getCoverageBit = function(numSamples, x, y, sampleNdx) { + var maxSamples = 16; + assertMsgOptions(maxSamples >= rrRenderer.RASTERIZER_MAX_SAMPLES_PER_FRAGMENT, 'maxSamples should not greater than ' + rrRenderer.RASTERIZER_MAX_SAMPLES_PER_FRAGMENT, false, true); + assertMsgOptions(deMath.deInRange32(numSamples, 1, maxSamples) && deMath.deInBounds32(x, 0, 2) && deMath.deInBounds32(y, 0, 2), 'numSamples, x or y not in bound', false, true); + return 1 << ((x * 2 + y) * numSamples + sampleNdx); +}; + +/** + * Get all sample bits for fragment + * @param {number} numSamples + * @param {number} x + * @param {number} y + * @return {number} + */ +rrRenderer.getCoverageFragmentSampleBits = function(numSamples, x, y) { + assertMsgOptions(deMath.deInBounds32(x, 0, 2) && deMath.deInBounds32(y, 0, 2), 'x or y is not in bound 0 to 2', false, true); + var fragMask = (1 << numSamples) - 1; + return fragMask << (x * 2 + y) * numSamples; +}; + +/** + * Set coverage bit in coverage mask + * @param {number} mask + * @param {number} numSamples + * @param {number} x + * @param {number} y + * @param {number} sampleNdx + * @param {number} val + * @return {number} + */ +rrRenderer.setCoverageValue = function(mask, numSamples, x, y, sampleNdx, val) { + var bit = rrRenderer.getCoverageBit(numSamples, x, y, sampleNdx); + return val ? (mask | bit) : (mask & ~bit); +}; + +/** + * Test if any sample for fragment is live + * @param {number} mask + * @param {number} numSamples + * @param {number} x + * @param {number} y + * @return {number} + */ +rrRenderer.getCoverageAnyFragmentSampleLive = function(mask, numSamples, x, y) { + return (mask & rrRenderer.getCoverageFragmentSampleBits(numSamples, x, y)) != 0; +}; + +// Referenced from rrRasterizer.cpp + +/** + * Pixel coord to sub pixel coord + * @param {number} v + * @return {number} + */ +rrRenderer.toSubpixelCoord = function(v) { + return Math.trunc(v * (1 << rrRenderer.RASTERIZER_SUBPIXEL_BITS) + (v < 0 ? -0.5 : 0.5)); +}; + +/** + * Floor sub pixel coord to pixel coord + * @param {number} coord + * @param {boolean} fillEdge + * @return {number} + */ +rrRenderer.floorSubpixelToPixelCoord = function(coord, fillEdge) { + if (coord >= 0) + return Math.trunc((coord - (fillEdge ? 1 : 0)) >> rrRenderer.RASTERIZER_SUBPIXEL_BITS); + else + return Math.trunc((coord - ((1 << rrRenderer.RASTERIZER_SUBPIXEL_BITS) - (fillEdge ? 0 : 1))) >> rrRenderer.RASTERIZER_SUBPIXEL_BITS); +}; + +/** + * Ceil sub pixel coord to pixel coord + * @param {number} coord + * @param {boolean} fillEdge + * @return {number} + */ +rrRenderer.ceilSubpixelToPixelCoord = function(coord, fillEdge) { + if (coord >= 0) + return Math.trunc((coord + (1 << rrRenderer.RASTERIZER_SUBPIXEL_BITS) - (fillEdge ? 0 : 1)) >> rrRenderer.RASTERIZER_SUBPIXEL_BITS); + else + return Math.trunc((coord + (fillEdge ? 1 : 0)) >> rrRenderer.RASTERIZER_SUBPIXEL_BITS); +}; + +/** + * \brief Edge function - referenced from struct EdgeFunction in rrRasterizer.hpp + * + * Edge function can be evaluated for point P (in a fixed-point coordinates + * with RASTERIZER_SUBPIXEL_BITS fractional part) by computing + * D = a * Px + b * Py + c + * + * D will be fixed-point value where lower (RASTERIZER_SUBPIXEL_BITS * 2) bits + * will be fractional part. + * + * Member function evaluateEdge, reverseEdge and isInsideCCW are referenced from rrRasterizer.cpp. + * + * @param {number} a + * @param {number} b + * @param {number} c + * @param {boolean} inclusive + */ +rrRenderer.edgeFunction = function(a, b, c, inclusive) { + this.a = a; + this.b = b; + this.c = c; + this.inclusive = inclusive; // True if edge is inclusive according to fill rules +}; + +/** + * Evaluate point (x,y) + * @param {number} x + * @param {number} y + * @return {number} + */ +rrRenderer.edgeFunction.prototype.evaluateEdge = function(x, y) { + return this.a * x + this.b * y + this.c; +}; + +/** + * Reverse edge (e.g. from CCW to CW) + */ +rrRenderer.edgeFunction.prototype.reverseEdge = function () { + this.a = -this.a; + this.b = -this.b; + this.c = -this.c; + this.inclusive = !this.inclusive; +}; + +/** + * Determine if a point with value edgeVal is inside the CCW region of the edge + * @param {number} edgeVal + * @return {boolean} + */ +rrRenderer.edgeFunction.prototype.isInsideCCW = function(edgeVal) { + return this.inclusive ? edgeVal >= 0 : edgeVal > 0; +}; + +/** + * Init an edge function in counter-clockwise (CCW) orientation + * @param {number} horizontalFill + * @param {number} verticalFill + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @return {rrRenderer.edgeFunction} + */ +rrRenderer.initEdgeCCW = function(horizontalFill, verticalFill, x0, y0, x1, y1) { + var xd = x1 - x0; + var yd = y1 - y0; + var inclusive = false; + + if (yd == 0) + inclusive = verticalFill == rrRenderState.VerticalFill.BOTTOM ? xd >= 0 : xd <= 0; + else + inclusive = horizontalFill == rrRenderState.HorizontalFill.LEFT ? yd <= 0 : yd >=0; + + return new rrRenderer.edgeFunction(y0 - y1, x1 - x0, x0 * y1 - y0 * x1, inclusive); +}; + +/** + * \brief Triangle rasterizer - referenced from class TriangleRasterizer in rrRasterizer.hpp + * + * Triangle rasterizer implements following features: + * - Rasterization using fixed-point coordinates + * - 1-sample rasterization (the value of numSamples always equals 1 in sglrReferenceContext) + * - Depth interpolation + * - Perspective-correct barycentric computation for interpolation + * - Visible face determination + * - Clipping - native dEQP does clipping before rasterization; see function drawBasicPrimitives + * in rrRenderer.cpp for more details + * + * It does not (and will not) implement following: + * - Triangle setup + * - Degenerate elimination + * - Coordinate transformation (inputs are in screen-space) + * - Culling - logic can be implemented outside by querying visible face + * - Scissoring - (this can be done by controlling viewport rectangle) + * - Any per-fragment operations + * + * @param {rrRenderState.RenderState} state + */ +rrRenderer.triangleRasterizer = function(state) { + this.m_viewport = state.viewport; + this.m_winding = state.rasterization.winding; + this.m_horizontalFill = state.rasterization.horizontalFill; + this.m_verticalFill = state.rasterization.verticalFill; +}; + +/** + * Initialize triangle rasterization + * @param {vec} v0 Screen-space coordinates (x, y, z) and 1/w for vertex 0 + * @param {vec} v1 Screen-space coordinates (x, y, z) and 1/w for vertex 1 + * @param {vec} v2 Screen-space coordinates (x, y, z) and 1/w for vertex 2 + */ +rrRenderer.triangleRasterizer.prototype.init = function(v0, v1, v2) { + this.m_v0 = v0; + this.m_v1 = v1; + this.m_v2 = v2; + + // Positions in fixed-point coordinates + var x0 = rrRenderer.toSubpixelCoord(v0[0]); + var y0 = rrRenderer.toSubpixelCoord(v0[1]); + var x1 = rrRenderer.toSubpixelCoord(v1[0]); + var y1 = rrRenderer.toSubpixelCoord(v1[1]); + var x2 = rrRenderer.toSubpixelCoord(v2[0]); + var y2 = rrRenderer.toSubpixelCoord(v2[1]); + + // Initialize edge functions + if (this.m_winding == rrRenderState.Winding.CCW) { + this.m_edge01 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x0, y0, x1, y1); + this.m_edge12 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x1, y1, x2, y2); + this.m_edge20 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x2, y2, x0, y0); + } else { + // Reverse edges + this.m_edge01 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x1, y1, x0, y0); + this.m_edge12 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x2, y2, x1, y1); + this.m_edge20 = rrRenderer.initEdgeCCW(this.m_horizontalFill, this.m_verticalFill, x0, y0, x2, y2); + } + + // Determine face + var s = this.m_edge01.evaluateEdge(x2, y2); + var positiveArea = (this.m_winding == rrRenderState.Winding.CCW ) ? s > 0 : s < 0; + this.m_face = positiveArea ? rrDefs.FaceType.FACETYPE_FRONT : rrDefs.FaceType.FACETYPE_BACK; + if (!positiveArea) { + // Reverse edges so that we can use CCW area tests & interpolation + this.m_edge01.reverseEdge(); + this.m_edge12.reverseEdge(); + this.m_edge20.reverseEdge(); + } + + // Bounding box + var minX = Math.min(x0, x1, x2); + var maxX = Math.max(x0, x1, x2); + var minY = Math.min(y0, y1, y2); + var maxY = Math.max(y0, y1, y2); + + this.m_bboxMin = []; + this.m_bboxMax = []; + this.m_bboxMin[0] = rrRenderer.floorSubpixelToPixelCoord(minX, this.m_horizontalFill == rrRenderState.HorizontalFill.LEFT); + this.m_bboxMin[1] = rrRenderer.floorSubpixelToPixelCoord(minY, this.m_verticalFill == rrRenderState.VerticalFill.BOTTOM); + this.m_bboxMax[0] = rrRenderer.ceilSubpixelToPixelCoord(maxX, this.m_horizontalFill == rrRenderState.HorizontalFill.RIGHT); + this.m_bboxMax[1] = rrRenderer.ceilSubpixelToPixelCoord(maxY, this.m_verticalFill == rrRenderState.VerticalFill.TOP); + + // Clamp to viewport + var wX0 = this.m_viewport.rect.left; + var wY0 = this.m_viewport.rect.bottom; + var wX1 = wX0 + this.m_viewport.rect.width - 1; + var wY1 = wY0 + this.m_viewport.rect.height - 1; + + this.m_bboxMin[0] = deMath.clamp(this.m_bboxMin[0], wX0, wX1); + this.m_bboxMin[1] = deMath.clamp(this.m_bboxMin[1], wY0, wY1); + this.m_bboxMax[0] = deMath.clamp(this.m_bboxMax[0], wX0, wX1); + this.m_bboxMax[1] = deMath.clamp(this.m_bboxMax[1], wY0, wY1); + + this.m_curPos = [this.m_bboxMin[0], this.m_bboxMin[1]]; +}; + +rrRenderer.triangleRasterizer.prototype.rasterize = function() { + var fragmentPackets = []; + var halfPixel = 1 << (rrRenderer.RASTERIZER_SUBPIXEL_BITS - 1); + + // For depth interpolation; given barycentrics A, B, C = (1 - A -B) + // We can reformulate the usual z = z0 * A + z1 * B + z2 * C into more + // stable equation z = A * (z0 - z2) + B * (z1 - z2) + z2 + var za = this.m_v0[2] - this.m_v2[2]; + var zb = this.m_v1[2] - this.m_v2[2]; + var zc = this.m_v2[2]; + + var zn = this.m_viewport.zn; + var zf = this.m_viewport.zf; + var depthScale = (zf - zn) / 2; + var depthBias = (zf + zn) / 2; + + while (this.m_curPos[1] <= this.m_bboxMax[1]) { + var x0 = this.m_curPos[0]; + var y0 = this.m_curPos[1]; + + // Subpixel coords of (x0, y0), (x0 + 1, y0), (x0, y0 + 1), (x0 + 1, y0 + 1) + var sx0 = rrRenderer.toSubpixelCoord(x0) + halfPixel; + var sx1 = rrRenderer.toSubpixelCoord(x0 + 1) + halfPixel; + var sy0 = rrRenderer.toSubpixelCoord(y0) + halfPixel; + var sy1 = rrRenderer.toSubpixelCoord(y0 + 1) + halfPixel; + + var sx = [sx0, sx1, sx0, sx1]; + var sy = [sy0, sy0, sy1, sy1]; + + // Viewport test + var outX1 = x0 + 1 == this.m_viewport.rect.left + this.m_viewport.rect.width; + var outY1 = y0 + 1 == this.m_viewport.rect.bottom + this.m_viewport.rect.height; + + // Coverage + var coverage = 0; + + // Evaluate edge values + var e01 = []; + var e12 = []; + var e20 = []; + for (var i = 0; i < 4; i++) { + e01.push(this.m_edge01.evaluateEdge(sx[i], sy[i])); + e12.push(this.m_edge12.evaluateEdge(sx[i], sy[i])); + e20.push(this.m_edge20.evaluateEdge(sx[i], sy[i])); + } + + // Compute coverage mask + coverage = rrRenderer.setCoverageValue(coverage, 1, 0, 0, 0, this.m_edge01.isInsideCCW(e01[0]) && this.m_edge12.isInsideCCW(e12[0]) && this.m_edge20.isInsideCCW(e20[0])); + coverage = rrRenderer.setCoverageValue(coverage, 1, 1, 0, 0, !outX1 && this.m_edge01.isInsideCCW(e01[1]) && this.m_edge12.isInsideCCW(e12[1]) && this.m_edge20.isInsideCCW(e20[1])); + coverage = rrRenderer.setCoverageValue(coverage, 1, 0, 1, 0, !outY1 && this.m_edge01.isInsideCCW(e01[2]) && this.m_edge12.isInsideCCW(e12[2]) && this.m_edge20.isInsideCCW(e20[2])); + coverage = rrRenderer.setCoverageValue(coverage, 1, 1, 1, 0, !outX1 && !outY1 && this.m_edge01.isInsideCCW(e01[3]) && this.m_edge12.isInsideCCW(e12[3]) && this.m_edge20.isInsideCCW(e20[3])); + + // Advance to next location + this.m_curPos[0] += 2; + if (this.m_curPos[0] > this.m_bboxMax[0]) { + this.m_curPos[0] = this.m_bboxMin[0]; + this.m_curPos[1] += 2; + } + + if (coverage == 0) + continue; // Discard + + // Compute depth and barycentric coordinates + var edgeSum = deMath.add(deMath.add(e01, e12), e20); + var z0 = deMath.divide(e12, edgeSum); + var z1 = deMath.divide(e20, edgeSum); + + var b0 = deMath.multiply(e12, [this.m_v0[3], this.m_v0[3], this.m_v0[3], this.m_v0[3]]); + var b1 = deMath.multiply(e20, [this.m_v1[3], this.m_v1[3], this.m_v1[3], this.m_v1[3]]); + var b2 = deMath.multiply(e01, [this.m_v2[3], this.m_v2[3], this.m_v2[3], this.m_v2[3]]); + var bSum = deMath.add(deMath.add(b0, b1), b2); + var barycentric0 = deMath.divide(b0, bSum); + var barycentric1 = deMath.divide(b1, bSum); + var barycentric2 = deMath.subtract(deMath.subtract([1, 1, 1, 1], barycentric0), barycentric1); + + // In native dEQP, after rasterization, the pixel (x0, y0) actually represents four pixels: + // (x0, y0), (x0 + 1, y0), (x0, y0 + 1) and (x0 + 1, y0 + 1). + // The barycentrics and depths of these four pixels are to be computed after rasterization: + // barycentrics are computed in function shadeFragments in es3fFboTestUtil.cpp; + // depths are computed in function writeFragmentPackets in rrRenderer.cpp. + + // In js, pixels are processed one after another, so their depths and barycentrics should be computed immediately. + + // Determine if (x0, y0), (x0 + 1, y0), (x0, y0 + 1), (x0 + 1, y0 + 1) can be rendered + for (var fragNdx = 0; fragNdx < 4; fragNdx++) { + var xo = fragNdx % 2; + var yo = Math.trunc(fragNdx / 2); + var x = x0 + xo; + var y = y0 + yo; + + // The value of numSamples always equals 1 in sglrReferenceContext. + if(rrRenderer.getCoverageAnyFragmentSampleLive(coverage, 1, xo, yo)) { + // Barycentric coordinates - referenced from function readTriangleVarying in rrShadingContext.hpp + var b = [barycentric0[fragNdx], barycentric1[fragNdx], barycentric2[fragNdx]]; + + // Depth - referenced from writeFragmentPackets in rrRenderer.cpp + var depth = z0[fragNdx] * za + z1[fragNdx] * zb + zc; + depth = depth * depthScale + depthBias; + + // Clip test + // Native dEQP does clipping test before rasterization. + if (!rrRenderer.clipTest(x, y, depth, this.m_viewport.rect)) + continue; + + fragmentPackets.push(new rrFragmentOperations.Fragment(b, [x, y], depth)); + } + } + } + return fragmentPackets; +}; + +/** + * @param {rrRenderState.RenderState} state + * @param {rrRenderer.RenderTarget} renderTarget + * @param {sglrShaderProgram.ShaderProgram} program + * @param {Array<rrVertexAttrib.VertexAttrib>} vertexAttribs + * @param {rrRenderer.PrimitiveType} primitive + * @param {(number|rrRenderer.DrawIndices)} first Index of first quad vertex + * @param {number} count Number of indices + * @param {number} instanceID + */ +rrRenderer.drawTriangles = function(state, renderTarget, program, vertexAttribs, primitive, first, count, instanceID) { + + /** + * @param {Array<rrVertexPacket.VertexPacket>} vertices + * @param {Array<number>} indices + * @return {Array<rrVertexPacket.VertexPacket>} + */ + var selectVertices = function(vertices, indices) { + var result = []; + for (var i = 0; i < indices.length; i++) + result.push(vertices[indices[i]]); + return result; + }; + + // Referenced from native dEQP Renderer::drawInstanced() in rrRenderer.cpp + + var primitives = new rrRenderer.PrimitiveList(primitive, count, first); + // Do not draw if nothing to draw + if (primitives.getNumElements() == 0) + return; + + // Prepare transformation + var numVaryings = program.vertexShader.getOutputs().length; + var vpalloc = new rrVertexPacket.VertexPacketAllocator(numVaryings); + var vertexPackets = vpalloc.allocArray(primitives.getNumElements()); + var drawContext = new rrRenderer.DrawContext(); + drawContext.primitiveID = 0; + + var numberOfVertices = primitives.getNumElements(); + var numVertexPackets = 0; + for (var elementNdx = 0; elementNdx < numberOfVertices; ++elementNdx) { + + // input + vertexPackets[numVertexPackets].instanceNdx = instanceID; + vertexPackets[numVertexPackets].vertexNdx = primitives.getIndex(elementNdx); + + // output + vertexPackets[numVertexPackets].pointSize = state.point.pointSize; // default value from the current state + vertexPackets[numVertexPackets].position = [0, 0, 0, 0]; // no undefined values + + ++numVertexPackets; + + } + program.shadeVertices(vertexAttribs, vertexPackets, numVertexPackets); + + // Referenced from native dEQP Renderer::rasterizePrimitive() for triangle rasterization in rrRenderer.cpp + + // In native dEQP, only maxFragmentPackets packets are processed per rasterize-shade-write loop; + // in js all packets are processed in one loop. + + var rasterizer = new rrRenderer.triangleRasterizer(state); + + for (var prim = primitives.getNextPrimitive(true); prim.length > 0; prim = primitives.getNextPrimitive()) { + var vertices = selectVertices(vertexPackets, prim); + + var v0 = rrRenderer.transformGLToWindowCoords(state, vertices[0]); + var v1 = rrRenderer.transformGLToWindowCoords(state, vertices[1]); + var v2 = rrRenderer.transformGLToWindowCoords(state, vertices[2]); + + rasterizer.init(v0, v1, v2); + + // Culling + if ((state.cullMode == rrRenderState.CullMode.FRONT && rasterizer.m_face == rrDefs.FaceType.FACETYPE_FRONT) || + (state.cullMode == rrRenderState.CullMode.BACK && rasterizer.m_face == rrDefs.FaceType.FACETYPE_BACK)) + return; + + /* TODO: Add Polygon Offset and Depth Clamp */ + + // Compute a conservative integer bounding box for the triangle + var minX = Math.floor(Math.min(v0[0], v1[0], v2[0])); + var maxX = Math.ceil(Math.max(v0[0], v1[0], v2[0])); + var minY = Math.floor(Math.min(v0[1], v1[1], v2[1])); + var maxY = Math.ceil(Math.max(v0[1], v1[1], v2[1])); + + // Shading context + var shadingContext = new rrShadingContext.FragmentShadingContext( + vertices[0].outputs, + vertices[1].outputs, + vertices[2].outputs + ); + shadingContext.setSize(maxX - minX, maxY - minY); + + // Rasterize + var fragmentPackets = rasterizer.rasterize(); + + // Shade + program.shadeFragments(fragmentPackets, shadingContext); + + // Handle fragment shader outputs + rrRenderer.writeFragments2(state, renderTarget, fragmentPackets); + } +}; + +/** + * @param {rrRenderState.RenderState} state + * @param {rrRenderer.RenderTarget} renderTarget + * @param {sglrShaderProgram.ShaderProgram} program + * @param {Array<rrVertexAttrib.VertexAttrib>} vertexAttribs + * @param {rrRenderer.PrimitiveType} primitive + * @param {(number|rrRenderer.DrawIndices)} first Index of first quad vertex + * @param {number} count Number of indices + * @param {number} instanceID + */ +rrRenderer.drawLines = function(state, renderTarget, program, vertexAttribs, primitive, first, count, instanceID) { + + /** + * @param {Array<rrVertexPacket.VertexPacket>} vertices + * @param {Array<number>} indices + * @return {Array<rrVertexPacket.VertexPacket>} + */ + var selectVertices = function(vertices, indices) { + var result = []; + for (var i = 0; i < indices.length; i++) + result.push(vertices[indices[i]]); + return result; + }; + + var lengthSquared = function(a) { + var sqSum = 0; + for (var i = 0; i < a.length; i++) + sqSum += a[i] * a[i]; + return sqSum; + }; + + var dot = function(a, b) { + var res = 0; + for (var i = 0; i < a.length; i++) + res += a[i] * b[i]; + return res; + }; + + var rasterizeLine = function(v0, v1) { + var d = [ + Math.abs(v1[0] - v0[0]), + Math.abs(v1[1] - v0[1])]; + var xstep = v0[0] < v1[0] ? 1 : -1; + var ystep = v0[1] < v1[1] ? 1 : -1; + var x = v0[0]; + var y = v0[1]; + var offset = d[0] - d[1]; + var lenV = [v1[0] - v0[0], v1[1] - v0[1]]; + var lenSq = lengthSquared(lenV); + + var packets = []; + + while (true) { + var t = dot([x - v0[0], y - v0[1]], lenV) / lenSq; + var depth = (1 - t) * v0[2] + t * v1[2]; + var b = [0, 0, 0]; + b[0] = 1 - t; + b[1] = t; + + if (x == v1[0] && y == v1[1]) + break; + + depth = depth * depthScale + depthBias; + packets.push(new rrFragmentOperations.Fragment(b, [x, y], depth)); + + var offset2 = 2 * offset; + if (offset2 > -1 * d[1]) { + x += xstep; + offset -= d[1]; + } + + if (offset2 < d[0]) { + y += ystep; + offset += d[0]; + } + } + return packets; + }; + + var primitives = new rrRenderer.PrimitiveList(primitive, count, first); + // Do not draw if nothing to draw + if (primitives.getNumElements() == 0) + return; + + // Prepare transformation + var numVaryings = program.vertexShader.getOutputs().length; + var vpalloc = new rrVertexPacket.VertexPacketAllocator(numVaryings); + var vertexPackets = vpalloc.allocArray(primitives.getNumElements()); + var drawContext = new rrRenderer.DrawContext(); + drawContext.primitiveID = 0; + + var numberOfVertices = primitives.getNumElements(); + var numVertexPackets = 0; + for (var elementNdx = 0; elementNdx < numberOfVertices; ++elementNdx) { + + // input + vertexPackets[numVertexPackets].instanceNdx = instanceID; + vertexPackets[numVertexPackets].vertexNdx = primitives.getIndex(elementNdx); + + // output + vertexPackets[numVertexPackets].pointSize = state.point.pointSize; // default value from the current state + vertexPackets[numVertexPackets].position = [0, 0, 0, 0]; // no undefined values + + ++numVertexPackets; + + } + program.shadeVertices(vertexAttribs, vertexPackets, numVertexPackets); + + var zn = state.viewport.zn; + var zf = state.viewport.zf; + var depthScale = (zf - zn) / 2; + var depthBias = (zf + zn) / 2; + + // For each quad, we get a group of six vertex packets + for (var prim = primitives.getNextPrimitive(true); prim.length > 0; prim = primitives.getNextPrimitive()) { + var linePackets = selectVertices(vertexPackets, prim); + + var v0 = rrRenderer.transformGLToWindowCoords(state, linePackets[0]); + var v1 = rrRenderer.transformGLToWindowCoords(state, linePackets[1]); + v0[2] = linePackets[0].position[2]; + v1[2] = linePackets[1].position[2]; + + v0[0] = Math.floor(v0[0]); + v0[1] = Math.floor(v0[1]); + v1[0] = Math.floor(v1[0]); + v1[1] = Math.floor(v1[1]); + + var lineWidth = state.line.lineWidth; + + var shadingContext = new rrShadingContext.FragmentShadingContext( + linePackets[0].outputs, + linePackets[1].outputs, + null + ); + var isXmajor = Math.abs(v1[0] - v0[0]) >= Math.abs(v1[1] - v0[1]); + var packets = []; + if (isXmajor) + packets = rasterizeLine([v0[0], v0[1] - (lineWidth - 1) / 2, v0[2]], + [v1[0], v1[1] - (lineWidth - 1) / 2, v1[2]]); + else + packets = rasterizeLine([v0[0] - (lineWidth - 1) / 2, v0[1], v0[2]], + [v1[0] - (lineWidth - 1) / 2, v1[1], v1[2]]); + var numPackets = packets.length; + if (lineWidth > 1) + for (var i = 0; i < numPackets; i++) { + var p = packets[i]; + for (var j = 1; j < lineWidth; j++) { + var p2 = deUtil.clone(p); + if (isXmajor) + p2.pixelCoord[1] += j; + else + p2.pixelCoord[0] += j; + packets.push(p2); + } + } + + var clipped = []; + for (var i = 0; i < packets.length; i++) { + var p = packets[i]; + if (rrRenderer.clipTest(p.pixelCoord[0], p.pixelCoord[1], p.sampleDepths[0], state.viewport.rect)) + clipped.push(p); + } + program.shadeFragments(clipped, shadingContext); + + rrRenderer.writeFragments2(state, renderTarget, clipped); + } +}; + +/** + * @param {rrRenderState.RenderState} state + * @param {rrRenderer.RenderTarget} renderTarget + * @param {sglrShaderProgram.ShaderProgram} program + * @param {Array<rrVertexAttrib.VertexAttrib>} vertexAttribs + * @param {rrRenderer.PrimitiveType} primitive + * @param {(number|rrRenderer.DrawIndices)} first Index of first quad vertex + * @param {number} count Number of indices + * @param {number} instanceID + */ +rrRenderer.drawPoints = function(state, renderTarget, program, vertexAttribs, primitive, first, count, instanceID) { + /** + * @param {Array<rrVertexPacket.VertexPacket>} vertices + * @param {Array<number>} indices + * @return {Array<rrVertexPacket.VertexPacket>} + */ + var selectVertices = function(vertices, indices) { + var result = []; + for (var i = 0; i < indices.length; i++) + result.push(vertices[indices[i]]); + return result; + }; + + var primitives = new rrRenderer.PrimitiveList(primitive, count, first); + // Do not draw if nothing to draw + if (primitives.getNumElements() == 0) + return; + + // Prepare transformation + var numVaryings = program.vertexShader.getOutputs().length; + var vpalloc = new rrVertexPacket.VertexPacketAllocator(numVaryings); + var vertexPackets = vpalloc.allocArray(primitives.getNumElements()); + var drawContext = new rrRenderer.DrawContext(); + drawContext.primitiveID = 0; + + var numberOfVertices = primitives.getNumElements(); + var numVertexPackets = 0; + for (var elementNdx = 0; elementNdx < numberOfVertices; ++elementNdx) { + + // input + vertexPackets[numVertexPackets].instanceNdx = instanceID; + vertexPackets[numVertexPackets].vertexNdx = primitives.getIndex(elementNdx); + + // output + vertexPackets[numVertexPackets].pointSize = state.point.pointSize; // default value from the current state + vertexPackets[numVertexPackets].position = [0, 0, 0, 0]; // no undefined values + + ++numVertexPackets; + + } + program.shadeVertices(vertexAttribs, vertexPackets, numVertexPackets); + + var zn = state.viewport.zn; + var zf = state.viewport.zf; + var depthScale = (zf - zn) / 2; + var depthBias = (zf + zn) / 2; + + // For each primitive, we draw a point. + for (var prim = primitives.getNextPrimitive(true); prim.length > 0; prim = primitives.getNextPrimitive()) { + var pointPackets = selectVertices(vertexPackets, prim); + + var v0 = rrRenderer.transformGLToWindowCoords(state, pointPackets[0]); + v0[2] = pointPackets[0].position[2]; + var pointSize = pointPackets[0].pointSize; + + var shadingContext = new rrShadingContext.FragmentShadingContext( + pointPackets[0].outputs, + null, + null + ); + var packets = []; + + var x = v0[0]; + var y = v0[1]; + var depth = v0[2]; + var b = [1, 0, 0]; + depth = depth * depthScale + depthBias; + + for (var i = Math.floor(x - pointSize / 2); i < x + pointSize / 2; i++) { + for (var j = Math.floor(y - pointSize / 2); j < y + pointSize / 2; j++) { + var centerX = i + 0.5; + var centerY = j + 0.5; + if (Math.abs(centerX - x) <= pointSize / 2 && + Math.abs(centerY - y) <= pointSize / 2 && + rrRenderer.clipTest(i, j, depth, state.viewport.rect)) + packets.push(new rrFragmentOperations.Fragment(b, [i, j], depth)); + } + } + + program.shadeFragments(packets, shadingContext); + + rrRenderer.writeFragments2(state, renderTarget, packets); + } +}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShaders.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShaders.js new file mode 100644 index 0000000000..143d9b7289 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShaders.js @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrShaders'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrGenericVector'); +goog.require('framework.referencerenderer.rrShadingContext'); +goog.require('framework.referencerenderer.rrVertexAttrib'); +goog.require('framework.referencerenderer.rrVertexPacket'); + +goog.scope(function() { + +var rrShaders = framework.referencerenderer.rrShaders; +var tcuTexture = framework.common.tcuTexture; +var deMath = framework.delibs.debase.deMath; +var rrGenericVector = framework.referencerenderer.rrGenericVector; +var rrShadingContext = framework.referencerenderer.rrShadingContext; +var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; +var rrVertexPacket = framework.referencerenderer.rrVertexPacket; + + /** + * Vertex shader input information + * @constructor + */ + rrShaders.VertexInputInfo = function() { + /** @type {rrGenericVector.GenericVecType} */ this.type; + }; + + /** + * Shader varying information + * @constructor + */ + rrShaders.VertexVaryingInfo = function() { + /** @type {rrGenericVector.GenericVecType} */ this.type; + /** @type {boolean} */ var flatshade = false; + }; + + /** + * Fragment shader output information + * @constructor + */ + rrShaders.FragmentOutputInfo = function() { + //Sensible defaults + /** @type {rrGenericVector.GenericVecType} */ this.type; + }; + + /** + * Vertex shader interface + * + * Vertex shaders execute shading for set of vertex packets. See VertexPacket + * documentation for more details on shading API. + * @constructor + * @param {number} numInputs + * @param {number} numOutputs + */ + rrShaders.VertexShader = function(numInputs, numOutputs) { + /** @type {Array<rrShaders.VertexInputInfo>} */ this.m_inputs = []; + for (var ndx = 0; ndx < numInputs; ndx++) this.m_inputs[ndx] = new rrShaders.VertexInputInfo(); + /** @type {Array<rrShaders.VertexVaryingInfo>} */ this.m_outputs = []; + for (var ndx = 0; ndx < numOutputs; ndx++) this.m_outputs[ndx] = new rrShaders.VertexVaryingInfo(); + }; + + /** + * getInputs + * @return {Array<rrShaders.VertexInputInfo>} + */ + rrShaders.VertexShader.prototype.getInputs = function() {return this.m_inputs;}; + + /** + * getOutputs + * @return {Array<rrShaders.VertexVaryingInfo>} + */ + rrShaders.VertexShader.prototype.getOutputs = function() {return this.m_outputs;}; + + /** + * Fragment shader interface + * + * Fragment shader executes shading for list of fragment packets. See + * FragmentPacket documentation for more details on shading API. + * @constructor + * @param {number} numInputs + * @param {number} numOutputs + */ + rrShaders.FragmentShader = function(numInputs, numOutputs) { + /** @type {Array<rrShaders.VertexVaryingInfo>} */ this.m_inputs = []; + for (var ndx = 0; ndx < numInputs; ndx++) this.m_inputs[ndx] = new rrShaders.VertexVaryingInfo(); + /** @type {Array<rrShaders.FragmentOutputInfo>} */ this.m_outputs = []; + for (var ndx = 0; ndx < numOutputs; ndx++) this.m_outputs[ndx] = new rrShaders.FragmentOutputInfo(); + /** @type {*} */ this.m_container; // owner object + }; + + /** + * getInputs + * @return {Array<rrShaders.VertexVaryingInfo>} + */ + rrShaders.FragmentShader.prototype.getInputs = function() {return this.m_inputs;}; + + /** + * getOutputs + * @return {Array<rrShaders.FragmentOutputInfo>} + */ + rrShaders.FragmentShader.prototype.getOutputs = function() {return this.m_outputs;}; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShadingContext.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShadingContext.js new file mode 100644 index 0000000000..38b9d201f9 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShadingContext.js @@ -0,0 +1,113 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrShadingContext'); +goog.require('framework.referencerenderer.rrFragmentOperations'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrDefs'); +goog.require('framework.referencerenderer.rrFragmentOperations'); +goog.require('framework.referencerenderer.rrGenericVector'); + +goog.scope(function() { + + var rrShadingContext = framework.referencerenderer.rrShadingContext; + var deMath = framework.delibs.debase.deMath; + var rrDefs = framework.referencerenderer.rrDefs; + var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations; + var rrGenericVector = framework.referencerenderer.rrGenericVector; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + /** + * Fragment shading context + * + * Contains per-primitive information used in fragment shading + * @constructor + * @param {Array<Array<number>>} varying0 (GenericVec4*) + * @param {Array<Array<number>>} varying1 (GenericVec4*) + * @param {Array<Array<number>>} varying2 (GenericVec4*) + */ + rrShadingContext.FragmentShadingContext = function(varying0, varying1, varying2) { + /** @type {Array<Array<Array<number>>>} */ this.varyings = [varying0, varying1, varying2]; //!< Vertex shader outputs. Pointer will be NULL if there is no such vertex. + this.m_width = 0xFFFFFFFF; + this.m_height = 0xFFFFFFFF; + }; + + /** + * @param {number} width + * @param {number} height + */ + rrShadingContext.FragmentShadingContext.prototype.setSize = function(width, height) { + this.m_width = width; + this.m_height = height; + }; + + rrShadingContext.FragmentShadingContext.prototype.getWidth = function() { + return this.m_width; + }; + + rrShadingContext.FragmentShadingContext.prototype.getHeight = function() { + return this.m_height; + }; + + // Read Varying + + /** + * @param {rrFragmentOperations.Fragment} packet + * @param {rrShadingContext.FragmentShadingContext} context + * @param {number} varyingLoc + * @return {Array<number>} (Vector<T, 4>) + */ + rrShadingContext.readTriangleVarying = function(packet, context, varyingLoc) { + var result = deMath.scale( + context.varyings[0][varyingLoc], + packet.barycentric[0] + ); + + if (context.varyings[1]) + result = deMath.add(result, deMath.scale( + context.varyings[1][varyingLoc], + packet.barycentric[1] + )); + + if (context.varyings[2]) + result = deMath.add(result, deMath.scale( + context.varyings[2][varyingLoc], + packet.barycentric[2] + )); + + return result; + }; + + /** + * @param {rrFragmentOperations.Fragment} packet + * @param {rrShadingContext.FragmentShadingContext} context + * @param {number} varyingLoc + * @return {Array<number>} (Vector<T, 4>) + */ + rrShadingContext.readVarying = function(packet, context, varyingLoc) { + return rrShadingContext.readTriangleVarying(packet, context, varyingLoc); + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrUtil.js new file mode 100644 index 0000000000..03a58168fc --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrUtil.js @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrUtil'); +goog.require('framework.opengl.simplereference.sglrGLContext'); +goog.require('framework.opengl.simplereference.sglrReferenceContext'); + +goog.scope(function() { + + var rrUtil = framework.referencerenderer.rrUtil; + var sglrGLContext = framework.opengl.simplereference.sglrGLContext; + var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext; + + /** + * @param {sglrGLContext.GLContext | WebGL2RenderingContext | sglrReferenceContext.ReferenceContext} ctx + * @param {number|Object} program + * @param {Array<number>} p0 + * @param {Array<number>} p1 + */ + rrUtil.drawQuad = function(ctx, program, p0, p1) { + // Vertex data. + var hz = (p0[2] + p1[2]) * 0.5; + /** @type {Array<number>} */ var position = [ + p0[0], p0[1], p0[2], 1.0, + p0[0], p1[1], hz, 1.0, + p1[0], p0[1], hz, 1.0, + p1[0], p1[1], p1[2], 1.0 + ]; + /** @type {Array<number>} */ var coord = [ + 0.0, 0.0, + 0.0, 1.0, + 1.0, 0.0, + 1.0, 1.0 + ]; + /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3]; + + var posLoc = ctx.getAttribLocation(program, 'a_position'); + if (posLoc == -1) + throw new Error('a_position attribute is not defined.'); + + var coordLoc = ctx.getAttribLocation(program, 'a_coord'); + var vaoID; + var bufIDs = []; + + vaoID = ctx.createVertexArray(); + ctx.bindVertexArray(vaoID); + + bufIDs[0] = ctx.createBuffer(); + bufIDs[1] = ctx.createBuffer(); + + ctx.useProgram(program); + + if (posLoc >= 0) { + ctx.bindBuffer(gl.ARRAY_BUFFER, bufIDs[0]); + ctx.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW); + + ctx.enableVertexAttribArray(posLoc); + ctx.vertexAttribPointer(posLoc, 4, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, null); + } + + if (coordLoc >= 0) { + ctx.bindBuffer(gl.ARRAY_BUFFER, bufIDs[1]); + ctx.bufferData(gl.ARRAY_BUFFER, new Float32Array(coord), gl.STATIC_DRAW); + + ctx.enableVertexAttribArray(coordLoc); + ctx.vertexAttribPointer(coordLoc, 2, gl.FLOAT, false, 0, 0); + + ctx.bindBuffer(gl.ARRAY_BUFFER, null); + } + + { + var ndxID = ctx.createBuffer(); + + ctx.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ndxID); + ctx.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); + + ctx.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + + ctx.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + ctx.deleteBuffer(ndxID); + } + + ctx.bindVertexArray(null); + ctx.deleteBuffer(bufIDs[0]); + ctx.deleteBuffer(bufIDs[1]); + ctx.deleteVertexArray(vaoID); + + if (posLoc >= 0) + ctx.disableVertexAttribArray(posLoc); + + if (coordLoc >= 0) + ctx.disableVertexAttribArray(coordLoc); + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexAttrib.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexAttrib.js new file mode 100644 index 0000000000..f6095e2cc9 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexAttrib.js @@ -0,0 +1,641 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrVertexAttrib'); +goog.require('framework.common.tcuFloat'); +goog.require('framework.delibs.debase.deMath'); +goog.require('framework.referencerenderer.rrGenericVector'); + +goog.scope(function() { + +var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib; +var deMath = framework.delibs.debase.deMath; +var tcuFloat = framework.common.tcuFloat; +var rrGenericVector = framework.referencerenderer.rrGenericVector; + + var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); + }; + + /** + * rrVertexAttrib.NormalOrder + * @enum + */ + rrVertexAttrib.NormalOrder = { + T0: 0, + T1: 1, + T2: 2, + T3: 3 + }; + + /** + * rrVertexAttrib.BGRAOrder + * @enum + */ + rrVertexAttrib.BGRAOrder = { + T0: 2, + T1: 1, + T2: 0, + T3: 3 + }; + + /** + * rrVertexAttrib.VertexAttribType enum + * @enum + */ + rrVertexAttrib.VertexAttribType = { + // Can only be rrVertexAttrib.read as floats + FLOAT: 0, + HALF: 1, + FIXED: 2, + DOUBLE: 3, + + // Can only be rrVertexAttrib.read as floats, will be normalized + NONPURE_UNORM8: 4, + NONPURE_UNORM16: 5, + NONPURE_UNORM32: 6, + NONPURE_UNORM_2_10_10_10_REV: 7, //!< Packed format, only size = 4 is allowed + + // Clamped formats, GLES3-style conversion: max{c / (2^(b-1) - 1), -1 } + NONPURE_SNORM8_CLAMP: 8, + NONPURE_SNORM16_CLAMP: 9, + NONPURE_SNORM32_CLAMP: 10, + NONPURE_SNORM_2_10_10_10_REV_CLAMP: 11, //!< Packed format, only size = 4 is allowed + + // Scaled formats, GLES2-style conversion: (2c + 1) / (2^b - 1) + NONPURE_SNORM8_SCALE: 12, + NONPURE_SNORM16_SCALE: 13, + NONPURE_SNORM32_SCALE: 14, + NONPURE_SNORM_2_10_10_10_REV_SCALE: 15, //!< Packed format, only size = 4 is allowed + + // can only be rrVertexAttrib.read as float, will not be normalized + NONPURE_UINT8: 16, + NONPURE_UINT16: 17, + NONPURE_UINT32: 18, + + NONPURE_INT8: 19, + NONPURE_INT16: 20, + NONPURE_INT32: 21, + + NONPURE_UINT_2_10_10_10_REV: 22, //!< Packed format, only size = 4 is allowed + NONPURE_INT_2_10_10_10_REV: 23, //!< Packed format, only size = 4 is allowed + + // can only be rrVertexAttrib.read as integers + PURE_UINT8: 24, + PURE_UINT16: 25, + PURE_UINT32: 26, + + PURE_INT8: 27, + PURE_INT16: 28, + PURE_INT32: 29, + + // reordered formats of gl.ARB_vertex_array_bgra + NONPURE_UNORM8_BGRA: 30, + NONPURE_UNORM_2_10_10_10_REV_BGRA: 31, + NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA: 32, + NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA: 33, + + // can be rrVertexAttrib.read as anything + DONT_CARE: 34 //!< Do not enforce type checking when reading GENERIC attribute. Used for current client side attributes. + }; + + /** + * rrVertexAttrib.VertexAttrib class + * @constructor + */ + rrVertexAttrib.VertexAttrib = function() { + /** @type {rrVertexAttrib.VertexAttribType} */ this.type = rrVertexAttrib.VertexAttribType.FLOAT; + /** @type {number} */ this.size = 0; + /** @type {number} */ this.stride = 0; + /** @type {number} */ this.instanceDivisor = 0; + /** @type {number} */ this.offset = 0; //Added this property to compensate functionality (not in original dEQP). + /** @type {ArrayBuffer} */ this.pointer = null; + /** @type {Array<number>|rrGenericVector.GenericVec4} */ this.generic; //!< Generic attribute, used if pointer is null. + }; + + /** + * @param {rrVertexAttrib.VertexAttribType} type + * @return {number} + */ + rrVertexAttrib.getComponentSize = function(type) { + switch (type) { + case rrVertexAttrib.VertexAttribType.FLOAT: return 4; + case rrVertexAttrib.VertexAttribType.HALF: return 2; + case rrVertexAttrib.VertexAttribType.FIXED: return 4; + case rrVertexAttrib.VertexAttribType.DOUBLE: return 8; //sizeof(double); + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM8: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM16: return 2; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM32: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_CLAMP: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_CLAMP: return 2; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_CLAMP: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_SCALE: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_SCALE: return 2; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_SCALE: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT8: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT16: return 2; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT32: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_INT8: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_INT16: return 2; + case rrVertexAttrib.VertexAttribType.NONPURE_INT32: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT_2_10_10_10_REV: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_INT_2_10_10_10_REV: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.PURE_UINT8: return 1; + case rrVertexAttrib.VertexAttribType.PURE_UINT16: return 2; + case rrVertexAttrib.VertexAttribType.PURE_UINT32: return 4; + case rrVertexAttrib.VertexAttribType.PURE_INT8: return 1; + case rrVertexAttrib.VertexAttribType.PURE_INT16: return 2; + case rrVertexAttrib.VertexAttribType.PURE_INT32: return 4; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM8_BGRA: return 1; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV_BGRA: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA: return 1; //sizeof(deUint32)/4; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA: return 1; //sizeof(deUint32)/4; + default: + throw new Error('rrVertexAttrib.getComponentSize - Invalid type'); + } + }; + + /** + * rrVertexAttrib.isValidVertexAttrib function + * @param {rrVertexAttrib.VertexAttrib} vertexAttrib + * @return {boolean} + */ + rrVertexAttrib.isValidVertexAttrib = function(vertexAttrib) { + // Trivial range checks. + if (!deMath.deInBounds32(vertexAttrib.type, 0, Object.keys(rrVertexAttrib.VertexAttribType).length) || + !deMath.deInRange32(vertexAttrib.size, 0, 4) || + vertexAttrib.instanceDivisor < 0) + return false; + + // Generic attributes + if (!vertexAttrib.pointer && vertexAttrib.type != rrVertexAttrib.VertexAttribType.DONT_CARE) + return false; + + // Packed formats + if ((vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_INT_2_10_10_10_REV || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_UINT_2_10_10_10_REV || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV_BGRA || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA || + vertexAttrib.type == rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA) && + vertexAttrib.size != 4) + return false; + + return true; + }; + + /** + * rrVertexAttrib.readVertexAttrib function + * @param {rrVertexAttrib.VertexAttrib} vertexAttrib + * @param {number} instanceNdx + * @param {number} vertexNdx + * @param {rrGenericVector.GenericVecType} genericType + * @return {goog.NumberArray} + */ + rrVertexAttrib.readVertexAttrib = function(vertexAttrib, instanceNdx, vertexNdx, genericType) { + DE_ASSERT(rrVertexAttrib.isValidVertexAttrib(vertexAttrib)); + /** @type {goog.NumberArray} */ var dst; + + var arrayType = null; + switch (genericType) { + case rrGenericVector.GenericVecType.INT32: + arrayType = Int32Array; + break; + case rrGenericVector.GenericVecType.UINT32: + arrayType = Uint32Array; + break; + case rrGenericVector.GenericVecType.FLOAT: + arrayType = Float32Array; + break; + } + + if (vertexAttrib.pointer) { + /** @type {number} */ var elementNdx = (vertexAttrib.instanceDivisor != 0) ? (instanceNdx / vertexAttrib.instanceDivisor) : vertexNdx; + /** @type {number} */ var compSize = rrVertexAttrib.getComponentSize(vertexAttrib.type); + /** @type {number} */ var stride = (vertexAttrib.stride != 0) ? (vertexAttrib.stride) : (vertexAttrib.size * compSize); + /** @type {number} */ var byteOffset = vertexAttrib.offset + (elementNdx * stride); + + dst = [0, 0, 0, 1]; // defaults + + if (arrayType != null) { + dst = new arrayType(dst); + } + + rrVertexAttrib.read(dst, vertexAttrib.type, vertexAttrib.size, new Uint8Array(vertexAttrib.pointer, byteOffset)); + } else { + dst = new arrayType(/** @type {Array<number>} */ vertexAttrib.generic.data); + } + + return dst; + }; + + /** + * rrVertexAttrib.readHalf + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + */ + rrVertexAttrib.readHalf = function(dst, size, ptr) { + var arraysize16 = 2; //2 bytes + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize16)); //Small buffer copy (max. 8 bytes) + var aligned = new Uint16Array(ptrclone.buffer); + + //Reinterpret aligned's values into the dst vector. + dst[0] = tcuFloat.newFloat32From16(aligned[0]).getValue(); + if (size >= 2) dst[1] = tcuFloat.newFloat32From16(aligned[1]).getValue(); + if (size >= 3) dst[2] = tcuFloat.newFloat32From16(aligned[2]).getValue(); + if (size >= 4) dst[3] = tcuFloat.newFloat32From16(aligned[3]).getValue(); + }; + + /** + * rrVertexAttrib.readFixed + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + */ + /*rrVertexAttrib.readFixed = function(dst, size, ptr) { + var arraysize32 = 4; //4 bytes + + //Reinterpret ptr as a uint16 array, + //assuming original ptr is 8-bits per element + var aligned = new Int32Array(ptr.buffer).subarray( + ptr.byteOffset / arraysize32, + (ptr.byteOffset + ptr.byteLength) / arraysize32); + + //Reinterpret aligned's values into the dst vector. + dst[0] = aligned[0] / (1 << 16); + if (size >= 2) dst[1] = aligned[1] / (1 << 16); + if (size >= 3) dst[2] = aligned[2] / (1 << 16); + if (size >= 4) dst[3] = aligned[3] / (1 << 16); + };*/ + + /** + * TODO: Check 64 bit numbers are handled ok + * rrVertexAttrib.readDouble + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + */ + /*rrVertexAttrib.readDouble = function(dst, size, ptr) { + var arraysize64 = 8; //8 bytes + + //Reinterpret 'ptr' into 'aligned' as a float64 array, + //assuming original ptr is 8-bits per element. + var aligned = new Float64Array(ptr.buffer).subarray( + ptr.byteOffset / arraysize64, + (ptr.byteOffset + ptr.byteLength) / arraysize64); + + //Reinterpret aligned's values into the dst vector. + dst[0] = aligned[0]; + if (size >= 2) dst[1] = aligned[1]; + if (size >= 3) dst[2] = aligned[2]; + if (size >= 4) dst[3] = aligned[3]; + };*/ + + /** + * extendSign + * @param {number} integerLen + * @param {number} integer_ (deUint32) + * @return {number} (deInt32) + */ + rrVertexAttrib.extendSign = function(integerLen, integer_) { + return new Int32Array([ + deMath.binaryOp( + 0 - + deMath.shiftLeft( + deMath.binaryOp( + integer_, + deMath.shiftLeft( + 1, + (integerLen - 1) + ), + deMath.BinaryOp.AND + ), + 1 + ) , + +integer_, + deMath.BinaryOp.OR + ) + ])[0]; + }; + + /** + * rrVertexAttrib.readUint2101010Rev + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + */ + rrVertexAttrib.readUint2101010Rev = function(dst, size, ptr) { + var arraysize32 = 4; //4 bytes + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize32)); //Small buffer copy (max. 16 bytes) + var aligned = new Uint32Array(ptrclone.buffer)[0]; + + dst[0] = deMath.binaryOp(deMath.shiftRight(aligned, 0), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND); + if (size >= 2) dst[1] = deMath.binaryOp(deMath.shiftRight(aligned, 10), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND); + if (size >= 3) dst[2] = deMath.binaryOp(deMath.shiftRight(aligned, 20), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND); + if (size >= 4) dst[3] = deMath.binaryOp(deMath.shiftRight(aligned, 30), deMath.shiftLeft(1, 2) - 1, deMath.BinaryOp.AND); + }; + + /** + * rrVertexAttrib.readInt2101010Rev + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + */ + rrVertexAttrib.readInt2101010Rev = function(dst, size, ptr) { + var arraysize32 = 4; //4 bytes + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize32)); //Small buffer copy (max. 16 bytes) + var aligned = new Uint32Array(ptrclone.buffer)[0]; + + dst[0] = rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 0), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)); + if (size >= 2) dst[1] = rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 10), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)); + if (size >= 3) dst[2] = rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 20), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)); + if (size >= 4) dst[3] = rrVertexAttrib.extendSign(2, deMath.binaryOp(deMath.shiftRight(aligned, 30), deMath.shiftLeft(1, 2) - 1, deMath.BinaryOp.AND)); + }; + + /** + * rrVertexAttrib.readUnorm2101010RevOrder + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {Object<rrVertexAttrib.NormalOrder|rrVertexAttrib.BGRAOrder>} order + */ + rrVertexAttrib.readUnorm2101010RevOrder = function(dst, size, ptr, order) { + var arraysize32 = 4; //4 bytes + + //Left shift within 32-bit range as 32-bit int. + var range10 = new Uint32Array([deMath.shiftLeft(1, 10) - 1])[0]; + var range2 = new Uint32Array([deMath.shiftLeft(1, 2) - 1])[0]; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize32)); //Small buffer copy (max. 16 bytes) + var aligned = new Uint32Array(ptrclone.buffer)[0]; + + dst[order.T0] = deMath.binaryOp(deMath.shiftRight(aligned, 0), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND) / range10; + if (size >= 2) dst[order.T1] = deMath.binaryOp(deMath.shiftRight(aligned, 10), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND) / range10; + if (size >= 3) dst[order.T2] = deMath.binaryOp(deMath.shiftRight(aligned, 20), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND) / range10; + if (size >= 4) dst[order.T3] = deMath.binaryOp(deMath.shiftRight(aligned, 30), deMath.shiftLeft(1, 2) - 1, deMath.BinaryOp.AND) / range2; + }; + + /** + * rrVertexAttrib.readSnorm2101010RevClampOrder + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {Object<rrVertexAttrib.NormalOrder|rrVertexAttrib.BGRAOrder>} order + */ + rrVertexAttrib.readSnorm2101010RevClampOrder = function(dst, size, ptr, order) { + var arraysize32 = 4; //4 bytes + + //Left shift within 32-bit range as 32-bit int. + var range10 = new Uint32Array([deMath.shiftLeft(1, 10 - 1) - 1])[0]; + var range2 = new Uint32Array([deMath.shiftLeft(1, 2 - 1) - 1])[0]; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize32)); //Small buffer copy (max. 16 bytes) + var aligned = new Uint32Array(ptrclone.buffer)[0]; + + dst[order.T0] = Math.max(-1.0, new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 0), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND))])[0] / range10); + if (size >= 2) dst[order.T1] = Math.max(-1.0, new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 10), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND))])[0] / range10); + if (size >= 3) dst[order.T2] = Math.max(-1.0, new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 20), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND))])[0] / range10); + if (size >= 4) dst[order.T3] = Math.max(-1.0, new Float32Array([rrVertexAttrib.extendSign(2, deMath.binaryOp(deMath.shiftRight(aligned, 30), deMath.shiftLeft(1, 2) - 1, deMath.BinaryOp.AND))])[0] / range2); + }; + + /** + * rrVertexAttrib.readSnorm2101010RevScaleOrder + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {Object<rrVertexAttrib.NormalOrder|rrVertexAttrib.BGRAOrder>} order + */ + rrVertexAttrib.readSnorm2101010RevScaleOrder = function(dst, size, ptr, order) { + var arraysize32 = 4; //4 bytes + + //Left shift within 32-bit range as 32-bit int. + var range10 = new Uint32Array([deMath.shiftLeft(1, 10) - 1])[0]; + var range2 = new Uint32Array([deMath.shiftLeft(1, 2) - 1])[0]; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arraysize32)); //Small buffer copy (max. 16 bytes) + var aligned = new Uint32Array(ptrclone.buffer)[0]; + + dst[order.T0] = new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 0), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)) * 2.0 + 1.0])[0] / range10; + if (size >= 2) dst[order.T1] = new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 10), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)) * 2.0 + 1.0])[0] / range10; + if (size >= 3) dst[order.T2] = new Float32Array([rrVertexAttrib.extendSign(10, deMath.binaryOp(deMath.shiftRight(aligned, 20), deMath.shiftLeft(1, 10) - 1, deMath.BinaryOp.AND)) * 2.0 + 1.0])[0] / range10; + if (size >= 4) dst[order.T3] = new Float32Array([rrVertexAttrib.extendSign(2, deMath.binaryOp(deMath.shiftRight(aligned, 30), deMath.shiftLeft(1, 2) - 1, deMath.BinaryOp.AND)) * 2.0 + 1.0])[0] / range2; + }; + + /** + * rrVertexAttrib.readUnormOrder + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {Object<rrVertexAttrib.NormalOrder|rrVertexAttrib.BGRAOrder>} order + * @param readAsTypeArray + */ + rrVertexAttrib.readUnormOrder = function(dst, size, ptr, order, readAsTypeArray) { + var arrayelementsize = readAsTypeArray.BYTES_PER_ELEMENT; + + //Left shift within 32-bit range as 32-bit float. + var range = new Float32Array([deMath.shiftLeft(1, arrayelementsize * 8) - 1])[0]; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arrayelementsize)); //Small buffer copy (max. 16 bytes) + var aligned = new readAsTypeArray(ptrclone.buffer); + + //Reinterpret aligned's values into the dst vector. + dst[order.T0] = aligned[0] / range; + if (size >= 2) dst[order.T1] = aligned[1] / range; + if (size >= 3) dst[order.T2] = aligned[2] / range; + if (size >= 4) dst[order.T3] = aligned[3] / range; + }; + + /** + * rrVertexAttrib.readSnormClamp + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {function(new:ArrayBufferView,(Array<number>|ArrayBuffer|ArrayBufferView|null|number), number=, number=)} readAsTypeArray + */ + rrVertexAttrib.readSnormClamp = function(dst, size, ptr, readAsTypeArray) { + var arrayelementsize = readAsTypeArray.BYTES_PER_ELEMENT; + + //Left shift within 32-bit range as 32-bit float. + var range = new Float32Array([deMath.shiftLeft(1, arrayelementsize * 8 - 1) - 1])[0]; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arrayelementsize)); //Small buffer copy (max. 16 bytes) + var aligned = new readAsTypeArray(ptrclone.buffer); + + //Reinterpret aligned's values into the dst vector. + dst[0] = Math.max(-1, aligned[0] / range); + if (size >= 2) dst[1] = Math.max(-1, aligned[1] / range); + if (size >= 3) dst[2] = Math.max(-1, aligned[2] / range); + if (size >= 4) dst[3] = Math.max(-1, aligned[3] / range); + }; + + /** + * rrVertexAttrib.readOrder + * @param {goog.NumberArray} dst + * @param {number} size + * @param {Uint8Array} ptr + * @param {Object<rrVertexAttrib.NormalOrder|rrVertexAttrib.BGRAOrder>} order NormalOrder or BGRAOrder + * @param readAsTypeArray Typed Array type + */ + rrVertexAttrib.readOrder = function(dst, size, ptr, order, readAsTypeArray) { + var arrayelementsize = readAsTypeArray.BYTES_PER_ELEMENT; + + var ptrclone = new Uint8Array(ptr.subarray(0, size * arrayelementsize)); //Small buffer copy (max. 16 bytes) + var aligned = new readAsTypeArray(ptrclone.buffer); + + //Reinterpret aligned's values into the dst vector. + //(automatic in JS typed arrays). + dst[order.T0] = aligned[0]; + if (size >= 2) dst[order.T1] = aligned[1]; + if (size >= 3) dst[order.T2] = aligned[2]; + if (size >= 4) dst[order.T3] = aligned[3]; + }; + + /** + * TODO: Implement readSNormScale. + * @param {goog.NumberArray} dst + * @param {rrVertexAttrib.VertexAttribType} type + * @param {number} size + * @param {Uint8Array} ptr + */ + rrVertexAttrib.read = function(dst, type, size, ptr) { + var order; + + switch (type) { + case rrVertexAttrib.VertexAttribType.FLOAT: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Float32Array); + break; + case rrVertexAttrib.VertexAttribType.HALF: + rrVertexAttrib.readHalf(dst, size, ptr); + break; + /*case rrVertexAttrib.VertexAttribType.FIXED: + rrVertexAttrib.readFixed(dst, size, ptr); + break; + case rrVertexAttrib.VertexAttribType.DOUBLE: + rrVertexAttrib.readDouble(dst, size, ptr); + break;*/ + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM8: + rrVertexAttrib.readUnormOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM16: + rrVertexAttrib.readUnormOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint16Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM32: + rrVertexAttrib.readUnormOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint32Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV: + rrVertexAttrib.readUnorm2101010RevOrder(dst, size, ptr, rrVertexAttrib.NormalOrder); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_CLAMP: //Int8 + rrVertexAttrib.readSnormClamp(dst, size, ptr, Int8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_CLAMP: //Int16 + rrVertexAttrib.readSnormClamp(dst, size, ptr, Int16Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_CLAMP: //Int32 + rrVertexAttrib.readSnormClamp(dst, size, ptr, Int32Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP: + rrVertexAttrib.readSnorm2101010RevClampOrder(dst, size, ptr, rrVertexAttrib.NormalOrder); + break; + /*case rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_SCALE: //Int8 + rrVertexAttrib.readSnormScale(dst, size, ptr, Int8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_SCALE: //Int16 + rrVertexAttrib.readSnormScale(dst, size, ptr, Int16Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_SCALE: //Int32 + rrVertexAttrib.readSnormScale(dst, size, ptr, Int32Array); + break;*/ + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE: + rrVertexAttrib.readSnorm2101010RevScaleOrder(dst, size, ptr, rrVertexAttrib.NormalOrder); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT_2_10_10_10_REV: + rrVertexAttrib.readUint2101010Rev(dst, size, ptr); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_INT_2_10_10_10_REV: + rrVertexAttrib.readInt2101010Rev(dst, size, ptr); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM8_BGRA: + rrVertexAttrib.readUnormOrder(dst, size, ptr, rrVertexAttrib.BGRAOrder, Uint8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV_BGRA: + rrVertexAttrib.readUnorm2101010RevOrder(dst, size, ptr, rrVertexAttrib.BGRAOrder); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA: + rrVertexAttrib.readSnorm2101010RevClampOrder(dst, size, ptr, rrVertexAttrib.BGRAOrder); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA: + rrVertexAttrib.readSnorm2101010RevScaleOrder(dst, size, ptr, rrVertexAttrib.BGRAOrder); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT8: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT16: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint16Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_UINT32: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint32Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_INT8: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int8Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_INT16: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int16Array); + break; + case rrVertexAttrib.VertexAttribType.NONPURE_INT32: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int32Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_UINT8: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint8Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_UINT16: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint16Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_UINT32: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Uint32Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_INT8: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int8Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_INT16: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int16Array); + break; + case rrVertexAttrib.VertexAttribType.PURE_INT32: + rrVertexAttrib.readOrder(dst, size, ptr, rrVertexAttrib.NormalOrder, Int32Array); + break; + + default: + throw new Error('rrVertexAttrib.read - Invalid type'); + } + }; + +}); diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexPacket.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexPacket.js new file mode 100644 index 0000000000..ec00e17d19 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexPacket.js @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + * 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.referencerenderer.rrVertexPacket'); +goog.require('framework.common.tcuTexture'); +goog.require('framework.delibs.debase.deMath'); + +goog.scope(function() { + +var rrVertexPacket = framework.referencerenderer.rrVertexPacket; +var tcuTexture = framework.common.tcuTexture; +var deMath = framework.delibs.debase.deMath; + + /** + * rrVertexPacket.VertexPacket class. (Should only be created by rrVertexPacket.VertexPacketAllocator) + * @constructor + */ + rrVertexPacket.VertexPacket = function() { + /** @type {number} */ this.instanceNdx; + /** @type {number} */ this.vertexNdx; + /** @type {goog.NumberArray} */ this.position; //!< Transformed position - must be written always. + /** @type {number} */ this.pointSize; //!< Point size, required when rendering points. + // /** @type {number} */ this.primitiveID; //!< Geometry shader output (Not used in webGL) + /** @type {Array<goog.NumberArray>} */ this.outputs = [[0, 0, 0, 0]]; + }; + + /** + * rrVertexPacket.VertexPacketAllocator class + * @constructor + * @param {number} numberOfVertexOutputs + */ + rrVertexPacket.VertexPacketAllocator = function(numberOfVertexOutputs) { + /** @type {number} */ this.m_numberOfVertexOutputs = numberOfVertexOutputs; + /** @type {Uint8Array} */ this.m_allocations; + /** @type {Array<rrVertexPacket.VertexPacket>} */ this.m_singleAllocPool = []; + }; + + /** + * @return {number} + */ + rrVertexPacket.VertexPacketAllocator.prototype.getNumVertexOutputs = function() { + return this.m_numberOfVertexOutputs; + }; + + /** + * allocArray + * @param {number} count + * @return {Array<rrVertexPacket.VertexPacket>} + */ + rrVertexPacket.VertexPacketAllocator.prototype.allocArray = function(count) { + if (!count) + return []; + + /** @type {number} */ var extraVaryings = (this.m_numberOfVertexOutputs == 0) ? (0) : (this.m_numberOfVertexOutputs - 1); + // /** @type {number} TODO: Check what this size is used for */ var packetSize = sizeof(rrVertexPacket.VertexPacket) + extraVaryings * sizeof(GenericVec4); + + /** @type {Array<rrVertexPacket.VertexPacket>} */ var retVal = []; + // /** @type {Uint8Array} TODO: same as above */ var ptr = new deInt8[packetSize * count]; // throws bad_alloc => ok + + //run ctors + for (var i = 0; i < count; ++i) + retVal.push(new rrVertexPacket.VertexPacket()); + + /** TODO: same as previous - this.m_allocations.push_back(ptr); */ + + return retVal; + }; + + /** + * @return {rrVertexPacket.VertexPacket} + */ + rrVertexPacket.VertexPacketAllocator.prototype.alloc = function() { + /** @type {number} */ var poolSize = 8; + + if (this.m_singleAllocPool.length == 0) + this.m_singleAllocPool = this.allocArray(poolSize); + + /** @type {rrVertexPacket.VertexPacket} */ var packet = this.m_singleAllocPool.pop(); + + return packet; + }; + +}); |